Bug 1088345 - Don't run GL commands that may cause non-OOM errors. - r=kamidphish
authorJeff Gilbert <jgilbert@mozilla.com>
Thu, 23 Oct 2014 15:10:57 -0700
changeset 237356 931498bf7d4ff27c774a434ec5c55156d82a224a
parent 237355 5e5b3c89df165dae1ee53e682641ccd2599e1200
child 237357 ac7a5ece234c31c4d913a2792f0859c24bfc22e2
push id4311
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 19:37:41 +0000
treeherdermozilla-beta@150c9fed433b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskamidphish
bugs1088345
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1088345 - Don't run GL commands that may cause non-OOM errors. - r=kamidphish
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertices.cpp
dom/canvas/WebGLVertexArray.cpp
dom/canvas/WebGLVertexArray.h
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -605,182 +605,190 @@ public:
         return TexSubImage2D_base(texImageTarget.get(), level, xoffset, yoffset,
                                   size.width, size.height,
                                   data->Stride(), format, type,
                                   data->GetData(), byteLength,
                                   js::Scalar::TypeMax, srcFormat, mPixelStorePremultiplyAlpha);
 
     }
 
-    void Uniform1i(WebGLUniformLocation* location, GLint x);
-    void Uniform2i(WebGLUniformLocation* location, GLint x, GLint y);
-    void Uniform3i(WebGLUniformLocation* location, GLint x, GLint y,
-                   GLint z);
-    void Uniform4i(WebGLUniformLocation* location, GLint x, GLint y,
-                   GLint z, GLint w);
+    void Uniform1i(WebGLUniformLocation* loc, GLint x);
+    void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
+    void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
+    void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z,
+                   GLint w);
+
+    void Uniform1f(WebGLUniformLocation* loc, GLfloat x);
+    void Uniform2f(WebGLUniformLocation* loc, GLfloat x, GLfloat y);
+    void Uniform3f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z);
+    void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z,
+                   GLfloat w);
 
-    void Uniform1f(WebGLUniformLocation* location, GLfloat x);
-    void Uniform2f(WebGLUniformLocation* location, GLfloat x, GLfloat y);
-    void Uniform3f(WebGLUniformLocation* location, GLfloat x, GLfloat y,
-                   GLfloat z);
-    void Uniform4f(WebGLUniformLocation* location, GLfloat x, GLfloat y,
-                   GLfloat z, GLfloat w);
-
-    void Uniform1iv(WebGLUniformLocation* location,
-                    const dom::Int32Array& arr) {
+    // Int array
+    void Uniform1iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform1iv_base(location, arr.Length(), arr.Data());
+        Uniform1iv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform1iv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLint>& arr) {
-        Uniform1iv_base(location, arr.Length(), arr.Elements());
+    void Uniform1iv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLint>& arr)
+    {
+        Uniform1iv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform1iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLint* data);
 
-    void Uniform2iv(WebGLUniformLocation* location,
-                    const dom::Int32Array& arr) {
+    void Uniform2iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform2iv_base(location, arr.Length(), arr.Data());
+        Uniform2iv_base(loc, arr.Length(), arr.Data());
+    }
+    void Uniform2iv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLint>& arr)
+    {
+        Uniform2iv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform2iv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLint>& arr) {
-        Uniform2iv_base(location, arr.Length(), arr.Elements());
+    void Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                         const GLint* data);
+
+    void Uniform3iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
+        arr.ComputeLengthAndData();
+        Uniform3iv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform2iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform3iv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLint>& arr)
+    {
+        Uniform3iv_base(loc, arr.Length(), arr.Elements());
+    }
+    void Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLint* data);
 
-    void Uniform3iv(WebGLUniformLocation* location,
-                    const dom::Int32Array& arr) {
+    void Uniform4iv(WebGLUniformLocation* loc, const dom::Int32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform3iv_base(location, arr.Length(), arr.Data());
+        Uniform4iv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform3iv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLint>& arr) {
-        Uniform3iv_base(location, arr.Length(), arr.Elements());
+    void Uniform4iv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLint>& arr)
+    {
+        Uniform4iv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform3iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLint* data);
 
-    void Uniform4iv(WebGLUniformLocation* location,
-                    const dom::Int32Array& arr) {
+    // Float array
+    void Uniform1fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform4iv_base(location, arr.Length(), arr.Data());
-    }
-    void Uniform4iv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLint>& arr) {
-        Uniform4iv_base(location, arr.Length(), arr.Elements());
+        Uniform1fv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform4iv_base(WebGLUniformLocation* location, uint32_t arrayLength,
-                         const GLint* data);
-
-    void Uniform1fv(WebGLUniformLocation* location,
-                    const dom::Float32Array& arr) {
-        arr.ComputeLengthAndData();
-        Uniform1fv_base(location, arr.Length(), arr.Data());
+    void Uniform1fv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLfloat>& arr)
+    {
+        Uniform1fv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform1fv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLfloat>& arr) {
-        Uniform1fv_base(location, arr.Length(), arr.Elements());
-    }
-    void Uniform1fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLfloat* data);
 
-    void Uniform2fv(WebGLUniformLocation* location,
-                    const dom::Float32Array& arr) {
+    void Uniform2fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform2fv_base(location, arr.Length(), arr.Data());
+        Uniform2fv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform2fv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLfloat>& arr) {
-        Uniform2fv_base(location, arr.Length(), arr.Elements());
+    void Uniform2fv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLfloat>& arr)
+    {
+        Uniform2fv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform2fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLfloat* data);
 
-    void Uniform3fv(WebGLUniformLocation* location,
-                    const dom::Float32Array& arr) {
+    void Uniform3fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform3fv_base(location, arr.Length(), arr.Data());
+        Uniform3fv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform3fv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLfloat>& arr) {
-        Uniform3fv_base(location, arr.Length(), arr.Elements());
+    void Uniform3fv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLfloat>& arr)
+    {
+        Uniform3fv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform3fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLfloat* data);
 
-    void Uniform4fv(WebGLUniformLocation* location,
-                    const dom::Float32Array& arr) {
+    void Uniform4fv(WebGLUniformLocation* loc, const dom::Float32Array& arr) {
         arr.ComputeLengthAndData();
-        Uniform4fv_base(location, arr.Length(), arr.Data());
+        Uniform4fv_base(loc, arr.Length(), arr.Data());
     }
-    void Uniform4fv(WebGLUniformLocation* location,
-                    const dom::Sequence<GLfloat>& arr) {
-        Uniform4fv_base(location, arr.Length(), arr.Elements());
+    void Uniform4fv(WebGLUniformLocation* loc,
+                    const dom::Sequence<GLfloat>& arr)
+    {
+        Uniform4fv_base(loc, arr.Length(), arr.Elements());
     }
-    void Uniform4fv_base(WebGLUniformLocation* location, uint32_t arrayLength,
+    void Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
                          const GLfloat* data);
 
-    void UniformMatrix2fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Float32Array &value) {
+    // Matrix
+    void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Float32Array& value)
+    {
         value.ComputeLengthAndData();
-        UniformMatrix2fv_base(location, transpose, value.Length(), value.Data());
+        UniformMatrix2fv_base(loc, transpose, value.Length(), value.Data());
     }
-    void UniformMatrix2fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Sequence<float> &value) {
-        UniformMatrix2fv_base(location, transpose, value.Length(),
+    void UniformMatrix2fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Sequence<float>& value)
+    {
+        UniformMatrix2fv_base(loc, transpose, value.Length(),
                               value.Elements());
     }
-    void UniformMatrix2fv_base(WebGLUniformLocation* location,
-                               WebGLboolean transpose, uint32_t arrayLength,
+    void UniformMatrix2fv_base(WebGLUniformLocation* loc,
+                               WebGLboolean transpose, size_t arrayLength,
                                const float* data);
 
-    void UniformMatrix3fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Float32Array &value) {
+    void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Float32Array& value)
+    {
         value.ComputeLengthAndData();
-        UniformMatrix3fv_base(location, transpose, value.Length(), value.Data());
+        UniformMatrix3fv_base(loc, transpose, value.Length(), value.Data());
+    }
+    void UniformMatrix3fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Sequence<float>& value)
+    {
+        UniformMatrix3fv_base(loc, transpose, value.Length(), value.Elements());
     }
-    void UniformMatrix3fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Sequence<float> &value) {
-        UniformMatrix3fv_base(location, transpose, value.Length(),
+    void UniformMatrix3fv_base(WebGLUniformLocation* loc,
+                               WebGLboolean transpose, size_t arrayLength,
+                               const float* data);
+
+    void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Float32Array& value)
+    {
+        value.ComputeLengthAndData();
+        UniformMatrix4fv_base(loc, transpose, value.Length(), value.Data());
+    }
+    void UniformMatrix4fv(WebGLUniformLocation* loc, WebGLboolean transpose,
+                          const dom::Sequence<float>& value)
+    {
+        UniformMatrix4fv_base(loc, transpose, value.Length(),
                               value.Elements());
     }
-    void UniformMatrix3fv_base(WebGLUniformLocation* location,
-                               WebGLboolean transpose, uint32_t arrayLength,
-                               const float* data);
-
-    void UniformMatrix4fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Float32Array &value) {
-        value.ComputeLengthAndData();
-        UniformMatrix4fv_base(location, transpose, value.Length(), value.Data());
-    }
-    void UniformMatrix4fv(WebGLUniformLocation* location,
-                          WebGLboolean transpose,
-                          const dom::Sequence<float> &value) {
-        UniformMatrix4fv_base(location, transpose, value.Length(),
-                              value.Elements());
-    }
-    void UniformMatrix4fv_base(WebGLUniformLocation* location,
-                               WebGLboolean transpose, uint32_t arrayLength,
+    void UniformMatrix4fv_base(WebGLUniformLocation* loc,
+                               WebGLboolean transpose, size_t arrayLength,
                                const float* data);
 
     void UseProgram(WebGLProgram *prog);
     bool ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength);
-    bool ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
-                                    GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength);
-    bool ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
-                                          GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
-                                          WebGLboolean aTranspose);
-    bool ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location);
+    bool ValidateUniformSetter(WebGLUniformLocation* loc, uint8_t setterSize,
+                               GLenum setterType, const char* info,
+                               GLuint* out_rawLoc);
+    bool ValidateUniformArraySetter(WebGLUniformLocation* loc,
+                                    uint8_t setterElemSize, GLenum setterType,
+                                    size_t setterArraySize, const char* info,
+                                    GLuint* out_rawLoc,
+                                    GLsizei* out_numElementsToUpload);
+    bool ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
+                                          uint8_t setterDims, GLenum setterType,
+                                          size_t setterArraySize,
+                                          bool setterTranspose,
+                                          const char* info, GLuint* out_rawLoc,
+                                          GLsizei* out_numElementsToUpload);
     void ValidateProgram(WebGLProgram *prog);
     bool ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object);
     bool ValidateSamplerUniformSetter(const char* info,
                                     WebGLUniformLocation *location,
                                     GLint value);
     void Viewport(GLint x, GLint y, GLsizei width, GLsizei height);
 // -----------------------------------------------------------------------------
 // WEBGL_lose_context
@@ -1042,16 +1050,22 @@ protected:
     int32_t mGLMaxVertexTextureImageUnits;
     int32_t mGLMaxVaryingVectors;
     int32_t mGLMaxFragmentUniformVectors;
     int32_t mGLMaxVertexUniformVectors;
     int32_t mGLMaxColorAttachments;
     int32_t mGLMaxDrawBuffers;
     uint32_t mGLMaxTransformFeedbackSeparateAttribs;
 
+public:
+    GLuint MaxVertexAttribs() const {
+        return mGLMaxVertexAttribs;
+    }
+
+protected:
     // Represents current status of the context with respect to context loss.
     // That is, whether the context is lost, and what part of the context loss
     // process we currently are at.
     // This is used to support the WebGL spec's asyncronous nature in handling
     // context loss.
     enum ContextStatus {
         // The context is stable; there either are none or we don't know of any.
         ContextNotLost,
@@ -1110,17 +1124,16 @@ protected:
     bool ValidateComparisonEnum(GLenum target, const char *info);
     bool ValidateStencilOpEnum(GLenum action, const char *info);
     bool ValidateFaceEnum(GLenum face, const char *info);
     bool ValidateTexInputData(GLenum type,
                               js::Scalar::Type jsArrayType,
                               WebGLTexImageFunc func,
                               WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char *info);
-    bool ValidateAttribIndex(GLuint index, const char *info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
     bool ValidateCopyTexImage(GLenum internalformat,
                               WebGLTexImageFunc func,
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -115,37 +115,40 @@ WebGLContext::AttachShader(WebGLProgram 
     // leave it for when we support more than one shader of each type.
     if (program->HasAttachedShaderOfType(shader->ShaderType()))
         return ErrorInvalidOperation("attachShader: only one of each type of shader may be attached to a program");
 
     if (!program->AttachShader(shader))
         return ErrorInvalidOperation("attachShader: shader is already attached");
 }
 
-
 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;
 
     GLuint progname = prog->GLName();
 
     if (!ValidateGLSLVariableName(name, "bindAttribLocation"))
         return;
 
-    if (!ValidateAttribIndex(location, "bindAttribLocation"))
-        return;
+    if (location >= MaxVertexAttribs()) {
+        return ErrorInvalidValue("bindAttribLocation: `location` must be less"
+                                 " than MAX_VERTEX_ATTRIBS.");
+    }
 
     if (StringBeginsWith(name, NS_LITERAL_STRING("gl_")))
-        return ErrorInvalidOperation("bindAttribLocation: can't set the location of a name that starts with 'gl_'");
+        return ErrorInvalidOperation("bindAttribLocation: can't set the"
+                                     " location of a name that starts with"
+                                     " 'gl_'.");
 
     NS_LossyConvertUTF16toASCII cname(name);
     nsCString mappedName;
     if (mShaderValidation) {
         WebGLProgram::HashMapIdentifier(cname, &mappedName);
     } else {
         mappedName.Assign(cname);
     }
@@ -422,16 +425,27 @@ WebGLContext::CopyTexSubImage2D_base(Tex
     }
 
     TexInternalFormat effectiveInternalFormat =
         EffectiveInternalFormatFromUnsizedInternalFormatAndType(internalformat, framebuffertype);
 
     // this should never fail, validation happened earlier.
     MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE);
 
+    const bool widthOrHeightIsZero = (width == 0 || height == 0);
+    if (gl->WorkAroundDriverBugs() &&
+        sub && widthOrHeightIsZero)
+    {
+        // NV driver on Linux complains that CopyTexSubImage2D(level=0,
+        // xoffset=0, yoffset=2, x=0, y=0, width=0, height=0) from a 300x150 FB
+        // to a 0x2 texture. This a useless thing to do, but technically legal.
+        // NV331.38 generates INVALID_VALUE.
+        return DummyFramebufferOperation(info);
+    }
+
     // check if the memory size of this texture may change with this call
     bool sizeMayChange = !sub;
     if (!sub && tex->HasImageInfoAt(texImageTarget, level)) {
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
         sizeMayChange = width != imageInfo.Width() ||
                         height != imageInfo.Height() ||
                         effectiveInternalFormat != imageInfo.EffectiveInternalFormat();
     }
@@ -874,19 +888,29 @@ WebGLContext::GetActiveAttrib(WebGLProgr
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getActiveAttrib: program", prog))
         return nullptr;
 
     MakeContextCurrent();
+    GLuint progname = prog->GLName();
+
+    GLuint activeAttribs = 0;
+    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTES,
+                      (GLint*)&activeAttribs);
+    if (index >= activeAttribs) {
+        ErrorInvalidValue("`index` (%i) must be less than ACTIVE_ATTRIBUTES"
+                          " (%i).",
+                          index, activeAttribs);
+        return nullptr;
+    }
 
     GLint len = 0;
-    GLuint progname = prog->GLName();;
     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &len);
     if (len == 0)
         return nullptr;
 
     nsAutoArrayPtr<char> name(new char[len]);
     GLint attrsize = 0;
     GLuint attrtype = 0;
 
@@ -972,19 +996,29 @@ WebGLContext::GetActiveUniform(WebGLProg
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getActiveUniform: program", prog))
         return nullptr;
 
     MakeContextCurrent();
+    GLuint progname = prog->GLName();
+
+    GLuint activeUniforms = 0;
+    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS,
+                      (GLint*)&activeUniforms);
+    if (index >= activeUniforms) {
+        ErrorInvalidValue("`index` (%i) must be less than ACTIVE_UNIFORMS"
+                          " (%i).",
+                          index, activeUniforms);
+        return nullptr;
+    }
 
     GLint len = 0;
-    GLuint progname = prog->GLName();
     gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &len);
     if (len == 0)
         return nullptr;
 
     nsAutoArrayPtr<char> name(new char[len]);
 
     GLint usize = 0;
     GLuint utype = 0;
@@ -1064,18 +1098,24 @@ WebGLContext::GetAttribLocation(WebGLPro
 }
 
 JS::Value
 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (target != LOCAL_GL_ARRAY_BUFFER && target != LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        ErrorInvalidEnumInfo("getBufferParameter: target", target);
+
+    WebGLRefPtr<WebGLBuffer>* slot = GetBufferSlotByTarget(target,
+                                                           "getBufferParameter");
+    if (!slot)
+        return JS::NullValue();
+
+    if (!*slot) {
+        ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
         return JS::NullValue();
     }
 
     MakeContextCurrent();
 
     switch (pname) {
         case LOCAL_GL_BUFFER_SIZE:
         case LOCAL_GL_BUFFER_USAGE:
@@ -2685,297 +2725,333 @@ WebGLContext::SurfaceFromElementResultTo
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     imageOut = data;
 
     return NS_OK;
 }
 
-
+////////////////////////////////////////////////////////////////////////////////
+// Uniform setters.
 
 void
-WebGLContext::Uniform1i(WebGLUniformLocation *location_object, GLint a1)
+WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform1i", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 1, LOCAL_GL_INT, "uniform1i", &rawLoc))
         return;
 
     // Only uniform1i can take sampler settings.
-    if (!ValidateSamplerUniformSetter("Uniform1i", location_object, a1))
+    if (!ValidateSamplerUniformSetter("Uniform1i", loc, a1))
         return;
 
     MakeContextCurrent();
-    gl->fUniform1i(location, a1);
+    gl->fUniform1i(rawLoc, a1);
 }
 
 void
-WebGLContext::Uniform2i(WebGLUniformLocation *location_object, GLint a1,
-                        GLint a2)
+WebGLContext::Uniform2i(WebGLUniformLocation* loc, GLint a1, GLint a2)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform2i", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 2, LOCAL_GL_INT, "uniform2i", &rawLoc))
         return;
 
     MakeContextCurrent();
-    gl->fUniform2i(location, a1, a2);
+    gl->fUniform2i(rawLoc, a1, a2);
 }
 
 void
-WebGLContext::Uniform3i(WebGLUniformLocation *location_object, GLint a1,
-                        GLint a2, GLint a3)
+WebGLContext::Uniform3i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform3i", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 3, LOCAL_GL_INT, "uniform3i", &rawLoc))
         return;
 
     MakeContextCurrent();
-    gl->fUniform3i(location, a1, a2, a3);
+    gl->fUniform3i(rawLoc, a1, a2, a3);
 }
 
 void
-WebGLContext::Uniform4i(WebGLUniformLocation *location_object, GLint a1,
-                        GLint a2, GLint a3, GLint a4)
+WebGLContext::Uniform4i(WebGLUniformLocation* loc, GLint a1, GLint a2, GLint a3,
+                        GLint a4)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform4i", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 4, LOCAL_GL_INT, "uniform4i", &rawLoc))
         return;
 
     MakeContextCurrent();
-    gl->fUniform4i(location, a1, a2, a3, a4);
+    gl->fUniform4i(rawLoc, a1, a2, a3, a4);
 }
 
 void
-WebGLContext::Uniform1f(WebGLUniformLocation *location_object, GLfloat a1)
+WebGLContext::Uniform1f(WebGLUniformLocation* loc, GLfloat a1)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform1f", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 1, LOCAL_GL_FLOAT, "uniform1f", &rawLoc))
         return;
+
     MakeContextCurrent();
-    gl->fUniform1f(location, a1);
+    gl->fUniform1f(rawLoc, a1);
 }
 
 void
-WebGLContext::Uniform2f(WebGLUniformLocation *location_object, GLfloat a1,
-                        GLfloat a2)
+WebGLContext::Uniform2f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform2f", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 2, LOCAL_GL_FLOAT, "uniform2f", &rawLoc))
         return;
+
     MakeContextCurrent();
-    gl->fUniform2f(location, a1, a2);
+    gl->fUniform2f(rawLoc, a1, a2);
 }
 
 void
-WebGLContext::Uniform3f(WebGLUniformLocation *location_object, GLfloat a1,
-                        GLfloat a2, GLfloat a3)
+WebGLContext::Uniform3f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
+                        GLfloat a3)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform3f", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 3, LOCAL_GL_FLOAT, "uniform3f", &rawLoc))
         return;
+
     MakeContextCurrent();
-    gl->fUniform3f(location, a1, a2, a3);
+    gl->fUniform3f(rawLoc, a1, a2, a3);
 }
 
 void
-WebGLContext::Uniform4f(WebGLUniformLocation *location_object, GLfloat a1,
-                        GLfloat a2, GLfloat a3, GLfloat a4)
+WebGLContext::Uniform4f(WebGLUniformLocation* loc, GLfloat a1, GLfloat a2,
+                        GLfloat a3, GLfloat a4)
 {
-    GLint location;
-    if (!ValidateUniformSetter("Uniform4f", location_object, location))
+    GLuint rawLoc;
+    if (!ValidateUniformSetter(loc, 4, LOCAL_GL_FLOAT, "uniform4f", &rawLoc))
         return;
+
     MakeContextCurrent();
-    gl->fUniform4f(location, a1, a2, a3, a4);
+    gl->fUniform4f(rawLoc, a1, a2, a3, a4);
+}
+
+////////////////////////////////////////
+// Array
+
+void
+WebGLContext::Uniform1iv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLint* data)
+{
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_INT, arrayLength,
+                                    "uniform1iv", &rawLoc,
+                                    &numElementsToUpload))
+    {
+        return;
+    }
+
+    if (!ValidateSamplerUniformSetter("uniform1iv", loc, data[0]))
+        return;
+
+    MakeContextCurrent();
+    gl->fUniform1iv(rawLoc, numElementsToUpload, data);
 }
 
 void
-WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLint* data)
+WebGLContext::Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLint* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_INT, arrayLength,
+                                    "uniform2iv", &rawLoc,
+                                    &numElementsToUpload))
+    {
         return;
     }
 
-    if (!ValidateSamplerUniformSetter("Uniform1iv", location_object, data[0]))
-        return;
-
-    MakeContextCurrent();
-    gl->fUniform1iv(location, numElementsToUpload, data);
-}
-
-void
-WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLint* data)
-{
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
-        return;
-    }
-
-    if (!ValidateSamplerUniformSetter("Uniform2iv", location_object, data[0]) ||
-        !ValidateSamplerUniformSetter("Uniform2iv", location_object, data[1]))
+    if (!ValidateSamplerUniformSetter("uniform2iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform2iv", loc, data[1]))
     {
         return;
     }
 
     MakeContextCurrent();
-    gl->fUniform2iv(location, numElementsToUpload, data);
+    gl->fUniform2iv(rawLoc, numElementsToUpload, data);
 }
 
 void
-WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLint* data)
+WebGLContext::Uniform3iv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLint* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_INT, arrayLength,
+                                    "uniform3iv", &rawLoc,
+                                    &numElementsToUpload))
+    {
         return;
     }
 
-    if (!ValidateSamplerUniformSetter("Uniform3iv", location_object, data[0]) ||
-        !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[1]) ||
-        !ValidateSamplerUniformSetter("Uniform3iv", location_object, data[2]))
+    if (!ValidateSamplerUniformSetter("uniform3iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform3iv", loc, data[1]) ||
+        !ValidateSamplerUniformSetter("uniform3iv", loc, data[2]))
     {
         return;
     }
 
     MakeContextCurrent();
-    gl->fUniform3iv(location, numElementsToUpload, data);
+    gl->fUniform3iv(rawLoc, numElementsToUpload, data);
 }
 
 void
-WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLint* data)
+WebGLContext::Uniform4iv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLint* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_INT, arrayLength,
+                                    "uniform4iv", &rawLoc,
+                                    &numElementsToUpload))
+    {
+        return;
+    }
+
+    if (!ValidateSamplerUniformSetter("uniform4iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[1]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[2]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[3]))
+    {
         return;
     }
 
-    if (!ValidateSamplerUniformSetter("Uniform4iv", location_object, data[0]) ||
-        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[1]) ||
-        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[2]) ||
-        !ValidateSamplerUniformSetter("Uniform4iv", location_object, data[3]))
+    MakeContextCurrent();
+    gl->fUniform4iv(rawLoc, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform1fv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLfloat* data)
+{
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_FLOAT, arrayLength,
+                                    "uniform1fv", &rawLoc,
+                                    &numElementsToUpload))
+    {
+        return;
+    }
+
+    MakeContextCurrent();
+    gl->fUniform1fv(rawLoc, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform2fv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLfloat* data)
+{
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_FLOAT, arrayLength,
+                                    "uniform2fv", &rawLoc,
+                                    &numElementsToUpload))
     {
         return;
     }
 
     MakeContextCurrent();
-    gl->fUniform4iv(location, numElementsToUpload, data);
-}
-
-void
-WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLfloat* data)
-{
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
-        return;
-    }
-    MakeContextCurrent();
-    gl->fUniform1fv(location, numElementsToUpload, data);
+    gl->fUniform2fv(rawLoc, numElementsToUpload, data);
 }
 
 void
-WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLfloat* data)
+WebGLContext::Uniform3fv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLfloat* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_FLOAT, arrayLength,
+                                    "uniform3fv", &rawLoc,
+                                    &numElementsToUpload))
+    {
         return;
     }
+
     MakeContextCurrent();
-    gl->fUniform2fv(location, numElementsToUpload, data);
-}
-
-void
-WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLfloat* data)
-{
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
-        return;
-    }
-    MakeContextCurrent();
-    gl->fUniform3fv(location, numElementsToUpload, data);
+    gl->fUniform3fv(rawLoc, numElementsToUpload, data);
 }
 
 void
-WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object,
-                              uint32_t arrayLength, const GLfloat* data)
+WebGLContext::Uniform4fv_base(WebGLUniformLocation* loc, size_t arrayLength,
+                              const GLfloat* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location,
-                                    numElementsToUpload, arrayLength)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_FLOAT, arrayLength,
+                                    "uniform4fv", &rawLoc,
+                                    &numElementsToUpload))
+    {
         return;
     }
+
     MakeContextCurrent();
-    gl->fUniform4fv(location, numElementsToUpload, data);
+    gl->fUniform4fv(rawLoc, numElementsToUpload, data);
 }
 
+////////////////////////////////////////
+// Matrix
+
 void
-WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object,
-                                    WebGLboolean aTranspose, uint32_t arrayLength,
-                                    const float* data)
+WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* loc, bool transpose,
+                                    size_t arrayLength, const float* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location,
-                                         numElementsToUpload, arrayLength, aTranspose)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformMatrixArraySetter(loc, 2, LOCAL_GL_FLOAT, arrayLength,
+                                          transpose, "uniformMatrix2fv",
+                                          &rawLoc, &numElementsToUpload))
+    {
         return;
     }
+
     MakeContextCurrent();
-    gl->fUniformMatrix2fv(location, numElementsToUpload, false, data);
+    gl->fUniformMatrix2fv(rawLoc, numElementsToUpload, false, data);
 }
 
 void
-WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object,
-                                    WebGLboolean aTranspose, uint32_t arrayLength,
-                                    const float* data)
+WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* loc, bool transpose,
+                                    size_t arrayLength, const float* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location,
-                                         numElementsToUpload, arrayLength, aTranspose)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformMatrixArraySetter(loc, 3, LOCAL_GL_FLOAT, arrayLength,
+                                          transpose, "uniformMatrix3fv",
+                                          &rawLoc, &numElementsToUpload))
+    {
         return;
     }
+
     MakeContextCurrent();
-    gl->fUniformMatrix3fv(location, numElementsToUpload, false, data);
+    gl->fUniformMatrix3fv(rawLoc, numElementsToUpload, false, data);
 }
 
 void
-WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
-                                    WebGLboolean aTranspose, uint32_t arrayLength,
-                                    const float* data)
+WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* loc, bool transpose,
+                                    size_t arrayLength, const float* data)
 {
-    uint32_t numElementsToUpload;
-    GLint location;
-    if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location,
-                                         numElementsToUpload, arrayLength, aTranspose)) {
+    GLuint rawLoc;
+    GLsizei numElementsToUpload;
+    if (!ValidateUniformMatrixArraySetter(loc, 4, LOCAL_GL_FLOAT, arrayLength,
+                                          transpose, "uniformMatrix4fv",
+                                          &rawLoc, &numElementsToUpload))
+    {
         return;
     }
+
     MakeContextCurrent();
-    gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
+    gl->fUniformMatrix4fv(rawLoc, numElementsToUpload, false, data);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
 void
 WebGLContext::UseProgram(WebGLProgram *prog)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObjectAllowNull("useProgram", prog))
         return;
@@ -4262,19 +4338,28 @@ void
 WebGLContext::Finish() {
     if (IsContextLost())
         return;
     MakeContextCurrent();
     gl->fFinish();
 }
 
 void
-WebGLContext::LineWidth(GLfloat width) {
+WebGLContext::LineWidth(GLfloat width)
+{
     if (IsContextLost())
         return;
+
+    // Doing it this way instead of `if (width <= 0.0)` handles NaNs.
+    const bool isValid = width > 0.0;
+    if (!isValid) {
+        ErrorInvalidValue("lineWidth: `width` must be positive and non-zero.");
+        return;
+    }
+
     MakeContextCurrent();
     gl->fLineWidth(width);
 }
 
 void
 WebGLContext::PolygonOffset(GLfloat factor, GLfloat units) {
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -1317,119 +1317,178 @@ WebGLContext::ValidateAttribArraySetter(
     }
     if (arrayLength < cnt) {
         ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
         return false;
     }
     return true;
 }
 
-bool
-WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
-                                         GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
+static bool
+IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
 {
-    if (IsContextLost())
-        return false;
-    if (!ValidateUniformLocation(name, location_object))
-        return false;
-    location = location_object->Location();
-    uint32_t uniformElemSize = location_object->ElementSize();
-    if (expectedElemSize != uniformElemSize) {
-        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
-                              " got a uniform of element size %d", name,
-                              expectedElemSize,
-                              uniformElemSize);
+    switch (uniformType) {
+    case LOCAL_GL_BOOL:
+    case LOCAL_GL_BOOL_VEC2:
+    case LOCAL_GL_BOOL_VEC3:
+    case LOCAL_GL_BOOL_VEC4:
+        return true; // GLfloat(0.0) sets a bool to false.
+
+    case LOCAL_GL_INT:
+    case LOCAL_GL_SAMPLER_2D:
+    case LOCAL_GL_SAMPLER_CUBE:
+    case LOCAL_GL_INT_VEC2:
+    case LOCAL_GL_INT_VEC3:
+    case LOCAL_GL_INT_VEC4:
+        return setterType == LOCAL_GL_INT;
+
+    case LOCAL_GL_FLOAT:
+    case LOCAL_GL_FLOAT_VEC2:
+    case LOCAL_GL_FLOAT_VEC3:
+    case LOCAL_GL_FLOAT_VEC4:
+    case LOCAL_GL_FLOAT_MAT2:
+    case LOCAL_GL_FLOAT_MAT3:
+    case LOCAL_GL_FLOAT_MAT4:
+        return setterType == LOCAL_GL_FLOAT;
+
+    default:
+        MOZ_ASSERT(false); // should never get here
         return false;
     }
-    if (arrayLength == 0 ||
-        arrayLength % expectedElemSize)
-    {
-        ErrorInvalidValue("%s: expected an array of length a multiple"
-                          " of %d, got an array of length %d", name,
-                          expectedElemSize,
-                          arrayLength);
+}
+
+static bool
+CheckUniformSizeAndType(WebGLContext& webgl, WebGLUniformLocation* loc,
+                        uint8_t setterElemSize, GLenum setterType,
+                        const char* info)
+{
+    if (setterElemSize != loc->ElementSize()) {
+        webgl.ErrorInvalidOperation("%s: Bad uniform size: %i", info,
+                                    loc->ElementSize());
+        return false;
+    }
+
+    if (!IsUniformSetterTypeValid(setterType, loc->Info().type)) {
+        webgl.ErrorInvalidOperation("%s: Bad uniform type: %i", info,
+                                    loc->Info().type);
         return false;
     }
-    const WebGLUniformInfo& info = location_object->Info();
-    if (!info.isArray &&
-        arrayLength != expectedElemSize) {
-        ErrorInvalidOperation("%s: expected an array of length exactly"
-                              " %d (since this uniform is not an array"
-                              " uniform), got an array of length %d", name,
-                              expectedElemSize,
-                              arrayLength);
+
+    return true;
+}
+
+static bool
+CheckUniformArrayLength(WebGLContext& webgl, WebGLUniformLocation* loc,
+                        uint8_t setterElemSize, size_t setterArraySize,
+                        const char* info)
+{
+    if (setterArraySize == 0 ||
+        setterArraySize % setterElemSize)
+    {
+        webgl.ErrorInvalidValue("%s: expected an array of length a multiple of"
+                                " %d, got an array of length %d.", info,
+                                setterElemSize, setterArraySize);
         return false;
     }
-    numElementsToUpload =
-        std::min(info.arraySize, arrayLength / expectedElemSize);
+
+    if (!loc->Info().isArray &&
+        setterArraySize != setterElemSize)
+    {
+        webgl.ErrorInvalidOperation("%s: expected an array of length exactly %d"
+                                    " (since this uniform is not an array"
+                                    " uniform), got an array of length %d.",
+                                    info, setterElemSize, setterArraySize);
+        return false;
+    }
+
     return true;
 }
 
 bool
-WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
-                                              GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
-                                              WebGLboolean aTranspose)
+WebGLContext::ValidateUniformSetter(WebGLUniformLocation* loc,
+                                    uint8_t setterElemSize, GLenum setterType,
+                                    const char* info, GLuint* out_rawLoc)
 {
-    uint32_t expectedElemSize = (dim)*(dim);
     if (IsContextLost())
         return false;
-    if (!ValidateUniformLocation(name, location_object))
-        return false;
-    location = location_object->Location();
-    uint32_t uniformElemSize = location_object->ElementSize();
-    if (expectedElemSize != uniformElemSize) {
-        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
-                              " got a uniform of element size %d", name,
-                              expectedElemSize,
-                              uniformElemSize);
-        return false;
-    }
-    if (arrayLength == 0 ||
-        arrayLength % expectedElemSize)
-    {
-        ErrorInvalidValue("%s: expected an array of length a multiple"
-                          " of %d, got an array of length %d", name,
-                          expectedElemSize,
-                          arrayLength);
+
+    if (!ValidateUniformLocation(info, loc))
         return false;
-    }
-    const WebGLUniformInfo& info = location_object->Info();
-    if (!info.isArray &&
-        arrayLength != expectedElemSize) {
-        ErrorInvalidOperation("%s: expected an array of length exactly"
-                              " %d (since this uniform is not an array"
-                              " uniform), got an array of length %d", name,
-                              expectedElemSize,
-                              arrayLength);
+
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
         return false;
-    }
-    if (aTranspose) {
-        ErrorInvalidValue("%s: transpose must be FALSE as per the "
-                          "OpenGL ES 2.0 spec", name);
-        return false;
-    }
-    numElementsToUpload =
-        std::min(info.arraySize, arrayLength / (expectedElemSize));
+
+    *out_rawLoc = loc->Location();
     return true;
 }
 
 bool
-WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
+WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
+                                         uint8_t setterElemSize, GLenum setterType,
+                                         size_t setterArraySize,
+                                         const char* info, GLuint* out_rawLoc,
+                                         GLsizei* out_numElementsToUpload)
 {
     if (IsContextLost())
         return false;
-    if (!ValidateUniformLocation(name, location_object))
+
+    if (!ValidateUniformLocation(info, loc))
+        return false;
+
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
         return false;
-    location = location_object->Location();
+
+    if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
+                                 info))
+    {
+        return false;
+    }
+
+    *out_rawLoc = loc->Location();
+    *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
+                                        setterArraySize / setterElemSize);
     return true;
 }
 
-bool WebGLContext::ValidateAttribIndex(GLuint index, const char *info)
+bool
+WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
+                                               uint8_t setterDims,
+                                               GLenum setterType,
+                                               size_t setterArraySize,
+                                               bool setterTranspose,
+                                               const char* info,
+                                               GLuint* out_rawLoc,
+                                               GLsizei* out_numElementsToUpload)
 {
-    return mBoundVertexArray->EnsureAttrib(index, info);
+    uint8_t setterElemSize = setterDims * setterDims;
+
+    if (IsContextLost())
+        return false;
+
+    if (!ValidateUniformLocation(info, loc))
+        return false;
+
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
+        return false;
+
+    if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
+                                 info))
+    {
+        return false;
+    }
+
+    if (setterTranspose) {
+        ErrorInvalidValue("%s: `transpose` must be false.", info);
+        return false;
+    }
+
+    *out_rawLoc = loc->Location();
+    *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
+                                        setterArraySize / setterElemSize);
+    return true;
 }
 
 bool WebGLContext::ValidateStencilParamsForDrawCall()
 {
   const char *msg = "%s set different front and back stencil %s. Drawing in this configuration is not allowed.";
   if (mStencilRefFront != mStencilRefBack) {
       ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
       return false;
--- a/dom/canvas/WebGLContextVertices.cpp
+++ b/dom/canvas/WebGLContextVertices.cpp
@@ -15,22 +15,46 @@
 #include "WebGLTexture.h"
 #include "WebGLUniformInfo.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 using namespace mozilla;
 using namespace dom;
 
+static bool
+CheckAttribIndex(WebGLContext& webgl, GLuint index, const char* info)
+{
+    if (index >= webgl.MaxVertexAttribs()) {
+        if (index == GLuint(-1)) {
+            webgl.ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
+                                    " probably comes from a getAttribLocation()"
+                                    " call, where this return value -1 means"
+                                    " that the passed name didn't correspond to"
+                                    " an active attribute in the specified"
+                                    " program.", info);
+        } else {
+            webgl.ErrorInvalidValue("%s: `index` must be less than"
+                                    " MAX_VERTEX_ATTRIBS.", info);
+        }
+        return false;
+    }
+
+    return true;
+}
+
 void
 WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
 {
     if (IsContextLost())
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib1f"))
+        return;
+
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib1f(index, x0);
     } else {
         mVertexAttrib0Vector[0] = x0;
         mVertexAttrib0Vector[1] = 0;
         mVertexAttrib0Vector[2] = 0;
@@ -41,16 +65,19 @@ WebGLContext::VertexAttrib1f(GLuint inde
 }
 
 void
 WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
 {
     if (IsContextLost())
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib2f"))
+        return;
+
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib2f(index, x0, x1);
     } else {
         mVertexAttrib0Vector[0] = x0;
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = 0;
@@ -61,16 +88,19 @@ WebGLContext::VertexAttrib2f(GLuint inde
 }
 
 void
 WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
 {
     if (IsContextLost())
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib3f"))
+        return;
+
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib3f(index, x0, x1, x2);
     } else {
         mVertexAttrib0Vector[0] = x0;
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = x2;
@@ -82,158 +112,178 @@ WebGLContext::VertexAttrib3f(GLuint inde
 
 void
 WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
                              GLfloat x2, GLfloat x3)
 {
     if (IsContextLost())
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib4f"))
+        return;
+
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib4f(index, x0, x1, x2, x3);
     } else {
         mVertexAttrib0Vector[0] = x0;
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = x2;
         mVertexAttrib0Vector[3] = x3;
         if (gl->IsGLES())
             gl->fVertexAttrib4f(index, x0, x1, x2, x3);
     }
 }
 
 
 void
-WebGLContext::VertexAttrib1fv_base(GLuint idx, uint32_t arrayLength,
+WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib1fv"))
+        return;
+
     MakeContextCurrent();
-    if (idx) {
-        gl->fVertexAttrib1fv(idx, ptr);
+    if (index) {
+        gl->fVertexAttrib1fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = GLfloat(0);
         mVertexAttrib0Vector[2] = GLfloat(0);
         mVertexAttrib0Vector[3] = GLfloat(1);
         if (gl->IsGLES())
-            gl->fVertexAttrib1fv(idx, ptr);
+            gl->fVertexAttrib1fv(index, ptr);
     }
 }
 
 void
-WebGLContext::VertexAttrib2fv_base(GLuint idx, uint32_t arrayLength,
+WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib2fv"))
+        return;
+
     MakeContextCurrent();
-    if (idx) {
-        gl->fVertexAttrib2fv(idx, ptr);
+    if (index) {
+        gl->fVertexAttrib2fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = GLfloat(0);
         mVertexAttrib0Vector[3] = GLfloat(1);
         if (gl->IsGLES())
-            gl->fVertexAttrib2fv(idx, ptr);
+            gl->fVertexAttrib2fv(index, ptr);
     }
 }
 
 void
-WebGLContext::VertexAttrib3fv_base(GLuint idx, uint32_t arrayLength,
+WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib3fv"))
+        return;
+
     MakeContextCurrent();
-    if (idx) {
-        gl->fVertexAttrib3fv(idx, ptr);
+    if (index) {
+        gl->fVertexAttrib3fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = ptr[2];
         mVertexAttrib0Vector[3] = GLfloat(1);
         if (gl->IsGLES())
-            gl->fVertexAttrib3fv(idx, ptr);
+            gl->fVertexAttrib3fv(index, ptr);
     }
 }
 
 void
-WebGLContext::VertexAttrib4fv_base(GLuint idx, uint32_t arrayLength,
+WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttrib4fv"))
+        return;
+
     MakeContextCurrent();
-    if (idx) {
-        gl->fVertexAttrib4fv(idx, ptr);
+    if (index) {
+        gl->fVertexAttrib4fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
         mVertexAttrib0Vector[2] = ptr[2];
         mVertexAttrib0Vector[3] = ptr[3];
         if (gl->IsGLES())
-            gl->fVertexAttrib4fv(idx, ptr);
+            gl->fVertexAttrib4fv(index, ptr);
     }
 }
 
 void
 WebGLContext::EnableVertexAttribArray(GLuint index)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
+    if (!CheckAttribIndex(*this, index, "enableVertexAttribArray"))
         return;
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     gl->fEnableVertexAttribArray(index);
-    MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
+
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
     mBoundVertexArray->mAttribs[index].enabled = true;
 }
 
 void
 WebGLContext::DisableVertexAttribArray(GLuint index)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
+    if (!CheckAttribIndex(*this, index, "disableVertexAttribArray"))
         return;
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     if (index || gl->IsGLES())
         gl->fDisableVertexAttribArray(index);
 
-    MOZ_ASSERT(mBoundVertexArray->HasAttrib(index)); // should have been validated earlier
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
     mBoundVertexArray->mAttribs[index].enabled = false;
 }
 
-
 JS::Value
 WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
                               ErrorResult& rv)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (!ValidateAttribIndex(index, "getVertexAttrib"))
+    if (!CheckAttribIndex(*this, index, "getVertexAttrib"))
         return JS::NullValue();
 
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
+
     MakeContextCurrent();
 
     switch (pname) {
         case LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
         {
             return WebGLObjectAsJSValue(cx, mBoundVertexArray->mAttribs[index].buf.get(), rv);
         }
 
@@ -295,45 +345,49 @@ WebGLContext::GetVertexAttrib(JSContext*
             return JS::BooleanValue(mBoundVertexArray->mAttribs[index].normalized);
         }
 
         default:
             break;
     }
 
     ErrorInvalidEnumInfo("getVertexAttrib: parameter", pname);
-
     return JS::NullValue();
 }
 
 WebGLsizeiptr
 WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
 {
     if (IsContextLost())
         return 0;
 
-    if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
+    if (!CheckAttribIndex(*this, index, "getVertexAttribOffset"))
         return 0;
 
     if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
         ErrorInvalidEnum("getVertexAttribOffset: bad parameter");
         return 0;
     }
 
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
     return mBoundVertexArray->mAttribs[index].byteOffset;
 }
 
 void
 WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
                                   WebGLboolean normalized, GLsizei stride,
                                   WebGLintptr byteOffset)
 {
     if (IsContextLost())
         return;
 
+    if (!CheckAttribIndex(*this, index, "vertexAttribPointer"))
+        return;
+
     if (mBoundArrayBuffer == nullptr)
         return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
 
     GLsizei requiredAlignment = 1;
     switch (type) {
         case LOCAL_GL_BYTE:
         case LOCAL_GL_UNSIGNED_BYTE:
             requiredAlignment = 1;
@@ -348,19 +402,18 @@ WebGLContext::VertexAttribPointer(GLuint
             break;
         default:
             return ErrorInvalidEnumInfo("vertexAttribPointer: type", type);
     }
 
     // requiredAlignment should always be a power of two.
     GLsizei requiredAlignmentMask = requiredAlignment - 1;
 
-    if (!ValidateAttribIndex(index, "vertexAttribPointer")) {
-        return;
-    }
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
 
     if (size < 1 || size > 4)
         return ErrorInvalidValue("vertexAttribPointer: invalid element size");
 
     if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
         return ErrorInvalidValue("vertexAttribPointer: negative or too large stride");
 
     if (byteOffset < 0)
@@ -401,19 +454,21 @@ WebGLContext::VertexAttribPointer(GLuint
 }
 
 void
 WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateAttribIndex(index, "vertexAttribDivisor")) {
+    if (!CheckAttribIndex(*this, index, "vertexAttribDivisor"))
         return;
-    }
+
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
 
     WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
     vd.divisor = divisor;
 
     InvalidateBufferFetching();
 
     MakeContextCurrent();
 
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -44,34 +44,24 @@ WebGLVertexArray::Delete()
 {
     DeleteImpl();
 
     LinkedListElement<WebGLVertexArray>::removeFrom(mContext->mVertexArrays);
     mElementArrayBuffer = nullptr;
     mAttribs.Clear();
 }
 
-bool
-WebGLVertexArray::EnsureAttrib(GLuint index, const char *info)
+void
+WebGLVertexArray::EnsureAttrib(GLuint index)
 {
-    if (index >= GLuint(mContext->mGLMaxVertexAttribs)) {
-        if (index == GLuint(-1)) {
-            mContext->ErrorInvalidValue("%s: index -1 is invalid. That probably comes from a getAttribLocation() call, "
-                                        "where this return value -1 means that the passed name didn't correspond to an active attribute in "
-                                        "the specified program.", info);
-        } else {
-            mContext->ErrorInvalidValue("%s: index %d is out of range", info, index);
-        }
-        return false;
-    }
-    else if (index >= mAttribs.Length()) {
+    MOZ_ASSERT(index < GLuint(mContext->mGLMaxVertexAttribs));
+
+    if (index >= mAttribs.Length()) {
         mAttribs.SetLength(index + 1);
     }
-
-    return true;
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLVertexArray,
   mAttribs,
   mElementArrayBuffer)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLVertexArray, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLVertexArray, Release)
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -56,17 +56,17 @@ public:
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLVertexArray)
 
     // -------------------------------------------------------------------------
     // MEMBER FUNCTIONS
 
-    bool EnsureAttrib(GLuint index, const char *info);
+    void EnsureAttrib(GLuint index);
     bool HasAttrib(GLuint index) {
         return index < mAttribs.Length();
     }
     bool IsAttribArrayEnabled(GLuint index) {
         return HasAttrib(index) && mAttribs[index].enabled;
     }