Backout ca411b1cf001 (bug 1109945) for shader editor failures
authorWes Kocher <wkocher@mozilla.com>
Fri, 09 Jan 2015 21:03:54 -0800
changeset 223169 6dab2820469ae49c71d3bd7045d44a915810f7b5
parent 223168 6bed029c93f6cb2d93b3cc668260b3ef141ff2f7
child 223170 8ce96306c2d339d94a49a442d5c56320b13b8169
push id10769
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 14:15:52 +0000
treeherderfx-team@0e9765732906 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1109945
milestone37.0a1
backs outca411b1cf0019393548598a66af9e08a711cd6f8
Backout ca411b1cf001 (bug 1109945) for shader editor failures
dom/canvas/WebGL2Context.cpp
dom/canvas/WebGL2ContextTransformFeedback.cpp
dom/canvas/WebGL2ContextUniforms.cpp
dom/canvas/WebGLActiveInfo.cpp
dom/canvas/WebGLActiveInfo.h
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertices.cpp
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLProgram.h
dom/canvas/WebGLShader.cpp
dom/canvas/WebGLShader.h
dom/canvas/WebGLShaderValidator.cpp
dom/canvas/WebGLShaderValidator.h
dom/canvas/WebGLUniformInfo.h
dom/canvas/WebGLUniformLocation.cpp
dom/canvas/WebGLUniformLocation.h
dom/canvas/WebGLValidateStrings.cpp
dom/canvas/WebGLValidateStrings.h
dom/canvas/moz.build
dom/canvas/test/webgl-conformance/conformance/misc/bad-arguments-test.html
gfx/gl/GLContext.h
gfx/gl/GLContextSymbols.h
modules/libpref/init/all.js
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -147,14 +147,12 @@ WebGLContext::InitWebGL2()
     mBoundUniformBuffers =
         MakeUnique<WebGLRefPtr<WebGLBuffer>[]>(mGLMaxUniformBufferBindings);
 
     mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
     mBoundTransformFeedback = mDefaultTransformFeedback;
     auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
     mBoundTransformFeedbackBuffers.reset(xfBuffers);
 
-    mBypassShaderValidation = true;
-
     return true;
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -207,50 +207,48 @@ WebGL2Context::TransformFeedbackVaryings
 
     GLsizei count = varyings.Length();
     GLchar** tmpVaryings = (GLchar**) nsMemory::Alloc(count * sizeof(GLchar*));
 
     for (GLsizei n = 0; n < count; n++) {
         tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
     }
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     MakeContextCurrent();
     gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
 
     NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
 }
 
+
 already_AddRefed<WebGLActiveInfo>
 WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getTransformFeedbackVarying: program", program))
         return nullptr;
 
     MakeContextCurrent();
 
     GLint len = 0;
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
     if (!len)
         return nullptr;
 
     UniquePtr<char[]> name(new char[len]);
     GLint tfsize = 0;
     GLuint tftype = 0;
 
     gl->fGetTransformFeedbackVarying(progname, index, len, &len, &tfsize, &tftype, name.get());
     if (len == 0 || tfsize == 0 || tftype == 0)
         return nullptr;
 
-    MOZ_CRASH("todo");
-    /*
-    // Reverse lookup of name
-    nsCString reverseMappedName;
-    prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
+    // TODO(djg): Reverse lookup of name
+    // nsCString reverseMappedName;
+    // prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
 
     nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name.get()));
     return result.forget();
-    */
 }
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -391,17 +391,17 @@ WebGL2Context::GetUniformIndices(WebGLPr
         return;
 
     if (!ValidateObject("getUniformIndices: program", program))
         return;
 
     if (!uniformNames.Length())
         return;
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     size_t count = uniformNames.Length();
     nsTArray<GLuint>& arr = retval.SetValue();
 
     MakeContextCurrent();
 
     for (size_t n = 0; n < count; n++) {
         NS_LossyConvertUTF16toASCII name(uniformNames[n]);
         //        const GLchar* glname = name.get();
@@ -426,17 +426,17 @@ WebGL2Context::GetActiveUniforms(WebGLPr
 
     if (!ValidateObject("getActiveUniforms: program", program))
         return;
 
     size_t count = uniformIndices.Length();
     if (!count)
         return;
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     nsTArray<GLint>& arr = retval.SetValue();
     arr.SetLength(count);
 
     MakeContextCurrent();
     gl->fGetActiveUniformsiv(progname, count, uniformIndices.Elements(), pname,
                              arr.Elements());
 }
 
@@ -445,24 +445,27 @@ WebGL2Context::GetUniformBlockIndex(WebG
                                     const nsAString& uniformBlockName)
 {
     if (IsContextLost())
         return 0;
 
     if (!ValidateObject("getUniformBlockIndex: program", program))
         return 0;
 
-    // Leave this unchecked for now.
+    if (!ValidateGLSLVariableName(uniformBlockName, "getUniformBlockIndex"))
+        return 0;
 
-    const NS_LossyConvertUTF16toASCII cname(uniformBlockName);
+    NS_LossyConvertUTF16toASCII cname(uniformBlockName);
+    nsCString mappedName;
+    program->MapIdentifier(cname, &mappedName);
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
 
     MakeContextCurrent();
-    return gl->fGetUniformBlockIndex(progname, cname.BeginReading());
+    return gl->fGetUniformBlockIndex(progname, mappedName.get());
 }
 
 static bool
 GetUniformBlockActiveUniforms(gl::GLContext* gl, JSContext* cx,
                               WebGL2Context* owner, GLuint progname,
                               GLuint uniformBlockIndex,
                               JS::MutableHandleObject out_array)
 {
@@ -493,17 +496,17 @@ WebGL2Context::GetActiveUniformBlockPara
 {
     retval.SetNull();
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockParameter: program", program))
         return;
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     GLint param = 0;
 
     MakeContextCurrent();
 
     switch(pname) {
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
         gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, &param);
@@ -543,17 +546,17 @@ WebGL2Context::GetActiveUniformBlockName
                                          nsAString& retval)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockName: program", program))
         return;
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
     GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
     GLsizei length = 0;
 
     MakeContextCurrent();
     gl->fGetActiveUniformBlockName(progname, uniformBlockIndex,
                                    WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH, &length,
                                    nameBuffer);
     retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(nameBuffer)));
@@ -566,13 +569,13 @@ WebGL2Context::UniformBlockBinding(WebGL
                                    GLuint uniformBlockBinding)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("uniformBlockBinding: program", program))
         return;
 
-    GLuint progname = program->mGLName;
+    GLuint progname = program->GLName();
 
     MakeContextCurrent();
     gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
 }
--- a/dom/canvas/WebGLActiveInfo.cpp
+++ b/dom/canvas/WebGLActiveInfo.cpp
@@ -1,99 +1,20 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLActiveInfo.h"
 
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "WebGLContext.h"
+#include "WebGLTexture.h"
 
 namespace mozilla {
 
-static uint8_t
-ElemSizeFromType(GLenum elemType)
+JSObject*
+WebGLActiveInfo::WrapObject(JSContext* cx)
 {
-    switch (elemType) {
-    case LOCAL_GL_BOOL:
-    case LOCAL_GL_FLOAT:
-    case LOCAL_GL_INT:
-    case LOCAL_GL_INT_SAMPLER_2D:
-    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_INT_SAMPLER_3D:
-    case LOCAL_GL_INT_SAMPLER_CUBE:
-    case LOCAL_GL_SAMPLER_2D:
-    case LOCAL_GL_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
-    case LOCAL_GL_SAMPLER_2D_SHADOW:
-    case LOCAL_GL_SAMPLER_CUBE:
-    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
-        return 1;
-
-    case LOCAL_GL_BOOL_VEC2:
-    case LOCAL_GL_FLOAT_VEC2:
-    case LOCAL_GL_INT_VEC2:
-        return 2;
-
-    case LOCAL_GL_BOOL_VEC3:
-    case LOCAL_GL_FLOAT_VEC3:
-    case LOCAL_GL_INT_VEC3:
-        return 3;
-
-
-    case LOCAL_GL_BOOL_VEC4:
-    case LOCAL_GL_FLOAT_MAT2:
-    case LOCAL_GL_FLOAT_VEC4:
-    case LOCAL_GL_INT_VEC4:
-        return 4;
-
-    case LOCAL_GL_FLOAT_MAT2x3:
-    case LOCAL_GL_FLOAT_MAT3x2:
-        return 6;
-
-    case LOCAL_GL_FLOAT_MAT2x4:
-    case LOCAL_GL_FLOAT_MAT4x2:
-        return 8;
-
-    case LOCAL_GL_FLOAT_MAT3:
-        return 9;
-
-    case LOCAL_GL_FLOAT_MAT3x4:
-    case LOCAL_GL_FLOAT_MAT4x3:
-        return 12;
-
-    case LOCAL_GL_FLOAT_MAT4:
-        return 16;
-
-    default:
-        MOZ_CRASH("Bad `elemType`.");
-    }
+    return dom::WebGLActiveInfoBinding::Wrap(cx, this);
 }
 
-WebGLActiveInfo::WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
-                                 const nsACString& baseUserName,
-                                 const nsACString& baseMappedName)
-    : mElemCount(elemCount)
-    , mElemType(elemType)
-    , mBaseUserName(baseUserName)
-    , mIsArray(isArray)
-    , mElemSize(ElemSizeFromType(elemType))
-    , mBaseMappedName(baseMappedName)
-{ }
-
-////////////////////////////////////////////////////////////////////////////////
-
-JSObject*
-WebGLActiveInfo::WrapObject(JSContext* js)
-{
-    return dom::WebGLActiveInfoBinding::Wrap(js, this);
-}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLActiveInfo)
-
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLActiveInfo, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLActiveInfo, Release)
-
 } // namespace mozilla
--- a/dom/canvas/WebGLActiveInfo.h
+++ b/dom/canvas/WebGLActiveInfo.h
@@ -1,83 +1,55 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_ACTIVE_INFO_H_
 #define WEBGL_ACTIVE_INFO_H_
 
-#include "GLDefs.h"
 #include "js/TypeDecls.h"
-#include "mozilla/Attributes.h"
-#include "nsISupportsImpl.h" // NS_INLINE_DECL_REFCOUNTING
 #include "nsString.h"
-#include "nsWrapperCache.h"
+#include "WebGLObjectModel.h"
 
 namespace mozilla {
 
 class WebGLActiveInfo MOZ_FINAL
-    : public nsWrapperCache
 {
 public:
-    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLActiveInfo)
-    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLActiveInfo)
-
-    const GLint mElemCount; // `size`
-    const GLenum mElemType; // `type`
-    const nsCString mBaseUserName; // `name`, but ASCII, and without any final "[0]".
-
-    // Not actually part of ActiveInfo:
-    const bool mIsArray;
-    const uint8_t mElemSize;
-    const nsCString mBaseMappedName; // Without any final "[0]".
-
-    WebGLActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
-                    const nsACString& baseUserName, const nsACString& baseMappedName);
-
-
-    /* GLES 2.0.25, p33:
-     *   This command will return as much information about active
-     *   attributes as possible. If no information is available, length will
-     *   be set to zero and name will be an empty string. This situation
-     *   could arise if GetActiveAttrib is issued after a failed link.
-     *
-     * It's the same for GetActiveUniform.
-     */
-    static WebGLActiveInfo* CreateInvalid() {
-        return new WebGLActiveInfo();
-    }
+    WebGLActiveInfo(GLint size, GLenum type, const nsACString& name)
+        : mSize(size)
+        , mType(type)
+        , mName(NS_ConvertASCIItoUTF16(name))
+    {}
 
     // WebIDL attributes
+
     GLint Size() const {
-        return mElemCount;
+        return mSize;
     }
 
     GLenum Type() const {
-        return mElemType;
+        return mType;
     }
 
     void GetName(nsString& retval) const {
-        CopyASCIItoUTF16(mBaseUserName, retval);
-        if (mIsArray)
-            retval.AppendLiteral("[0]");
+        retval = mName;
     }
 
-    virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
+    JSObject* WrapObject(JSContext* cx);
+
+   NS_INLINE_DECL_REFCOUNTING(WebGLActiveInfo)
 
 private:
-    WebGLActiveInfo()
-        : mElemCount(0)
-        , mElemType(0)
-        , mBaseUserName("")
-        , mIsArray(false)
-        , mElemSize(0)
-        , mBaseMappedName("")
-    { }
+    // Private destructor, to discourage deletion outside of Release():
+    ~WebGLActiveInfo()
+    {
+    }
 
-    // Private destructor, to discourage deletion outside of Release():
-    ~WebGLActiveInfo() { }
+    GLint mSize;
+    GLenum mType;
+    nsString mName;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_ACTIVE_INFO_H_
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -197,30 +197,31 @@ WebGLContextOptions::WebGLContextOptions
 {
     // Set default alpha state based on preference.
     if (Preferences::GetBool("webgl.default-no-alpha", false))
         alpha = false;
 }
 
 WebGLContext::WebGLContext()
     : WebGLContextUnchecked(nullptr)
-    , mBypassShaderValidation(false)
     , mNeedsFakeNoAlpha(false)
 {
     mGeneration = 0;
     mInvalidated = false;
     mShouldPresent = true;
     mResetLayer = true;
     mOptionsFrozen = false;
 
     mActiveTexture = 0;
     mPixelStoreFlipY = false;
     mPixelStorePremultiplyAlpha = false;
     mPixelStoreColorspaceConversion = BROWSER_DEFAULT_WEBGL;
 
+    mShaderValidation = true;
+
     mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
 
     mVertexAttrib0Vector[0] = 0;
     mVertexAttrib0Vector[1] = 0;
     mVertexAttrib0Vector[2] = 0;
     mVertexAttrib0Vector[3] = 1;
     mFakeVertexAttrib0BufferObjectVector[0] = 0;
     mFakeVertexAttrib0BufferObjectVector[1] = 0;
@@ -324,17 +325,16 @@ WebGLContext::DestroyResourcesAndContext
     mBoundArrayBuffer = nullptr;
     mBoundCopyReadBuffer = nullptr;
     mBoundCopyWriteBuffer = nullptr;
     mBoundPixelPackBuffer = nullptr;
     mBoundPixelUnpackBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mBoundUniformBuffer = nullptr;
     mCurrentProgram = nullptr;
-    mActiveProgramLinkInfo = nullptr;
     mBoundFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
     mBoundTransformFeedback = nullptr;
     mDefaultTransformFeedback = nullptr;
 
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -14,17 +14,16 @@
 #include "mozilla/WeakPtr.h"
 
 #include "GLDefs.h"
 #include "WebGLActiveInfo.h"
 #include "WebGLContextUnchecked.h"
 #include "WebGLObjectModel.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLTexture.h"
-#include "WebGLShaderValidator.h"
 #include "WebGLStrongTypes.h"
 #include <stdarg.h>
 
 #include "nsTArray.h"
 #include "nsCycleCollectionNoteChild.h"
 
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
@@ -92,20 +91,16 @@ class ImageData;
 struct WebGLContextAttributes;
 template<typename> struct Nullable;
 }
 
 namespace gfx {
 class SourceSurface;
 }
 
-namespace webgl {
-struct LinkedProgramInfo;
-}
-
 WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
 
 void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
 
 struct WebGLContextOptions
 {
     // these are defaults
     WebGLContextOptions();
@@ -374,19 +369,17 @@ public:
                            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 CompileShaderANGLE(WebGLShader* shader);
-    void CompileShaderBypass(WebGLShader* shader, const nsCString& shaderSource);
-    void CompressedTexImage2D(GLenum target, GLint level,
+    void CompressedTexImage2D(GLenum texImageTarget, GLint level,
                               GLenum internalformat, GLsizei width,
                               GLsizei height, GLint border,
                               const dom::ArrayBufferView& view);
     void CompressedTexSubImage2D(GLenum texImageTarget, GLint level,
                                  GLint xoffset, GLint yoffset, GLsizei width,
                                  GLsizei height, GLenum format,
                                  const dom::ArrayBufferView& view);
     void CopyTexImage2D(GLenum texImageTarget, GLint level,
@@ -837,20 +830,18 @@ public:
         UniformMatrix4fv_base(loc, transpose, value.Length(),
                               value.Elements());
     }
     void UniformMatrix4fv_base(WebGLUniformLocation* loc,
                                WebGLboolean transpose, size_t arrayLength,
                                const float* data);
 
     void UseProgram(WebGLProgram* prog);
-
     bool ValidateAttribArraySetter(const char* name, uint32_t count,
                                    uint32_t arrayLength);
-    bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
     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);
@@ -1120,19 +1111,18 @@ protected:
     GLuint mActiveTexture;
 
     // glGetError sources:
     bool mEmitContextLostErrorOnce;
     GLenum mWebGLError;
     GLenum mUnderlyingGLError;
     GLenum GetAndFlushUnderlyingGLErrors();
 
-    bool mBypassShaderValidation;
-
-    webgl::ShaderValidator* CreateShaderValidator(GLenum shaderType) const;
+    // whether shader validation is supported
+    bool mShaderValidation;
 
     // some GL constants
     int32_t mGLMaxVertexAttribs;
     int32_t mGLMaxTextureUnits;
     int32_t mGLMaxTextureSize;
     int32_t mGLMaxTextureSizeLog2;
     int32_t mGLMaxCubeMapTextureSize;
     int32_t mGLMaxCubeMapTextureSizeLog2;
@@ -1147,20 +1137,16 @@ protected:
     GLuint  mGLMaxTransformFeedbackSeparateAttribs;
     GLuint  mGLMaxUniformBufferBindings;
 
 public:
     GLuint MaxVertexAttribs() const {
         return mGLMaxVertexAttribs;
     }
 
-    GLuint GLMaxTextureUnits() const {
-        return mGLMaxTextureUnits;
-    }
-
 
     bool IsFormatValidForFB(GLenum sizedFormat) const;
 
 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
@@ -1232,16 +1218,20 @@ protected:
                               WebGLTexImageFunc func, WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char* info);
     bool ValidateAttribIndex(GLuint index, const char* info);
     bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
                                WebGLboolean normalized, GLsizei stride,
                                WebGLintptr byteOffset, 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,
                               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,
@@ -1278,20 +1268,16 @@ protected:
                                   GLsizei levelHeight, WebGLTexImageFunc func,
                                   WebGLTexDimensions dims);
     bool ValidateCompTexImageDataSize(GLint level, GLenum internalFormat,
                                       GLsizei width, GLsizei height,
                                       uint32_t byteLength,
                                       WebGLTexImageFunc func,
                                       WebGLTexDimensions dims);
 
-    bool ValidateUniformLocationForProgram(WebGLUniformLocation* location,
-                                           WebGLProgram* program,
-                                           const char* funcName);
-
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
 
     // If jsArrayType is MaxTypedArrayViewType, it means no array.
@@ -1410,17 +1396,16 @@ protected:
     void ForceLoseContext(bool simulateLoss = false);
     void ForceRestoreContext();
 
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
-    RefPtr<const webgl::LinkedProgramInfo> mActiveProgramLinkInfo;
 
     uint32_t mMaxFramebufferColorAttachments;
 
     WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
     WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
     WebGLRefPtr<WebGLTransformFeedback> mBoundTransformFeedback;
     WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
 
@@ -1600,17 +1585,17 @@ inline bool
 WebGLContext::ValidateObjectAssumeNonNull(const char* info, ObjectType* object)
 {
     MOZ_ASSERT(object);
 
     if (!ValidateObjectAllowDeletedOrNull(info, object))
         return false;
 
     if (object->IsDeleted()) {
-        ErrorInvalidValue("%s: Deleted object passed as argument.", info);
+        ErrorInvalidValue("%s: deleted object passed as argument", info);
         return false;
     }
 
     return true;
 }
 
 template<class ObjectType>
 inline bool
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -9,16 +9,17 @@
 #include "mozilla/CheckedInt.h"
 #include "WebGLBuffer.h"
 #include "WebGLContextUtils.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLProgram.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLShader.h"
 #include "WebGLTexture.h"
+#include "WebGLUniformInfo.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 
 // For a Tegra workaround.
@@ -404,25 +405,21 @@ void WebGLContext::Draw_cleanup()
 /*
  * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
  * that will be legal to be read from bound VBOs.
  */
 
 bool
 WebGLContext::ValidateBufferFetching(const char* info)
 {
-    MOZ_ASSERT(mCurrentProgram);
-    // Note that mCurrentProgram->IsLinked() is NOT GUARANTEED.
-    MOZ_ASSERT(mActiveProgramLinkInfo);
-
 #ifdef DEBUG
     GLint currentProgram = 0;
     MakeContextCurrent();
     gl->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &currentProgram);
-    MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->mGLName,
+    MOZ_ASSERT(GLuint(currentProgram) == mCurrentProgram->GLName(),
                "WebGL: current program doesn't agree with GL state");
 #endif
 
     if (mBufferFetchingIsVerified)
         return true;
 
     bool hasPerVertex = false;
     uint32_t maxVertices = UINT32_MAX;
@@ -439,17 +436,17 @@ WebGLContext::ValidateBufferFetching(con
 
         if (vd.buf == nullptr) {
             ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info, i);
             return false;
         }
 
         // If the attrib is not in use, then we don't have to validate
         // it, just need to make sure that the binding is non-null.
-        if (!mActiveProgramLinkInfo->HasActiveAttrib(i))
+        if (!mCurrentProgram->IsAttribInUse(i))
             continue;
 
         // the base offset
         CheckedUint32 checked_byteLength = CheckedUint32(vd.buf->ByteLength()) - vd.byteOffset;
         CheckedUint32 checked_sizeOfLastElement = CheckedUint32(vd.componentSize()) * vd.size;
 
         if (!checked_byteLength.isValid() ||
             !checked_sizeOfLastElement.isValid())
@@ -496,35 +493,34 @@ WebGLContext::ValidateBufferFetching(con
 
     return true;
 }
 
 WebGLVertexAttrib0Status
 WebGLContext::WhatDoesVertexAttrib0Need()
 {
     MOZ_ASSERT(mCurrentProgram);
-    MOZ_ASSERT(mActiveProgramLinkInfo);
 
     // work around Mac OSX crash, see bug 631420
 #ifdef XP_MACOSX
     if (gl->WorkAroundDriverBugs() &&
         mBoundVertexArray->IsAttribArrayEnabled(0) &&
-        !mActiveProgramLinkInfo->HasActiveAttrib(0))
+        !mCurrentProgram->IsAttribInUse(0))
     {
         return WebGLVertexAttrib0Status::EmulatedUninitializedArray;
     }
 #endif
 
     if (MOZ_LIKELY(gl->IsGLES() ||
                    mBoundVertexArray->IsAttribArrayEnabled(0)))
     {
         return WebGLVertexAttrib0Status::Default;
     }
 
-    return mActiveProgramLinkInfo->HasActiveAttrib(0)
+    return mCurrentProgram->IsAttribInUse(0)
            ? WebGLVertexAttrib0Status::EmulatedInitializedArray
            : WebGLVertexAttrib0Status::EmulatedUninitializedArray;
 }
 
 bool
 WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount)
 {
     WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -47,18 +47,21 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Endian.h"
 #include "mozilla/fallible.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::gl;
 using namespace mozilla::gfx;
-using namespace mozilla::gl;
+
+static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum* baseType,
+                                           GLint* unitSize);
 
 const WebGLRectangleObject*
 WebGLContext::CurValidFBRectObject() const
 {
     const WebGLRectangleObject* rect = nullptr;
 
     if (mBoundFramebuffer) {
         // We don't really need to ask the driver.
@@ -101,34 +104,63 @@ WebGLContext::ActiveTexture(GLenum textu
 void
 WebGLContext::AttachShader(WebGLProgram* program, WebGLShader* shader)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("attachShader: program", program) ||
         !ValidateObject("attachShader: shader", shader))
-    {
         return;
-    }
-
-    program->AttachShader(shader);
+
+    // Per GLSL ES 2.0, we can only have one of each type of shader
+    // attached.  This renders the next test somewhat moot, but we'll
+    // 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,
                                  const nsAString& name)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("bindAttribLocation: program", prog))
         return;
 
-    prog->BindAttribLocation(location, name);
+    GLuint progname = prog->GLName();
+
+    if (!ValidateGLSLVariableName(name, "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_'.");
+
+    NS_LossyConvertUTF16toASCII cname(name);
+    nsCString mappedName;
+    if (mShaderValidation) {
+        WebGLProgram::HashMapIdentifier(cname, &mappedName);
+    } else {
+        mappedName.Assign(cname);
+    }
+
+    MakeContextCurrent();
+    gl->fBindAttribLocation(progname, location, mappedName.get());
 }
 
 void
 WebGLContext::BindFramebuffer(GLenum target, WebGLFramebuffer* wfb)
 {
     if (IsContextLost())
         return;
 
@@ -743,25 +775,24 @@ WebGLContext::DeleteShader(WebGLShader* 
 }
 
 void
 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) ||
+        // it's valid to attempt to detach a deleted shader, since it's
+        // still a shader
         !ValidateObjectAllowDeleted("detashShader: shader", shader))
-    {
         return;
-    }
-
-    program->DetachShader(shader);
+
+    if (!program->DetachShader(shader))
+        return ErrorInvalidOperation("detachShader: shader is not attached");
 }
 
 void
 WebGLContext::DepthFunc(GLenum func)
 {
     if (IsContextLost())
         return;
 
@@ -849,16 +880,60 @@ WebGLContext::FrontFace(GLenum mode)
         default:
             return ErrorInvalidEnumInfo("frontFace: mode", mode);
     }
 
     MakeContextCurrent();
     gl->fFrontFace(mode);
 }
 
+already_AddRefed<WebGLActiveInfo>
+WebGLContext::GetActiveAttrib(WebGLProgram* prog, uint32_t index)
+{
+    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;
+    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;
+
+    gl->fGetActiveAttrib(progname, index, len, &len, &attrsize, &attrtype, name);
+    if (attrsize == 0 || attrtype == 0) {
+        return nullptr;
+    }
+
+    nsCString reverseMappedName;
+    prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
+
+    nsRefPtr<WebGLActiveInfo> retActiveInfo =
+        new WebGLActiveInfo(attrsize, attrtype, reverseMappedName);
+    return retActiveInfo.forget();
+}
+
 void
 WebGLContext::GenerateMipmap(GLenum rawTarget)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateTextureTargetEnum(rawTarget, "generateMipmap"))
         return;
@@ -914,68 +989,119 @@ WebGLContext::GenerateMipmap(GLenum rawT
         gl->fGenerateMipmap(target.get());
         gl->fTexParameteri(target.get(), LOCAL_GL_TEXTURE_MIN_FILTER, tex->MinFilter().get());
     } else {
         gl->fGenerateMipmap(target.get());
     }
 }
 
 already_AddRefed<WebGLActiveInfo>
-WebGLContext::GetActiveAttrib(WebGLProgram* prog, GLuint index)
-{
-    if (IsContextLost())
-        return nullptr;
-
-    if (!ValidateObject("getActiveAttrib: program", prog))
-        return nullptr;
-
-    return prog->GetActiveAttrib(index);
-}
-
-already_AddRefed<WebGLActiveInfo>
-WebGLContext::GetActiveUniform(WebGLProgram* prog, GLuint index)
+WebGLContext::GetActiveUniform(WebGLProgram* prog, uint32_t index)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getActiveUniform: program", prog))
         return nullptr;
 
-    return prog->GetActiveUniform(index);
+    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;
+    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;
+
+    gl->fGetActiveUniform(progname, index, len, &len, &usize, &utype, name);
+    if (len == 0 || usize == 0 || utype == 0) {
+        return nullptr;
+    }
+
+    nsCString reverseMappedName;
+    prog->ReverseMapIdentifier(nsDependentCString(name), &reverseMappedName);
+
+    // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
+    // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
+    //
+    // > If the active uniform is an array, the uniform name returned in name will always
+    // > be the name of the uniform array appended with "[0]".
+    //
+    // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning
+    // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the
+    // returned name ends in [0], and if it doesn't, append that.
+    //
+    // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
+    // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
+    // we do it unconditionally.
+    if (usize > 1 && reverseMappedName.CharAt(reverseMappedName.Length()-1) != ']')
+        reverseMappedName.AppendLiteral("[0]");
+
+    nsRefPtr<WebGLActiveInfo> retActiveInfo =
+        new WebGLActiveInfo(usize, utype, reverseMappedName);
+    return retActiveInfo.forget();
 }
 
 void
 WebGLContext::GetAttachedShaders(WebGLProgram* prog,
                                  Nullable<nsTArray<nsRefPtr<WebGLShader>>>& retval)
 {
     retval.SetNull();
     if (IsContextLost())
         return;
 
+    if (!ValidateObjectAllowNull("getAttachedShaders", prog))
+        return;
+
+    MakeContextCurrent();
+
     if (!prog) {
-        ErrorInvalidValue("getAttachedShaders: Invalid program.");
-        return;
+        retval.SetNull();
+        ErrorInvalidValue("getAttachedShaders: invalid program");
+    } else if (prog->AttachedShaders().Length() == 0) {
+        retval.SetValue().TruncateLength(0);
+    } else {
+        retval.SetValue().AppendElements(prog->AttachedShaders());
     }
-
-    if (!ValidateObject("getAttachedShaders", prog))
-        return;
-
-    prog->GetAttachedShaders(&retval.SetValue());
 }
 
 GLint
 WebGLContext::GetAttribLocation(WebGLProgram* prog, const nsAString& name)
 {
     if (IsContextLost())
         return -1;
 
     if (!ValidateObject("getAttribLocation: program", prog))
         return -1;
 
-    return prog->GetAttribLocation(name);
+    if (!ValidateGLSLVariableName(name, "getAttribLocation"))
+        return -1;
+
+    NS_LossyConvertUTF16toASCII cname(name);
+    nsCString mappedName;
+    prog->MapIdentifier(cname, &mappedName);
+
+    GLuint progname = prog->GLName();
+
+    MakeContextCurrent();
+    return gl->fGetAttribLocation(progname, mappedName.get());
 }
 
 JS::Value
 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
@@ -1309,33 +1435,110 @@ JS::Value
 WebGLContext::GetProgramParameter(WebGLProgram* prog, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog))
         return JS::NullValue();
 
-    return prog->GetProgramParameter(pname);
+    GLuint progname = prog->GLName();
+
+    MakeContextCurrent();
+
+    GLint i = 0;
+
+    if (IsWebGL2()) {
+        switch (pname) {
+        case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
+        case LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
+            gl->fGetProgramiv(progname, pname, &i);
+            return JS::Int32Value(i);
+        }
+    }
+
+    switch (pname) {
+        case LOCAL_GL_ATTACHED_SHADERS:
+        case LOCAL_GL_ACTIVE_UNIFORMS:
+        case LOCAL_GL_ACTIVE_ATTRIBUTES:
+            gl->fGetProgramiv(progname, pname, &i);
+            return JS::Int32Value(i);
+
+        case LOCAL_GL_DELETE_STATUS:
+            return JS::BooleanValue(prog->IsDeleteRequested());
+
+        case LOCAL_GL_LINK_STATUS:
+            return JS::BooleanValue(prog->LinkStatus());
+
+        case LOCAL_GL_VALIDATE_STATUS:
+#ifdef XP_MACOSX
+            // See comment in ValidateProgram below.
+            if (gl->WorkAroundDriverBugs())
+                i = 1;
+            else
+                gl->fGetProgramiv(progname, pname, &i);
+#else
+            gl->fGetProgramiv(progname, pname, &i);
+#endif
+            return JS::BooleanValue(bool(i));
+
+        default:
+            ErrorInvalidEnumInfo("getProgramParameter: parameter", pname);
+    }
+
+    return JS::NullValue();
 }
 
 void
 WebGLContext::GetProgramInfoLog(WebGLProgram* prog, nsAString& retval)
 {
-    retval.SetIsVoid(true);
-
+    nsAutoCString s;
+    GetProgramInfoLog(prog, s);
+    if (s.IsVoid())
+        retval.SetIsVoid(true);
+    else
+        CopyASCIItoUTF16(s, retval);
+}
+
+void
+WebGLContext::GetProgramInfoLog(WebGLProgram* prog, nsACString& retval)
+{
     if (IsContextLost())
+    {
+        retval.SetIsVoid(true);
+        return;
+    }
+
+    if (!ValidateObject("getProgramInfoLog: program", prog)) {
+        retval.Truncate();
         return;
-
-    if (!ValidateObject("getProgramInfoLog: program", prog))
+    }
+
+    GLuint progname = prog->GLName();
+
+    MakeContextCurrent();
+
+    GLint k = -1;
+    gl->fGetProgramiv(progname, LOCAL_GL_INFO_LOG_LENGTH, &k);
+    if (k == -1) {
+        // If GetProgramiv doesn't modify |k|,
+        // it's because there was a GL error.
+        // GetProgramInfoLog should return null on error. (Bug 746740)
+        retval.SetIsVoid(true);
         return;
-
-    prog->GetProgramInfoLog(&retval);
-
-    retval.SetIsVoid(false);
+    }
+
+    if (k == 0) {
+        retval.Truncate();
+        return;
+    }
+
+    retval.SetCapacity(k);
+    gl->fGetProgramInfoLog(progname, k, &k, (char*) retval.BeginWriting());
+    retval.SetLength(k);
 }
 
 // here we have to support all pnames with both int and float params.
 // See this discussion:
 //  https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
 void WebGLContext::TexParameter_base(GLenum rawTarget, GLenum pname,
                                      GLint* intParamPtr,
                                      GLfloat* floatParamPtr)
@@ -1533,44 +1736,181 @@ WebGLContext::GetTexParameterInternal(co
         default:
             ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
     }
 
     return JS::NullValue();
 }
 
 JS::Value
-WebGLContext::GetUniform(JSContext* js, WebGLProgram* prog,
-                         WebGLUniformLocation* loc)
+WebGLContext::GetUniform(JSContext* cx, WebGLProgram* prog,
+                         WebGLUniformLocation* location)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (!ValidateObject("getUniform: `program`", prog))
+    if (!ValidateObject("getUniform: program", prog))
+        return JS::NullValue();
+
+    if (!ValidateObject("getUniform: location", location))
         return JS::NullValue();
 
-    if (!ValidateObject("getUniform: `location`", loc))
+    if (location->Program() != prog) {
+        ErrorInvalidValue("getUniform: this uniform location corresponds to another program");
+        return JS::NullValue();
+    }
+
+    if (location->ProgramGeneration() != prog->Generation()) {
+        ErrorInvalidOperation("getUniform: this uniform location is obsolete since the program has been relinked");
         return JS::NullValue();
-
-    if (!loc->ValidateForProgram(prog, this, "getUniform"))
+    }
+
+    GLuint progname = prog->GLName();
+
+    MakeContextCurrent();
+
+    GLint uniforms = 0;
+    GLint uniformNameMaxLength = 0;
+    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORMS, &uniforms);
+    gl->fGetProgramiv(progname, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformNameMaxLength);
+
+    // we now need the type info to switch between fGetUniformfv and fGetUniformiv
+    // the only way to get that is to iterate through all active uniforms by index until
+    // one matches the given uniform location.
+    GLenum uniformType = 0;
+    nsAutoArrayPtr<GLchar> uniformName(new GLchar[uniformNameMaxLength]);
+    // this buffer has 16 more bytes to be able to store [index] at the end.
+    nsAutoArrayPtr<GLchar> uniformNameBracketIndex(new GLchar[uniformNameMaxLength + 16]);
+
+    GLint index;
+    for (index = 0; index < uniforms; ++index) {
+        GLsizei length;
+        GLint size;
+        gl->fGetActiveUniform(progname, index, uniformNameMaxLength, &length,
+                              &size, &uniformType, uniformName);
+        if (gl->fGetUniformLocation(progname, uniformName) == location->Location())
+            break;
+
+        // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size'
+        // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above,
+        // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]".
+        if (size > 1) {
+            bool found_it = false;
+            if (uniformName[length - 1] == ']') { // if uniformName ends in [0]
+                // remove the [0] at the end
+                length -= 3;
+                uniformName[length] = 0;
+            }
+            for (GLint arrayIndex = 1; arrayIndex < size; arrayIndex++) {
+                sprintf(uniformNameBracketIndex.get(), "%s[%d]", uniformName.get(), arrayIndex);
+                if (gl->fGetUniformLocation(progname, uniformNameBracketIndex) == location->Location()) {
+                    found_it = true;
+                    break;
+                }
+            }
+            if (found_it) break;
+        }
+    }
+
+    if (index == uniforms) {
+        GenerateWarning("getUniform: internal error: hit an OpenGL driver bug");
         return JS::NullValue();
-
-    return loc->GetUniform(js, this);
+    }
+
+    GLenum baseType;
+    GLint unitSize;
+    if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize)) {
+        GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType);
+        return JS::NullValue();
+    }
+
+    // this should never happen
+    if (unitSize > 16) {
+        GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize);
+        return JS::NullValue();
+    }
+
+    if (baseType == LOCAL_GL_FLOAT) {
+        GLfloat fv[16] = { GLfloat(0) };
+        gl->fGetUniformfv(progname, location->Location(), fv);
+        if (unitSize == 1) {
+            return JS::DoubleValue(fv[0]);
+        } else {
+            JSObject* obj = Float32Array::Create(cx, this, unitSize, fv);
+            if (!obj) {
+                ErrorOutOfMemory("getUniform: out of memory");
+                return JS::NullValue();
+            }
+            return JS::ObjectOrNullValue(obj);
+        }
+    } else if (baseType == LOCAL_GL_INT) {
+        GLint iv[16] = { 0 };
+        gl->fGetUniformiv(progname, location->Location(), iv);
+        if (unitSize == 1) {
+            return JS::Int32Value(iv[0]);
+        } else {
+            JSObject* obj = Int32Array::Create(cx, this, unitSize, iv);
+            if (!obj) {
+                ErrorOutOfMemory("getUniform: out of memory");
+                return JS::NullValue();
+            }
+            return JS::ObjectOrNullValue(obj);
+        }
+    } else if (baseType == LOCAL_GL_BOOL) {
+        GLint iv[16] = { 0 };
+        gl->fGetUniformiv(progname, location->Location(), iv);
+        if (unitSize == 1) {
+            return JS::BooleanValue(iv[0] ? true : false);
+        } else {
+            bool uv[16];
+            for (int k = 0; k < unitSize; k++)
+                uv[k] = iv[k];
+            JS::Rooted<JS::Value> val(cx);
+            // Be careful: we don't want to convert all of |uv|!
+            if (!ToJSValue(cx, uv, unitSize, &val)) {
+                ErrorOutOfMemory("getUniform: out of memory");
+                return JS::NullValue();
+            }
+            return val;
+        }
+    }
+
+    // Else preserving behavior, but I'm not sure this is correct per spec
+    return JS::UndefinedValue();
 }
 
 already_AddRefed<WebGLUniformLocation>
 WebGLContext::GetUniformLocation(WebGLProgram* prog, const nsAString& name)
 {
     if (IsContextLost())
         return nullptr;
 
     if (!ValidateObject("getUniformLocation: program", prog))
         return nullptr;
 
-    return prog->GetUniformLocation(name);
+    if (!ValidateGLSLVariableName(name, "getUniformLocation"))
+        return nullptr;
+
+    NS_LossyConvertUTF16toASCII cname(name);
+    nsCString mappedName;
+    prog->MapIdentifier(cname, &mappedName);
+
+    GLuint progname = prog->GLName();
+    MakeContextCurrent();
+    GLint intlocation = gl->fGetUniformLocation(progname, mappedName.get());
+
+    nsRefPtr<WebGLUniformLocation> loc;
+    if (intlocation >= 0) {
+        WebGLUniformInfo info = prog->GetUniformInfoForMappedIdentifier(mappedName);
+        loc = new WebGLUniformLocation(this,
+                                       prog,
+                                       intlocation,
+                                       info);
+    }
+    return loc.forget();
 }
 
 void
 WebGLContext::Hint(GLenum target, GLenum mode)
 {
     if (IsContextLost())
         return;
 
@@ -1640,37 +1980,175 @@ WebGLContext::IsTexture(WebGLTexture* te
     if (IsContextLost())
         return false;
 
     return ValidateObjectAllowDeleted("isTexture", tex) &&
         !tex->IsDeleted() &&
         tex->HasEverBeenBound();
 }
 
+// Try to bind an attribute that is an array to location 0:
+bool
+WebGLContext::BindArrayAttribToLocation0(WebGLProgram* program)
+{
+    if (mBoundVertexArray->IsAttribArrayEnabled(0)) {
+        return false;
+    }
+
+    GLint leastArrayLocation = -1;
+
+    std::map<GLint, nsCString>::iterator itr;
+    for (itr = program->mActiveAttribMap.begin();
+         itr != program->mActiveAttribMap.end();
+         itr++) {
+        int32_t index = itr->first;
+        if (mBoundVertexArray->IsAttribArrayEnabled(index) &&
+            index < leastArrayLocation)
+        {
+            leastArrayLocation = index;
+        }
+    }
+
+    if (leastArrayLocation > 0) {
+        nsCString& attrName = program->mActiveAttribMap.find(leastArrayLocation)->second;
+        const char* attrNameCStr = attrName.get();
+        gl->fBindAttribLocation(program->GLName(), 0, attrNameCStr);
+        return true;
+    }
+    return false;
+}
+
+static void
+LinkAndUpdateProgram(GLContext* gl, WebGLProgram* prog)
+{
+    GLuint name = prog->GLName();
+    gl->fLinkProgram(name);
+
+    prog->SetLinkStatus(false);
+
+    GLint ok = 0;
+    gl->fGetProgramiv(name, LOCAL_GL_LINK_STATUS, &ok);
+    if (!ok)
+        return;
+
+    if (!prog->UpdateInfo())
+        return;
+
+    prog->SetLinkStatus(true);
+}
+
 void
-WebGLContext::LinkProgram(WebGLProgram* prog)
+WebGLContext::LinkProgram(WebGLProgram* program)
 {
     if (IsContextLost())
         return;
 
-    if (!ValidateObject("linkProgram", prog))
+    if (!ValidateObject("linkProgram", program))
+        return;
+
+    InvalidateBufferFetching(); // we do it early in this function
+    // as some of the validation below changes program state
+
+    if (!program->NextGeneration()) {
+        // XXX throw?
+        return;
+    }
+
+    if (!program->HasBothShaderTypesAttached()) {
+        GenerateWarning("linkProgram: this program doesn't have both a vertex"
+                        " shader and a fragment shader");
+        program->SetLinkStatus(false);
+        return;
+    }
+
+    if (program->HasBadShaderAttached()) {
+        GenerateWarning("linkProgram: The program has bad shaders attached.");
+        program->SetLinkStatus(false);
+        return;
+    }
+
+    // bug 777028
+    // Mesa can't handle more than 16 samplers per program, counting each array entry.
+    if (gl->WorkAroundDriverBugs() &&
+        mIsMesa &&
+        program->UpperBoundNumSamplerUniforms() > 16)
+    {
+        GenerateWarning("Programs with more than 16 samplers are disallowed on"
+                        " Mesa drivers to avoid a Mesa crasher.");
+        program->SetLinkStatus(false);
         return;
-
-    prog->LinkProgram();
-
-    if (prog->IsLinked()) {
-        mActiveProgramLinkInfo = prog->LinkInfo();
-
-        if (gl->WorkAroundDriverBugs() &&
-            gl->Vendor() == gl::GLVendor::NVIDIA)
-        {
-            if (mCurrentProgram == prog)
-                gl->fUseProgram(prog->mGLName);
+    }
+
+    MakeContextCurrent();
+    LinkAndUpdateProgram(gl, program);
+
+    if (program->LinkStatus()) {
+        if (BindArrayAttribToLocation0(program)) {
+            GenerateWarning("linkProgram: Relinking program to make attrib0 an"
+                            " array.");
+            LinkAndUpdateProgram(gl, program);
         }
     }
+
+    if (!program->LinkStatus()) {
+        if (ShouldGenerateWarnings()) {
+            // report shader/program infoLogs as warnings.
+            // note that shader compilation errors can be deferred to linkProgram,
+            // which is why we can't do anything in compileShader. In practice we could
+            // report in compileShader the translation errors generated by ANGLE,
+            // but it seems saner to keep a single way of obtaining shader infologs.
+
+            nsAutoCString log;
+
+            bool alreadyReportedShaderInfoLog = false;
+
+            for (size_t i = 0; i < program->AttachedShaders().Length(); i++) {
+
+                WebGLShader* shader = program->AttachedShaders()[i];
+
+                if (shader->CompileStatus())
+                    continue;
+
+                const char* shaderTypeName = nullptr;
+                if (shader->ShaderType() == LOCAL_GL_VERTEX_SHADER) {
+                    shaderTypeName = "vertex";
+                } else if (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) {
+                    shaderTypeName = "fragment";
+                } else {
+                    // should have been validated earlier
+                    MOZ_ASSERT(false);
+                    shaderTypeName = "<unknown>";
+                }
+
+                GetShaderInfoLog(shader, log);
+
+                GenerateWarning("linkProgram: a %s shader used in this program failed to "
+                                "compile, with this log:\n%s\n",
+                                shaderTypeName,
+                                log.get());
+                alreadyReportedShaderInfoLog = true;
+            }
+
+            if (!alreadyReportedShaderInfoLog) {
+                GetProgramInfoLog(program, log);
+                if (!log.IsEmpty()) {
+                    GenerateWarning("linkProgram failed, with this log:\n%s\n",
+                                    log.get());
+                }
+            }
+        }
+        return;
+    }
+
+    if (gl->WorkAroundDriverBugs() &&
+        gl->Vendor() == gl::GLVendor::NVIDIA)
+    {
+        if (program == mCurrentProgram)
+            gl->fUseProgram(program->GLName());
+    }
 }
 
 void
 WebGLContext::PixelStorei(GLenum pname, GLint param)
 {
     if (IsContextLost())
         return;
 
@@ -2299,17 +2777,17 @@ WebGLContext::SurfaceFromElementResultTo
 void
 WebGLContext::Uniform1i(WebGLUniformLocation* loc, GLint a1)
 {
     GLuint rawLoc;
     if (!ValidateUniformSetter(loc, 1, LOCAL_GL_INT, "uniform1i", &rawLoc))
         return;
 
     // Only uniform1i can take sampler settings.
-    if (!loc->ValidateSamplerSetter(a1, this, "uniform1i"))
+    if (!ValidateSamplerUniformSetter("Uniform1i", loc, a1))
         return;
 
     MakeContextCurrent();
     gl->fUniform1i(rawLoc, a1);
 }
 
 void
 WebGLContext::Uniform2i(WebGLUniformLocation* loc, GLint a1, GLint a2)
@@ -2402,17 +2880,17 @@ WebGLContext::Uniform1iv_base(WebGLUnifo
     GLsizei numElementsToUpload;
     if (!ValidateUniformArraySetter(loc, 1, LOCAL_GL_INT, arrayLength,
                                     "uniform1iv", &rawLoc,
                                     &numElementsToUpload))
     {
         return;
     }
 
-    if (!loc->ValidateSamplerSetter(data[0], this, "uniform1iv"))
+    if (!ValidateSamplerUniformSetter("uniform1iv", loc, data[0]))
         return;
 
     MakeContextCurrent();
     gl->fUniform1iv(rawLoc, numElementsToUpload, data);
 }
 
 void
 WebGLContext::Uniform2iv_base(WebGLUniformLocation* loc, size_t arrayLength,
@@ -2422,18 +2900,18 @@ WebGLContext::Uniform2iv_base(WebGLUnifo
     GLsizei numElementsToUpload;
     if (!ValidateUniformArraySetter(loc, 2, LOCAL_GL_INT, arrayLength,
                                     "uniform2iv", &rawLoc,
                                     &numElementsToUpload))
     {
         return;
     }
 
-    if (!loc->ValidateSamplerSetter(data[0], this, "uniform2iv") ||
-        !loc->ValidateSamplerSetter(data[1], this, "uniform2iv"))
+    if (!ValidateSamplerUniformSetter("uniform2iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform2iv", loc, data[1]))
     {
         return;
     }
 
     MakeContextCurrent();
     gl->fUniform2iv(rawLoc, numElementsToUpload, data);
 }
 
@@ -2445,19 +2923,19 @@ WebGLContext::Uniform3iv_base(WebGLUnifo
     GLsizei numElementsToUpload;
     if (!ValidateUniformArraySetter(loc, 3, LOCAL_GL_INT, arrayLength,
                                     "uniform3iv", &rawLoc,
                                     &numElementsToUpload))
     {
         return;
     }
 
-    if (!loc->ValidateSamplerSetter(data[0], this, "uniform3iv") ||
-        !loc->ValidateSamplerSetter(data[1], this, "uniform3iv") ||
-        !loc->ValidateSamplerSetter(data[2], this, "uniform3iv"))
+    if (!ValidateSamplerUniformSetter("uniform3iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform3iv", loc, data[1]) ||
+        !ValidateSamplerUniformSetter("uniform3iv", loc, data[2]))
     {
         return;
     }
 
     MakeContextCurrent();
     gl->fUniform3iv(rawLoc, numElementsToUpload, data);
 }
 
@@ -2469,20 +2947,20 @@ WebGLContext::Uniform4iv_base(WebGLUnifo
     GLsizei numElementsToUpload;
     if (!ValidateUniformArraySetter(loc, 4, LOCAL_GL_INT, arrayLength,
                                     "uniform4iv", &rawLoc,
                                     &numElementsToUpload))
     {
         return;
     }
 
-    if (!loc->ValidateSamplerSetter(data[0], this, "uniform4iv") ||
-        !loc->ValidateSamplerSetter(data[1], this, "uniform4iv") ||
-        !loc->ValidateSamplerSetter(data[2], this, "uniform4iv") ||
-        !loc->ValidateSamplerSetter(data[3], this, "uniform4iv"))
+    if (!ValidateSamplerUniformSetter("uniform4iv", loc, data[0]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[1]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[2]) ||
+        !ValidateSamplerUniformSetter("uniform4iv", loc, data[3]))
     {
         return;
     }
 
     MakeContextCurrent();
     gl->fUniform4iv(rawLoc, numElementsToUpload, data);
 }
 
@@ -2611,41 +3089,54 @@ WebGLContext::UniformMatrix4fv_base(WebG
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 WebGLContext::UseProgram(WebGLProgram* prog)
 {
     if (IsContextLost())
         return;
 
-    if (!prog) {
-        mCurrentProgram = nullptr;
-        mActiveProgramLinkInfo = nullptr;
+    if (!ValidateObjectAllowNull("useProgram", prog))
         return;
-    }
-
-    if (!ValidateObject("useProgram", prog))
-        return;
-
-    if (prog->UseProgram()) {
-        mCurrentProgram = prog;
-        mActiveProgramLinkInfo = mCurrentProgram->LinkInfo();
-    }
+
+    MakeContextCurrent();
+
+    InvalidateBufferFetching();
+
+    GLuint progname = prog ? prog->GLName() : 0;
+
+    if (prog && !prog->LinkStatus())
+        return ErrorInvalidOperation("useProgram: program was not linked successfully");
+
+    gl->fUseProgram(progname);
+
+    mCurrentProgram = prog;
 }
 
 void
 WebGLContext::ValidateProgram(WebGLProgram* prog)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("validateProgram", prog))
         return;
 
-    prog->ValidateProgram();
+    MakeContextCurrent();
+
+#ifdef XP_MACOSX
+    // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
+    if (gl->WorkAroundDriverBugs()) {
+        GenerateWarning("validateProgram: implemented as a no-operation on Mac to work around crashes");
+        return;
+    }
+#endif
+
+    GLuint progname = prog->GLName();
+    gl->fValidateProgram(progname);
 }
 
 already_AddRefed<WebGLFramebuffer>
 WebGLContext::CreateFramebuffer()
 {
     if (IsContextLost())
         return nullptr;
 
@@ -2688,17 +3179,315 @@ void
 WebGLContext::CompileShader(WebGLShader* shader)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("compileShader", shader))
         return;
 
-    shader->CompileShader();
+    GLuint shadername = shader->GLName();
+
+    shader->SetCompileStatus(false);
+
+    // nothing to do if the validator is disabled
+    if (!mShaderValidation)
+        return;
+
+    // nothing to do if translation was already done
+    if (!shader->NeedsTranslation())
+        return;
+
+    MakeContextCurrent();
+
+    ShShaderOutput targetShaderSourceLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT;
+
+    ShHandle compiler = 0;
+    ShBuiltInResources resources;
+
+    memset(&resources, 0, sizeof(ShBuiltInResources));
+
+    ShInitBuiltInResources(&resources);
+
+    resources.MaxVertexAttribs = mGLMaxVertexAttribs;
+    resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
+    resources.MaxVaryingVectors = mGLMaxVaryingVectors;
+    resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
+    resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
+    resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
+    resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
+    resources.MaxDrawBuffers = mGLMaxDrawBuffers;
+
+    if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
+        resources.EXT_frag_depth = 1;
+
+    if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
+        resources.OES_standard_derivatives = 1;
+
+    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
+        resources.EXT_draw_buffers = 1;
+
+    if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
+        resources.EXT_shader_texture_lod = 1;
+
+    // Tell ANGLE to allow highp in frag shaders. (unless disabled)
+    // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
+    resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
+
+    resources.HashFunction = WebGLProgram::IdentifierHashFunction;
+
+    if (gl->WorkAroundDriverBugs()) {
+#ifdef XP_MACOSX
+        if (gl->Vendor() == gl::GLVendor::NVIDIA) {
+            // Work around bug 890432
+            resources.MaxExpressionComplexity = 1000;
+        }
+#endif
+    }
+
+    // We're storing an actual instance of StripComments because, if we don't, the
+    // cleanSource nsAString instance will be destroyed before the reference is
+    // actually used.
+    StripComments stripComments(shader->Source());
+    const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
+    if (!ValidateGLSLString(cleanSource, "compileShader"))
+        return;
+
+    // shaderSource() already checks that the source stripped of comments is in the
+    // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
+    NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
+
+    if (gl->WorkAroundDriverBugs()) {
+        const uint32_t maxSourceLength = 0x3ffff;
+        if (sourceCString.Length() > maxSourceLength)
+            return ErrorInvalidValue("compileShader: source has more than %d characters",
+                                     maxSourceLength);
+    }
+
+    const char* s = sourceCString.get();
+
+#define WEBGL2_BYPASS_ANGLE
+#ifdef WEBGL2_BYPASS_ANGLE
+    /*
+     * The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
+     * is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
+     *
+     * To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
+     *
+     * To bypass angle, the context must be a WebGL 2 and the shader must have the
+     * following line at the very top :
+     *      #version proto-200
+     *
+     * In this case, byPassANGLE == true and here is what we do :
+     *  We create two shader source code:
+     *    - one for the driver, that enable GL_EXT_gpu_shader4
+     *    - one for the angle compilor, to get informations about vertex attributes
+     *      and uniforms
+     */
+    static const char* bypassPrefixSearch = "#version proto-200";
+    static const char* bypassANGLEPrefix[2] = {"precision mediump float;\n"
+                                               "#define gl_VertexID 0\n"
+                                               "#define gl_InstanceID 0\n",
+
+                                               "precision mediump float;\n"
+                                               "#extension GL_EXT_draw_buffers : enable\n"
+                                               "#define gl_PrimitiveID 0\n"};
+
+    const bool bypassANGLE = IsWebGL2() && (strstr(s, bypassPrefixSearch) != 0);
+
+    const char* angleShaderCode = s;
+    nsTArray<char> bypassANGLEShaderCode;
+    nsTArray<char> bypassDriverShaderCode;
+
+    if (bypassANGLE) {
+        const int bypassStage = (shader->ShaderType() == LOCAL_GL_FRAGMENT_SHADER) ? 1 : 0;
+        const char* originalShader = strstr(s, bypassPrefixSearch) + strlen(bypassPrefixSearch);
+        int originalShaderSize = strlen(s) - (originalShader - s);
+        int bypassShaderCodeSize = originalShaderSize + 4096 + 1;
+
+        bypassANGLEShaderCode.SetLength(bypassShaderCodeSize);
+        strcpy(bypassANGLEShaderCode.Elements(), bypassANGLEPrefix[bypassStage]);
+        strcat(bypassANGLEShaderCode.Elements(), originalShader);
+
+        bypassDriverShaderCode.SetLength(bypassShaderCodeSize);
+        strcpy(bypassDriverShaderCode.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
+        strcat(bypassDriverShaderCode.Elements(), originalShader);
+
+        angleShaderCode = bypassANGLEShaderCode.Elements();
+    }
+#endif
+
+    compiler = ShConstructCompiler(shader->ShaderType(),
+                                   SH_WEBGL_SPEC,
+                                   targetShaderSourceLanguage,
+                                   &resources);
+
+    int compileOptions = SH_VARIABLES |
+                         SH_ENFORCE_PACKING_RESTRICTIONS |
+                         SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
+                         SH_OBJECT_CODE |
+                         SH_LIMIT_CALL_STACK_DEPTH;
+
+    if (resources.MaxExpressionComplexity > 0) {
+        compileOptions |= SH_LIMIT_EXPRESSION_COMPLEXITY;
+    }
+
+#ifndef XP_MACOSX
+    // We want to do this everywhere, but to do this on Mac, we need
+    // to do it only on Mac OSX > 10.6 as this causes the shader
+    // compiler in 10.6 to crash
+    compileOptions |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
+#endif
+
+#ifdef XP_MACOSX
+    if (gl->WorkAroundDriverBugs()) {
+        // Work around bug 665578 and bug 769810
+        if (gl->Vendor() == gl::GLVendor::ATI) {
+            compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+        }
+
+        // Work around bug 735560
+        if (gl->Vendor() == gl::GLVendor::Intel) {
+            compileOptions |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+        }
+
+        // Work around bug 636926
+        if (gl->Vendor() == gl::GLVendor::NVIDIA) {
+            compileOptions |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
+        }
+
+        // Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
+        // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
+        compileOptions |= SH_UNFOLD_SHORT_CIRCUIT;
+    }
+#endif
+
+#ifdef WEBGL2_BYPASS_ANGLE
+    if (!ShCompile(compiler, &angleShaderCode, 1, compileOptions)) {
+#else
+    if (!ShCompile(compiler, &s, 1, compileOptions)) {
+#endif
+        size_t lenWithNull = 0;
+        ShGetInfo(compiler, SH_INFO_LOG_LENGTH, &lenWithNull);
+
+        if (!lenWithNull) {
+            // Error in ShGetInfo.
+            shader->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
+        } else {
+            size_t len = lenWithNull - 1;
+
+            nsAutoCString info;
+            if (len) {
+                // Don't allocate or try to write to zero length string
+                info.SetLength(len); // Allocates len+1, for the null-term.
+                ShGetInfoLog(compiler, info.BeginWriting());
+            }
+            shader->SetTranslationFailure(info);
+        }
+        ShDestruct(compiler);
+        shader->SetCompileStatus(false);
+        return;
+    }
+
+    size_t num_attributes = 0;
+    ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTES, &num_attributes);
+    size_t num_uniforms = 0;
+    ShGetInfo(compiler, SH_ACTIVE_UNIFORMS, &num_uniforms);
+    size_t attrib_max_length = 0;
+    ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attrib_max_length);
+    size_t uniform_max_length = 0;
+    ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &uniform_max_length);
+    size_t mapped_max_length = 0;
+    ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_max_length);
+
+    shader->mAttribMaxNameLength = attrib_max_length;
+
+    shader->mAttributes.Clear();
+    shader->mUniforms.Clear();
+    shader->mUniformInfos.Clear();
+
+    nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
+    nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
+    nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
+
+    for (size_t i = 0; i < num_uniforms; i++) {
+        size_t length;
+        int size;
+        sh::GLenum type;
+        ShPrecisionType precision;
+        int staticUse;
+        ShGetVariableInfo(compiler, SH_ACTIVE_UNIFORMS, (int)i,
+                          &length, &size, &type,
+                          &precision, &staticUse,
+                          uniform_name,
+                          mapped_name);
+
+        shader->mUniforms.AppendElement(WebGLMappedIdentifier(
+                                            nsDependentCString(uniform_name),
+                                            nsDependentCString(mapped_name)));
+
+        // we need uniform info to validate uniform setter calls
+        char mappedNameLength = strlen(mapped_name);
+        char mappedNameLastChar = mappedNameLength > 1
+                                  ? mapped_name[mappedNameLength - 1]
+                                  : 0;
+        shader->mUniformInfos.AppendElement(WebGLUniformInfo(
+                                                size,
+                                                mappedNameLastChar == ']',
+                                                type));
+    }
+
+    for (size_t i = 0; i < num_attributes; i++) {
+        size_t length;
+        int size;
+        sh::GLenum type;
+        ShPrecisionType precision;
+        int staticUse;
+        ShGetVariableInfo(compiler, SH_ACTIVE_ATTRIBUTES, (int)i,
+                          &length, &size, &type,
+                          &precision, &staticUse,
+                          attribute_name,
+                          mapped_name);
+        shader->mAttributes.AppendElement(WebGLMappedIdentifier(
+                                              nsDependentCString(attribute_name),
+                                              nsDependentCString(mapped_name)));
+    }
+
+    size_t lenWithNull = 0;
+    ShGetInfo(compiler, SH_OBJECT_CODE_LENGTH, &lenWithNull);
+    MOZ_ASSERT(lenWithNull >= 1);
+    size_t len = lenWithNull - 1;
+
+    nsAutoCString translatedSrc;
+    translatedSrc.SetLength(len); // Allocates len+1, for the null-term.
+    ShGetObjectCode(compiler, translatedSrc.BeginWriting());
+
+    CopyASCIItoUTF16(translatedSrc, shader->mTranslatedSource);
+
+    const char* ts = translatedSrc.get();
+
+#ifdef WEBGL2_BYPASS_ANGLE
+    if (bypassANGLE) {
+        const char* driverShaderCode = bypassDriverShaderCode.Elements();
+        gl->fShaderSource(shadername, 1, (const GLchar**) &driverShaderCode, nullptr);
+    } else {
+        gl->fShaderSource(shadername, 1, &ts, nullptr);
+    }
+#else
+    gl->fShaderSource(shadername, 1, &ts, nullptr);
+#endif
+
+    shader->SetTranslationSuccess();
+
+    ShDestruct(compiler);
+
+    gl->fCompileShader(shadername);
+    GLint ok;
+    gl->fGetShaderiv(shadername, LOCAL_GL_COMPILE_STATUS, &ok);
+    shader->SetCompileStatus(ok);
 }
 
 void
 WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
                                    GLint level,
                                    GLenum internalformat,
                                    GLsizei width, GLsizei height, GLint border,
                                    const ArrayBufferView& view)
@@ -2820,33 +3609,91 @@ JS::Value
 WebGLContext::GetShaderParameter(WebGLShader* shader, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     if (!ValidateObject("getShaderParameter: shader", shader))
         return JS::NullValue();
 
-    return shader->GetShaderParameter(pname);
+    GLuint shadername = shader->GLName();
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_SHADER_TYPE:
+        {
+            GLint i = 0;
+            gl->fGetShaderiv(shadername, pname, &i);
+            return JS::NumberValue(uint32_t(i));
+        }
+            break;
+        case LOCAL_GL_DELETE_STATUS:
+            return JS::BooleanValue(shader->IsDeleteRequested());
+            break;
+        case LOCAL_GL_COMPILE_STATUS:
+        {
+            GLint i = 0;
+            gl->fGetShaderiv(shadername, pname, &i);
+            return JS::BooleanValue(bool(i));
+        }
+            break;
+        default:
+            ErrorInvalidEnumInfo("getShaderParameter: parameter", pname);
+    }
+
+    return JS::NullValue();
 }
 
 void
 WebGLContext::GetShaderInfoLog(WebGLShader* shader, nsAString& retval)
 {
-    retval.SetIsVoid(true);
-
+    nsAutoCString s;
+    GetShaderInfoLog(shader, s);
+    if (s.IsVoid())
+        retval.SetIsVoid(true);
+    else
+        CopyASCIItoUTF16(s, retval);
+}
+
+void
+WebGLContext::GetShaderInfoLog(WebGLShader* shader, nsACString& retval)
+{
     if (IsContextLost())
+    {
+        retval.SetIsVoid(true);
         return;
+    }
 
     if (!ValidateObject("getShaderInfoLog: shader", shader))
         return;
 
-    shader->GetShaderInfoLog(&retval);
-
-    retval.SetIsVoid(false);
+    retval = shader->TranslationLog();
+    if (!retval.IsVoid()) {
+        return;
+    }
+
+    MakeContextCurrent();
+
+    GLuint shadername = shader->GLName();
+    GLint k = -1;
+    gl->fGetShaderiv(shadername, LOCAL_GL_INFO_LOG_LENGTH, &k);
+    if (k == -1) {
+        // XXX GL Error? should never happen.
+        return;
+    }
+
+    if (k == 0) {
+        retval.Truncate();
+        return;
+    }
+
+    retval.SetCapacity(k);
+    gl->fGetShaderInfoLog(shadername, k, &k, (char*) retval.BeginWriting());
+    retval.SetLength(k);
 }
 
 already_AddRefed<WebGLShaderPrecisionFormat>
 WebGLContext::GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype)
 {
     if (IsContextLost())
         return nullptr;
 
@@ -2890,51 +3737,61 @@ WebGLContext::GetShaderPrecisionFormat(G
     nsRefPtr<WebGLShaderPrecisionFormat> retShaderPrecisionFormat
         = new WebGLShaderPrecisionFormat(this, range[0], range[1], precision);
     return retShaderPrecisionFormat.forget();
 }
 
 void
 WebGLContext::GetShaderSource(WebGLShader* shader, nsAString& retval)
 {
-    retval.SetIsVoid(true);
-
-    if (IsContextLost())
+    if (IsContextLost()) {
+        retval.SetIsVoid(true);
         return;
+    }
 
     if (!ValidateObject("getShaderSource: shader", shader))
         return;
 
-    shader->GetShaderSource(&retval);
+    retval.Assign(shader->Source());
 }
 
 void
 WebGLContext::ShaderSource(WebGLShader* shader, const nsAString& source)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("shaderSource: shader", shader))
         return;
 
-    shader->ShaderSource(source);
+    // We're storing an actual instance of StripComments because, if we don't, the
+    // cleanSource nsAString instance will be destroyed before the reference is
+    // actually used.
+    StripComments stripComments(source);
+    const nsAString& cleanSource = Substring(stripComments.result().Elements(), stripComments.length());
+    if (!ValidateGLSLString(cleanSource, "compileShader"))
+        return;
+
+    shader->SetSource(source);
+
+    shader->SetNeedsTranslation();
 }
 
 void
 WebGLContext::GetShaderTranslatedSource(WebGLShader* shader, nsAString& retval)
 {
-    retval.SetIsVoid(true);
-
-    if (IsContextLost())
+    if (IsContextLost()) {
+        retval.SetIsVoid(true);
         return;
+    }
 
     if (!ValidateObject("getShaderTranslatedSource: shader", shader))
         return;
 
-    shader->GetShaderTranslatedSource(&retval);
+    retval.Assign(shader->TranslatedSource());
 }
 
 GLenum WebGLContext::CheckedTexImage2D(TexImageTarget texImageTarget,
                                        GLint level,
                                        TexInternalFormat internalformat,
                                        GLsizei width,
                                        GLsizei height,
                                        GLint border,
@@ -3402,16 +4259,87 @@ WebGLContext::RestoreContext()
     // restoreContext().
 
     if (!mAllowContextRestore)
         return ErrorInvalidOperation("restoreContext: Context cannot be restored.");
 
     ForceRestoreContext();
 }
 
+bool
+BaseTypeAndSizeFromUniformType(GLenum uType, GLenum* baseType, GLint* unitSize)
+{
+    switch (uType) {
+        case LOCAL_GL_INT:
+        case LOCAL_GL_INT_VEC2:
+        case LOCAL_GL_INT_VEC3:
+        case LOCAL_GL_INT_VEC4:
+        case LOCAL_GL_SAMPLER_2D:
+        case LOCAL_GL_SAMPLER_CUBE:
+            *baseType = LOCAL_GL_INT;
+            break;
+        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:
+            *baseType = LOCAL_GL_FLOAT;
+            break;
+        case LOCAL_GL_BOOL:
+        case LOCAL_GL_BOOL_VEC2:
+        case LOCAL_GL_BOOL_VEC3:
+        case LOCAL_GL_BOOL_VEC4:
+            *baseType = LOCAL_GL_BOOL; // pretend these are int
+            break;
+        default:
+            return false;
+    }
+
+    switch (uType) {
+        case LOCAL_GL_INT:
+        case LOCAL_GL_FLOAT:
+        case LOCAL_GL_BOOL:
+        case LOCAL_GL_SAMPLER_2D:
+        case LOCAL_GL_SAMPLER_CUBE:
+            *unitSize = 1;
+            break;
+        case LOCAL_GL_INT_VEC2:
+        case LOCAL_GL_FLOAT_VEC2:
+        case LOCAL_GL_BOOL_VEC2:
+            *unitSize = 2;
+            break;
+        case LOCAL_GL_INT_VEC3:
+        case LOCAL_GL_FLOAT_VEC3:
+        case LOCAL_GL_BOOL_VEC3:
+            *unitSize = 3;
+            break;
+        case LOCAL_GL_INT_VEC4:
+        case LOCAL_GL_FLOAT_VEC4:
+        case LOCAL_GL_BOOL_VEC4:
+            *unitSize = 4;
+            break;
+        case LOCAL_GL_FLOAT_MAT2:
+            *unitSize = 4;
+            break;
+        case LOCAL_GL_FLOAT_MAT3:
+            *unitSize = 9;
+            break;
+        case LOCAL_GL_FLOAT_MAT4:
+            *unitSize = 16;
+            break;
+        default:
+            return false;
+    }
+
+    return true;
+}
+
+
 WebGLTexelFormat
 mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveInternalFormat)
 {
     switch (effectiveInternalFormat.get()) {
         case LOCAL_GL_RGBA8:                  return WebGLTexelFormat::RGBA8;
         case LOCAL_GL_SRGB8_ALPHA8:           return WebGLTexelFormat::RGBA8;
         case LOCAL_GL_RGB8:                   return WebGLTexelFormat::RGB8;
         case LOCAL_GL_SRGB8:                  return WebGLTexelFormat::RGB8;
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -1026,17 +1026,17 @@ WebGLContext::AssertCachedBindings()
         GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
         AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
     }
 
     // Bound object state
     GLuint bound = mBoundFramebuffer ? mBoundFramebuffer->GLName() : 0;
     AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
 
-    bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
+    bound = mCurrentProgram ? mCurrentProgram->GLName() : 0;
     AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
 
     // Textures
     GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
     AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);
 
     WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
     bound = curTex ? curTex->GLName() : 0;
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -17,17 +17,16 @@
 #include "WebGLBuffer.h"
 #include "WebGLContextUtils.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLProgram.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLShader.h"
 #include "WebGLTexture.h"
 #include "WebGLUniformLocation.h"
-#include "WebGLValidateStrings.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 #if defined(MOZ_WIDGET_COCOA)
 #include "nsCocoaFeatures.h"
 #endif
 
 namespace mozilla {
@@ -363,16 +362,60 @@ WebGLContext::ValidateDrawModeEnum(GLenu
         return true;
 
     default:
         ErrorInvalidEnumInfo(info, mode);
         return false;
     }
 }
 
+bool
+WebGLContext::ValidateGLSLVariableName(const nsAString& name, const char* info)
+{
+    if (name.IsEmpty())
+        return false;
+
+    const uint32_t maxSize = 256;
+    if (name.Length() > maxSize) {
+        ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
+                          " maximum allowed length of %d characters.", info,
+                          name.Length(), maxSize);
+        return false;
+    }
+
+    if (!ValidateGLSLString(name, info))
+        return false;
+
+    nsString prefix1 = NS_LITERAL_STRING("webgl_");
+    nsString prefix2 = NS_LITERAL_STRING("_webgl_");
+
+    if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
+        Substring(name, 0, prefix2.Length()).Equals(prefix2))
+    {
+        ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
+                              info);
+        return false;
+    }
+
+    return true;
+}
+
+bool WebGLContext::ValidateGLSLString(const nsAString& string, const char* info)
+{
+    for (uint32_t i = 0; i < string.Length(); ++i) {
+        if (!ValidateGLSLCharacter(string.CharAt(i))) {
+             ErrorInvalidValue("%s: String contains the illegal character"
+                               " '%d'.", info, string.CharAt(i));
+             return false;
+        }
+    }
+
+    return true;
+}
+
 /**
  * Return true if the framebuffer attachment is valid. Attachment must
  * be one of depth/stencil/depth_stencil/color attachment.
  */
 bool
 WebGLContext::ValidateFramebufferAttachment(GLenum attachment,
                                             const char* funcName)
 {
@@ -1465,129 +1508,261 @@ WebGLContext::ValidateTexImage(TexImageT
         return false;
     }
 
     // Parameters are OK
     return true;
 }
 
 bool
-WebGLContext::ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName)
+WebGLContext::ValidateUniformLocation(const char* info,
+                                      WebGLUniformLocation* loc)
 {
-    /* 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 (!ValidateObjectAllowNull(info, loc))
+        return false;
+
     if (!loc)
         return false;
 
-    if (!ValidateObject(funcName, loc))
+    // The need to check specifically for !mCurrentProgram here is explained in
+    // bug 657556.
+    if (!mCurrentProgram) {
+        ErrorInvalidOperation("%s: No program is currently bound.", info);
         return false;
+    }
 
-    if (!mCurrentProgram) {
-        ErrorInvalidOperation("%s: No program is currently bound.", funcName);
+    if (mCurrentProgram != loc->Program()) {
+        ErrorInvalidOperation("%s: This uniform location doesn't correspond to"
+                              " the current program.", info);
+        return false;
+    }
+
+    if (mCurrentProgram->Generation() != loc->ProgramGeneration()) {
+        ErrorInvalidOperation("%s: This uniform location is obsolete since the"
+                              " program has been relinked.", info);
         return false;
     }
 
-    return loc->ValidateForProgram(mCurrentProgram, this, funcName);
+    return true;
 }
 
 bool
-WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t setterElemSize,
+WebGLContext::ValidateSamplerUniformSetter(const char* info,
+                                           WebGLUniformLocation* loc,
+                                           GLint value)
+{
+    if (loc->Info().type != LOCAL_GL_SAMPLER_2D &&
+        loc->Info().type != LOCAL_GL_SAMPLER_CUBE)
+    {
+        return true;
+    }
+
+    if (value >= 0 && value < mGLMaxTextureUnits)
+        return true;
+
+    ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
+                      " valid texture unit.", info, value);
+    return false;
+}
+
+bool
+WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt,
                                         uint32_t arrayLength)
 {
     if (IsContextLost())
         return false;
 
-    if (arrayLength < setterElemSize) {
-        ErrorInvalidOperation("%s: Array must have >= %d elements.", name,
-                              setterElemSize);
+    if (arrayLength < cnt) {
+        ErrorInvalidOperation("%s: Array must be >= %d elements.", name, cnt);
+        return false;
+    }
+
+    return true;
+}
+
+static bool
+IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
+{
+    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_INT_SAMPLER_2D:
+    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
+    case LOCAL_GL_INT_SAMPLER_3D:
+    case LOCAL_GL_INT_SAMPLER_CUBE:
+    case LOCAL_GL_INT_VEC2:
+    case LOCAL_GL_INT_VEC3:
+    case LOCAL_GL_INT_VEC4:
+    case LOCAL_GL_SAMPLER_2D:
+    case LOCAL_GL_SAMPLER_2D_ARRAY:
+    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
+    case LOCAL_GL_SAMPLER_2D_SHADOW:
+    case LOCAL_GL_SAMPLER_CUBE:
+    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
+    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
+    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
+    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
+        return setterType == LOCAL_GL_INT;
+
+    case LOCAL_GL_FLOAT:
+    case LOCAL_GL_FLOAT_MAT2:
+    case LOCAL_GL_FLOAT_MAT2x3:
+    case LOCAL_GL_FLOAT_MAT2x4:
+    case LOCAL_GL_FLOAT_MAT3:
+    case LOCAL_GL_FLOAT_MAT3x2:
+    case LOCAL_GL_FLOAT_MAT3x4:
+    case LOCAL_GL_FLOAT_MAT4:
+    case LOCAL_GL_FLOAT_MAT4x2:
+    case LOCAL_GL_FLOAT_MAT4x3:
+    case LOCAL_GL_FLOAT_VEC2:
+    case LOCAL_GL_FLOAT_VEC3:
+    case LOCAL_GL_FLOAT_VEC4:
+        return setterType == LOCAL_GL_FLOAT;
+
+    default:
+        MOZ_ASSERT(false); // should never get here
+        return false;
+    }
+}
+
+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;
+    }
+
+    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;
+    }
+
+    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::ValidateUniformSetter(WebGLUniformLocation* loc,
                                     uint8_t setterElemSize, GLenum setterType,
-                                    const char* funcName, GLuint* out_rawLoc)
+                                    const char* info, GLuint* out_rawLoc)
 {
     if (IsContextLost())
         return false;
 
-    if (!ValidateUniformLocation(loc, funcName))
+    if (!ValidateUniformLocation(info, loc))
         return false;
 
-    if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
         return false;
 
-    *out_rawLoc = loc->mLoc;
+    *out_rawLoc = loc->Location();
     return true;
 }
 
 bool
 WebGLContext::ValidateUniformArraySetter(WebGLUniformLocation* loc,
                                          uint8_t setterElemSize,
                                          GLenum setterType,
                                          size_t setterArraySize,
-                                         const char* funcName,
+                                         const char* info,
                                          GLuint* const out_rawLoc,
                                          GLsizei* const out_numElementsToUpload)
 {
     if (IsContextLost())
         return false;
 
-    if (!ValidateUniformLocation(loc, funcName))
+    if (!ValidateUniformLocation(info, loc))
         return false;
 
-    if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
         return false;
 
-    if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
+    if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
+                                 info))
+    {
         return false;
+    }
 
-    *out_rawLoc = loc->mLoc;
-    *out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
+    *out_rawLoc = loc->Location();
+    *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
                                         setterArraySize / setterElemSize);
     return true;
 }
 
 bool
 WebGLContext::ValidateUniformMatrixArraySetter(WebGLUniformLocation* loc,
                                                uint8_t setterDims,
                                                GLenum setterType,
                                                size_t setterArraySize,
                                                bool setterTranspose,
-                                               const char* funcName,
+                                               const char* info,
                                                GLuint* const out_rawLoc,
                                                GLsizei* const out_numElementsToUpload)
 {
     uint8_t setterElemSize = setterDims * setterDims;
 
     if (IsContextLost())
         return false;
 
-    if (!ValidateUniformLocation(loc, funcName))
-        return false;
-
-    if (!loc->ValidateSizeAndType(setterElemSize, setterType, this, funcName))
+    if (!ValidateUniformLocation(info, loc))
         return false;
 
-    if (!loc->ValidateArrayLength(setterElemSize, setterArraySize, this, funcName))
+    if (!CheckUniformSizeAndType(*this, loc, setterElemSize, setterType, info))
         return false;
 
-    if (setterTranspose) {
-        ErrorInvalidValue("%s: `transpose` must be false.", funcName);
+    if (!CheckUniformArrayLength(*this, loc, setterElemSize, setterArraySize,
+                                 info))
+    {
         return false;
     }
 
-    *out_rawLoc = loc->mLoc;
-    *out_numElementsToUpload = std::min((size_t)loc->mActiveInfo->mElemCount,
+    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::ValidateAttribIndex(GLuint index, const char* info)
 {
     bool valid = (index < MaxVertexAttribs());
@@ -1915,23 +2090,25 @@ WebGLContext::InitAndValidateGL()
         gl->fPointParameterf(LOCAL_GL_POINT_SPRITE_COORD_ORIGIN,
                              LOCAL_GL_LOWER_LEFT);
     }
 #endif
 
     // Check the shader validator pref
     NS_ENSURE_TRUE(Preferences::GetRootBranch(), false);
 
-    mBypassShaderValidation = Preferences::GetBool("webgl.bypass-shader-validation",
-                                                   mBypassShaderValidation);
+    mShaderValidation = Preferences::GetBool("webgl.shader_validator",
+                                             mShaderValidation);
 
     // initialize shader translator
-    if (!ShInitialize()) {
-        GenerateWarning("GLSL translator initialization failed!");
-        return false;
+    if (mShaderValidation) {
+        if (!ShInitialize()) {
+            GenerateWarning("GLSL translator initialization failed!");
+            return false;
+        }
     }
 
     // Mesa can only be detected with the GL_VERSION string, of the form
     // "2.1 Mesa 7.11.0"
     const char* versionStr = (const char*)(gl->fGetString(LOCAL_GL_VERSION));
     mIsMesa = strstr(versionStr, "Mesa");
 
     // Notice that the point of calling fGetError here is not only to check for
--- a/dom/canvas/WebGLContextVertices.cpp
+++ b/dom/canvas/WebGLContextVertices.cpp
@@ -8,16 +8,17 @@
 #include "GLContext.h"
 #include "mozilla/CheckedInt.h"
 #include "WebGLBuffer.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLProgram.h"
 #include "WebGLRenderbuffer.h"
 #include "WebGLShader.h"
 #include "WebGLTexture.h"
+#include "WebGLUniformInfo.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 using namespace mozilla;
 using namespace dom;
 
 void
 WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -2,697 +2,371 @@
 /* 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 "WebGLProgram.h"
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "MurmurHash3.h"
 #include "WebGLContext.h"
 #include "WebGLShader.h"
-#include "WebGLUniformLocation.h"
-#include "WebGLValidateStrings.h"
 
 namespace mozilla {
 
-/* If `name`: "foo[3]"
- * Then returns true, with
- *     `out_baseName`: "foo"
- *     `out_isArray`: true
- *     `out_index`: 3
- *
- * If `name`: "foo"
- * Then returns true, with
- *     `out_baseName`: "foo"
- *     `out_isArray`: false
- *     `out_index`: <not written>
- */
+/** Takes an ASCII string like "foo[i]", turns it into "foo" and returns "[i]"
+  * in bracketPart.
+  *
+  * \param string input/output: The string to split, becomes the string without
+  *                             the bracket part.
+  * \param bracketPart output: Gets the bracket part.
+  *
+  * Notice that if there are multiple brackets like "foo[i].bar[j]", only the
+  * last bracket is split.
+  */
 static bool
-ParseName(const nsCString& name, nsCString* const out_baseName,
-          bool* const out_isArray, size_t* const out_arrayIndex)
+SplitLastSquareBracket(nsACString& string, nsCString& bracketPart)
 {
-    int32_t indexEnd = name.RFind("]");
-    if (indexEnd == -1 ||
-        (uint32_t)indexEnd != name.Length() - 1)
-    {
-        *out_baseName = name;
-        *out_isArray = false;
-        return true;
-    }
+    MOZ_ASSERT(bracketPart.IsEmpty(),
+               "SplitLastSquareBracket must be called with empty bracketPart"
+               " string.");
 
-    int32_t indexOpenBracket = name.RFind("[");
-    if (indexOpenBracket == -1)
+    if (string.IsEmpty())
         return false;
 
-    uint32_t indexStart = indexOpenBracket + 1;
-    uint32_t indexLen = indexEnd - indexStart;
-    if (indexLen == 0)
+    char* string_start = string.BeginWriting();
+    char* s = string_start + string.Length() - 1;
+
+    if (*s != ']')
         return false;
 
-    const nsAutoCString indexStr(Substring(name, indexStart, indexLen));
+    while (*s != '[' && s != string_start)
+        s--;
 
-    nsresult errorcode;
-    int32_t indexNum = indexStr.ToInteger(&errorcode);
-    if (NS_FAILED(errorcode))
+    if (*s != '[')
         return false;
 
-    if (indexNum < 0)
-        return false;
-
-    *out_baseName = StringHead(name, indexOpenBracket);
-    *out_isArray = true;
-    *out_arrayIndex = indexNum;
+    bracketPart.Assign(s);
+    *s = 0;
+    string.EndWriting();
+    string.SetLength(s - string_start);
     return true;
 }
 
-static void
-AddActiveInfo(GLint elemCount, GLenum elemType, bool isArray,
-              const nsACString& baseUserName, const nsACString& baseMappedName,
-              std::vector<nsRefPtr<WebGLActiveInfo>>* activeInfoList,
-              std::map<nsCString, const WebGLActiveInfo*>* infoLocMap)
-{
-    nsRefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(elemCount, elemType, isArray,
-                                                         baseUserName, baseMappedName);
-    activeInfoList->push_back(info);
-
-    infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
-}
-
-//#define DUMP_SHADERVAR_MAPPINGS
-
-static TemporaryRef<const webgl::LinkedProgramInfo>
-QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
-{
-    RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
-
-    GLuint maxAttribLenWithNull = 0;
-    gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
-                      (GLint*)&maxAttribLenWithNull);
-    if (maxAttribLenWithNull < 1)
-        maxAttribLenWithNull = 1;
-
-    GLuint maxUniformLenWithNull = 0;
-    gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
-                      (GLint*)&maxUniformLenWithNull);
-    if (maxUniformLenWithNull < 1)
-        maxUniformLenWithNull = 1;
-
-#ifdef DUMP_SHADERVAR_MAPPINGS
-    printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
-    printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
-#endif
-
-    // Attribs
-
-    GLuint numActiveAttribs = 0;
-    gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
-                      (GLint*)&numActiveAttribs);
-
-    for (GLuint i = 0; i < numActiveAttribs; i++) {
-        nsAutoCString mappedName;
-        mappedName.SetLength(maxAttribLenWithNull - 1);
-
-        GLsizei lengthWithoutNull = 0;
-        GLint elemCount = 0; // `size`
-        GLenum elemType = 0; // `type`
-        gl->fGetActiveAttrib(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
-                             &elemCount, &elemType, mappedName.BeginWriting());
-
-        mappedName.SetLength(lengthWithoutNull);
-
-        // Collect ActiveInfos:
-
-        // Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
-        // path.
-        nsDependentCString userName;
-        if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
-            userName.Rebind(mappedName, 0);
-
-#ifdef DUMP_SHADERVAR_MAPPINGS
-        printf_stderr("[attrib %i] %s/%s\n", i, mappedName.BeginReading(),
-                      userName.BeginReading());
-        printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
-#endif
-
-        const bool isArray = false;
-        AddActiveInfo(elemCount, elemType, isArray, userName, mappedName,
-                      &info->activeAttribs, &info->attribMap);
-
-        // Collect active locations:
-        GLint loc = gl->fGetAttribLocation(prog->mGLName, mappedName.BeginReading());
-        if (loc == -1)
-            MOZ_CRASH("Active attrib has no location.");
-
-        info->activeAttribLocs.insert(loc);
-    }
-
-    // Uniforms
-
-    const bool needsCheckForArrays = true;
-
-    GLuint numActiveUniforms = 0;
-    gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORMS,
-                      (GLint*)&numActiveUniforms);
-
-    for (GLuint i = 0; i < numActiveUniforms; i++) {
-        nsAutoCString mappedName;
-        mappedName.SetLength(maxUniformLenWithNull - 1);
-
-        GLsizei lengthWithoutNull = 0;
-        GLint elemCount = 0; // `size`
-        GLenum elemType = 0; // `type`
-        gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
-                              &elemCount, &elemType, mappedName.BeginWriting());
-
-        mappedName.SetLength(lengthWithoutNull);
-
-        nsAutoCString baseMappedName;
-        bool isArray;
-        size_t arrayIndex;
-        if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
-            MOZ_CRASH("Failed to parse `mappedName` received from driver.");
-
-        // Note that for good drivers, `isArray` should already be correct.
-        // However, if FindUniform succeeds, it will be validator-guaranteed correct.
-
-        nsAutoCString baseUserName;
-        if (!prog->FindUniformByMappedName(baseMappedName, &baseUserName, &isArray)) {
-            baseUserName = baseMappedName;
-
-            if (needsCheckForArrays && !isArray) {
-                // By GLES 3, GetUniformLocation("foo[0]") should return -1 if `foo` is
-                // not an array. Our current linux Try slaves return the location of `foo`
-                // anyways, though.
-                std::string mappedName = baseMappedName.BeginReading();
-                mappedName += "[0]";
-
-                GLint loc = gl->fGetUniformLocation(prog->mGLName, mappedName.c_str());
-                if (loc != -1)
-                    isArray = true;
-            }
-        }
-
-#ifdef DUMP_SHADERVAR_MAPPINGS
-        printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
-                      (int)isArray, baseMappedName.BeginReading(),
-                      baseUserName.BeginReading());
-        printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
-        printf_stderr("    isArray: %d\n", (int)isArray);
-#endif
-
-        AddActiveInfo(elemCount, elemType, isArray, baseUserName, baseMappedName,
-                      &info->activeUniforms, &info->uniformMap);
-    }
-
-    return info.forget();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-
-webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* aProg)
-    : prog(aProg)
-{ }
-
-////////////////////////////////////////////////////////////////////////////////
-// WebGLProgram
-
-static GLuint
-CreateProgram(gl::GLContext* gl)
-{
-    gl->MakeCurrent();
-    return gl->fCreateProgram();
+JSObject*
+WebGLProgram::WrapObject(JSContext* cx) {
+    return dom::WebGLProgramBinding::Wrap(cx, this);
 }
 
 WebGLProgram::WebGLProgram(WebGLContext* webgl)
     : WebGLContextBoundObject(webgl)
-    , mGLName(CreateProgram(webgl->GL()))
+    , mLinkStatus(false)
+    , mGeneration(0)
+    , mIdentifierMap(new CStringMap)
+    , mIdentifierReverseMap(new CStringMap)
+    , mUniformInfoMap(new CStringToUniformInfoMap)
+    , mAttribMaxNameLength(0)
 {
+    mContext->MakeContextCurrent();
+    mGLName = mContext->gl->fCreateProgram();
     mContext->mPrograms.insertBack(this);
 }
 
 void
 WebGLProgram::Delete()
 {
-    gl::GLContext* gl = mContext->GL();
-
-    gl->MakeCurrent();
-    gl->fDeleteProgram(mGLName);
-
-    mVertShader = nullptr;
-    mFragShader = nullptr;
-
-    mMostRecentLinkInfo = nullptr;
-
+    DetachShaders();
+    mContext->MakeContextCurrent();
+    mContext->gl->fDeleteProgram(mGLName);
     LinkedListElement<WebGLProgram>::removeFrom(mContext->mPrograms);
 }
 
-////////////////////////////////////////////////////////////////////////////////
-// GL funcs
-
-void
+bool
 WebGLProgram::AttachShader(WebGLShader* shader)
 {
-    WebGLRefPtr<WebGLShader>* shaderSlot;
-    switch (shader->mType) {
-    case LOCAL_GL_VERTEX_SHADER:
-        shaderSlot = &mVertShader;
-        break;
-    case LOCAL_GL_FRAGMENT_SHADER:
-        shaderSlot = &mFragShader;
-        break;
-    default:
-        mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
-        return;
-    }
-
-    if (*shaderSlot) {
-        if (shader == *shaderSlot) {
-            mContext->ErrorInvalidOperation("attachShader: `shader` is already attached.");
-        } else {
-            mContext->ErrorInvalidOperation("attachShader: Only one of each type of"
-                                            " shader may be attached to a program.");
-        }
-        return;
-    }
-
-    *shaderSlot = shader;
-
-    mContext->MakeContextCurrent();
-    mContext->gl->fAttachShader(mGLName, shader->mGLName);
-}
-
-void
-WebGLProgram::BindAttribLocation(GLuint loc, const nsAString& name)
-{
-    if (!ValidateGLSLVariableName(name, mContext, "bindAttribLocation"))
-        return;
-
-    if (loc >= mContext->MaxVertexAttribs()) {
-        mContext->ErrorInvalidValue("bindAttribLocation: `location` must be less than"
-                                    " MAX_VERTEX_ATTRIBS.");
-        return;
-    }
+    if (ContainsShader(shader))
+        return false;
 
-    if (StringBeginsWith(name, NS_LITERAL_STRING("gl_"))) {
-        mContext->ErrorInvalidOperation("bindAttribLocation: Can't set the  location of a"
-                                        " name that starts with 'gl_'.");
-        return;
-    }
-
-    NS_LossyConvertUTF16toASCII asciiName(name);
-
-    auto res = mBoundAttribLocs.insert(std::pair<nsCString, GLuint>(asciiName, loc));
-
-    const bool wasInserted = res.second;
-    if (!wasInserted) {
-        auto itr = res.first;
-        itr->second = loc;
-    }
-}
-
-void
-WebGLProgram::DetachShader(WebGLShader* shader)
-{
-    MOZ_ASSERT(shader);
-
-    WebGLRefPtr<WebGLShader>* shaderSlot;
-    switch (shader->mType) {
-    case LOCAL_GL_VERTEX_SHADER:
-        shaderSlot = &mVertShader;
-        break;
-    case LOCAL_GL_FRAGMENT_SHADER:
-        shaderSlot = &mFragShader;
-        break;
-    default:
-        mContext->ErrorInvalidOperation("attachShader: Bad type for shader.");
-        return;
-    }
-
-    if (*shaderSlot != shader) {
-        mContext->ErrorInvalidOperation("detachShader: `shader` is not attached.");
-        return;
-    }
-
-    *shaderSlot = nullptr;
+    mAttachedShaders.AppendElement(shader);
 
     mContext->MakeContextCurrent();
-    mContext->gl->fDetachShader(mGLName, shader->mGLName);
-}
-
-already_AddRefed<WebGLActiveInfo>
-WebGLProgram::GetActiveAttrib(GLuint index) const
-{
-    if (!mMostRecentLinkInfo) {
-        nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
-        return ret.forget();
-    }
-
-    const auto& activeList = mMostRecentLinkInfo->activeAttribs;
-
-    if (index >= activeList.size()) {
-        mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
-                                    index, "ACTIVE_ATTRIBS", activeList.size());
-        return nullptr;
-    }
-
-    nsRefPtr<WebGLActiveInfo> ret =  activeList[index];
-    return ret.forget();
-}
-
-already_AddRefed<WebGLActiveInfo>
-WebGLProgram::GetActiveUniform(GLuint index) const
-{
-    if (!mMostRecentLinkInfo) {
-        nsRefPtr<WebGLActiveInfo> ret = WebGLActiveInfo::CreateInvalid();
-        return ret.forget();
-    }
-
-    const auto& activeList = mMostRecentLinkInfo->activeUniforms;
-
-    if (index >= activeList.size()) {
-        mContext->ErrorInvalidValue("`index` (%i) must be less than %s (%i).",
-                                    index, "ACTIVE_UNIFORMS", activeList.size());
-        return nullptr;
-    }
-
-    nsRefPtr<WebGLActiveInfo> ret = activeList[index];
-    return ret.forget();
-}
-
-void
-WebGLProgram::GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const
-{
-    out->TruncateLength(0);
-
-    if (mVertShader)
-        out->AppendElement(mVertShader);
-
-    if (mFragShader)
-        out->AppendElement(mFragShader);
-}
-
-GLint
-WebGLProgram::GetAttribLocation(const nsAString& userName_wide) const
-{
-    if (!ValidateGLSLVariableName(userName_wide, mContext, "getAttribLocation"))
-        return -1;
-
-    if (!IsLinked()) {
-        mContext->ErrorInvalidOperation("getAttribLocation: `program` must be linked.");
-        return -1;
-    }
-
-    const NS_LossyConvertUTF16toASCII userName(userName_wide);
-
-    const WebGLActiveInfo* info;
-    if (!LinkInfo()->FindAttrib(userName, &info))
-        return -1;
-
-    const nsCString& mappedName = info->mBaseMappedName;
-
-    gl::GLContext* gl = mContext->GL();
-    gl->MakeCurrent();
-
-    return gl->fGetAttribLocation(mGLName, mappedName.BeginReading());
-}
-
-void
-WebGLProgram::GetProgramInfoLog(nsAString* const out) const
-{
-    CopyASCIItoUTF16(mLinkLog, *out);
-}
+    mContext->gl->fAttachShader(GLName(), shader->GLName());
 
-static GLint
-GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname)
-{
-    GLint ret = 0;
-    gl->fGetProgramiv(program, pname, &ret);
-    return ret;
-}
-
-JS::Value
-WebGLProgram::GetProgramParameter(GLenum pname) const
-{
-    gl::GLContext* gl = mContext->gl;
-    gl->MakeCurrent();
-
-    if (mContext->IsWebGL2()) {
-        switch (pname) {
-        case LOCAL_GL_ACTIVE_UNIFORM_BLOCKS:
-            return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
-        }
-    }
-
-
-    switch (pname) {
-    case LOCAL_GL_ATTACHED_SHADERS:
-    case LOCAL_GL_ACTIVE_UNIFORMS:
-    case LOCAL_GL_ACTIVE_ATTRIBUTES:
-        return JS::Int32Value(GetProgramiv(gl, mGLName, pname));
-
-    case LOCAL_GL_DELETE_STATUS:
-        return JS::BooleanValue(IsDeleteRequested());
-
-    case LOCAL_GL_LINK_STATUS:
-        return JS::BooleanValue(IsLinked());
-
-    case LOCAL_GL_VALIDATE_STATUS:
-#ifdef XP_MACOSX
-        // See comment in ValidateProgram.
-        if (gl->WorkAroundDriverBugs())
-            return JS::BooleanValue(true);
-#endif
-        return JS::BooleanValue(bool(GetProgramiv(gl, mGLName, pname)));
-
-    default:
-        mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
-                                       pname);
-        return JS::NullValue();
-    }
-}
-
-already_AddRefed<WebGLUniformLocation>
-WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
-{
-    if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
-        return nullptr;
-
-    if (!IsLinked()) {
-        mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
-        return nullptr;
-    }
-
-    const NS_LossyConvertUTF16toASCII userName(userName_wide);
-
-    nsDependentCString baseUserName;
-    bool isArray;
-    size_t arrayIndex;
-    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
-        return nullptr;
-
-    const WebGLActiveInfo* activeInfo;
-    if (!LinkInfo()->FindUniform(baseUserName, &activeInfo))
-        return nullptr;
-
-    const nsCString& baseMappedName = activeInfo->mBaseMappedName;
-
-    nsAutoCString mappedName(baseMappedName);
-    if (isArray) {
-        mappedName.AppendLiteral("[");
-        mappedName.AppendInt(uint32_t(arrayIndex));
-        mappedName.AppendLiteral("]");
-    }
-
-    gl::GLContext* gl = mContext->GL();
-    gl->MakeCurrent();
-
-    GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
-    if (loc == -1)
-        return nullptr;
-
-    nsRefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
-                                                                     loc, activeInfo);
-    return locObj.forget();
+    return true;
 }
 
 bool
-WebGLProgram::LinkProgram()
+WebGLProgram::DetachShader(WebGLShader* shader)
 {
-    mContext->InvalidateBufferFetching(); // we do it early in this function
-    // as some of the validation below changes program state
-
-    mLinkLog.Truncate();
-    mMostRecentLinkInfo = nullptr;
-
-    if (!mVertShader || !mVertShader->IsCompiled()) {
-        mLinkLog.AssignLiteral("Must have a compiled vertex shader attached.");
-        mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
+    if (!mAttachedShaders.RemoveElement(shader))
         return false;
-    }
 
-    if (!mFragShader || !mFragShader->IsCompiled()) {
-        mLinkLog.AssignLiteral("Must have an compiled fragment shader attached.");
-        mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
-        return false;
-    }
-
-    if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
-        mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
-        return false;
-    }
-
-    gl::GLContext* gl = mContext->gl;
-    gl->MakeCurrent();
+    mContext->MakeContextCurrent();
+    mContext->gl->fDetachShader(GLName(), shader->GLName());
 
-    // Bug 777028: Mesa can't handle more than 16 samplers per program,
-    // counting each array entry.
-    size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
-                                           mFragShader->CalcNumSamplerUniforms();
-    if (gl->WorkAroundDriverBugs() &&
-        mContext->mIsMesa &&
-        numSamplerUniforms_upperBound > 16)
-    {
-        mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
-                               " Mesa drivers to avoid crashing.");
-        mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
-        return false;
-    }
+    return true;
+}
 
-    // Bind the attrib locations.
-    // This can't be done trivially, because we have to deal with mapped attrib names.
-    for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
-        const nsCString& name = itr->first;
-        GLuint index = itr->second;
-
-        mVertShader->BindAttribLocation(mGLName, name, index);
-    }
-
-    if (LinkAndUpdate())
-        return true;
-
-    // Failed link.
-    if (mContext->ShouldGenerateWarnings()) {
-        // report shader/program infoLogs as warnings.
-        // note that shader compilation errors can be deferred to linkProgram,
-        // which is why we can't do anything in compileShader. In practice we could
-        // report in compileShader the translation errors generated by ANGLE,
-        // but it seems saner to keep a single way of obtaining shader infologs.
-        if (!mLinkLog.IsEmpty()) {
-            mContext->GenerateWarning("linkProgram: Failed to link, leaving the following"
-                                      " log:\n%s\n",
-                                      mLinkLog.BeginReading());
-        }
+bool
+WebGLProgram::HasAttachedShaderOfType(GLenum shaderType)
+{
+    for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
+        if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType)
+            return true;
     }
 
     return false;
 }
 
 bool
-WebGLProgram::UseProgram() const
+WebGLProgram::HasBadShaderAttached()
 {
-    if (!mMostRecentLinkInfo) {
-        mContext->ErrorInvalidOperation("useProgram: Program has not been successfully"
-                                        " linked.");
-        return false;
-    }
-
-    mContext->MakeContextCurrent();
-
-    mContext->InvalidateBufferFetching();
-
-    mContext->gl->fUseProgram(mGLName);
-    return true;
-}
-
-void
-WebGLProgram::ValidateProgram() const
-{
-    mContext->MakeContextCurrent();
-    gl::GLContext* gl = mContext->gl;
-
-#ifdef XP_MACOSX
-    // See bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed
-    // with Mac OS 10.6.7.
-    if (gl->WorkAroundDriverBugs()) {
-        mContext->GenerateWarning("validateProgram: Implemented as a no-op on"
-                                  " Mac to work around crashes.");
-        return;
+    for (uint32_t i = 0; i < mAttachedShaders.Length(); ++i) {
+        if (mAttachedShaders[i] && !mAttachedShaders[i]->CompileStatus())
+            return true;
     }
-#endif
-
-    gl->fValidateProgram(mGLName);
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool
-WebGLProgram::LinkAndUpdate()
-{
-    mMostRecentLinkInfo = nullptr;
-
-    gl::GLContext* gl = mContext->gl;
-    gl->fLinkProgram(mGLName);
-
-    // Grab the program log.
-    GLuint logLenWithNull = 0;
-    gl->fGetProgramiv(mGLName, LOCAL_GL_INFO_LOG_LENGTH, (GLint*)&logLenWithNull);
-    if (logLenWithNull > 1) {
-        mLinkLog.SetLength(logLenWithNull - 1);
-        gl->fGetProgramInfoLog(mGLName, logLenWithNull, nullptr, mLinkLog.BeginWriting());
-    } else {
-        mLinkLog.SetLength(0);
-    }
-
-    GLint ok = 0;
-    gl->fGetProgramiv(mGLName, LOCAL_GL_LINK_STATUS, &ok);
-    if (!ok)
-        return false;
-
-    mMostRecentLinkInfo = QueryProgramInfo(this, gl);
-
-    MOZ_ASSERT(mMostRecentLinkInfo);
-    if (!mMostRecentLinkInfo)
-        mLinkLog.AssignLiteral("Failed to gather program info.");
-
-    return mMostRecentLinkInfo;
-}
-
-bool
-WebGLProgram::FindAttribUserNameByMappedName(const nsACString& mappedName,
-                                             nsDependentCString* const out_userName) const
-{
-    if (mVertShader->FindAttribUserNameByMappedName(mappedName, out_userName))
-        return true;
 
     return false;
 }
 
-bool
-WebGLProgram::FindUniformByMappedName(const nsACString& mappedName,
-                                      nsCString* const out_userName,
-                                      bool* const out_isArray) const
+size_t
+WebGLProgram::UpperBoundNumSamplerUniforms()
+{
+    size_t numSamplerUniforms = 0;
+
+    for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
+        const WebGLShader* shader = mAttachedShaders[i];
+        if (!shader)
+            continue;
+
+        for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
+            WebGLUniformInfo u = shader->mUniformInfos[j];
+            if (u.type == LOCAL_GL_SAMPLER_2D ||
+                u.type == LOCAL_GL_SAMPLER_CUBE)
+            {
+                numSamplerUniforms += u.arraySize;
+            }
+        }
+    }
+
+    return numSamplerUniforms;
+}
+
+void
+WebGLProgram::MapIdentifier(const nsACString& name,
+                            nsCString* const out_mappedName)
 {
-    if (mVertShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
-        return true;
+    MOZ_ASSERT(mIdentifierMap);
+
+    nsCString mutableName(name);
+    nsCString bracketPart;
+    bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
+    if (hadBracketPart)
+        mutableName.AppendLiteral("[0]");
+
+    if (mIdentifierMap->Get(mutableName, out_mappedName)) {
+        if (hadBracketPart) {
+            nsCString mappedBracketPart;
+            bool mappedHadBracketPart = SplitLastSquareBracket(*out_mappedName,
+                                                               mappedBracketPart);
+            if (mappedHadBracketPart)
+                out_mappedName->Append(bracketPart);
+        }
+        return;
+    }
+
+    // Not found? We might be in the situation we have a uniform array name and
+    // the GL's glGetActiveUniform returned its name without [0], as is allowed
+    // by desktop GL but not in ES. Let's then try with [0].
+    mutableName.AppendLiteral("[0]");
+    if (mIdentifierMap->Get(mutableName, out_mappedName))
+        return;
+
+    /* Not found? Return name unchanged. This case happens e.g. on bad user
+     * input, or when we're not using identifier mapping, or if we didn't store
+     * an identifier in the map because e.g. its mapping is trivial. (as happens
+     * for short identifiers)
+     */
+    out_mappedName->Assign(name);
+}
+
+void
+WebGLProgram::ReverseMapIdentifier(const nsACString& name,
+                                   nsCString* const out_reverseMappedName)
+{
+    MOZ_ASSERT(mIdentifierReverseMap);
 
-    if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
-        return true;
+    nsCString mutableName(name);
+    nsCString bracketPart;
+    bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
+    if (hadBracketPart)
+        mutableName.AppendLiteral("[0]");
+
+    if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName)) {
+        if (hadBracketPart) {
+            nsCString reverseMappedBracketPart;
+            bool reverseMappedHadBracketPart = SplitLastSquareBracket(*out_reverseMappedName,
+                                                                      reverseMappedBracketPart);
+            if (reverseMappedHadBracketPart)
+                out_reverseMappedName->Append(bracketPart);
+        }
+        return;
+    }
+
+    // Not found? We might be in the situation we have a uniform array name and
+    // the GL's glGetActiveUniform returned its name without [0], as is allowed
+    // by desktop GL but not in ES. Let's then try with [0].
+    mutableName.AppendLiteral("[0]");
+    if (mIdentifierReverseMap->Get(mutableName, out_reverseMappedName))
+        return;
 
-    return false;
+    /* Not found? Return name unchanged. This case happens e.g. on bad user
+     * input, or when we're not using identifier mapping, or if we didn't store
+     * an identifier in the map because e.g. its mapping is trivial. (as happens
+     * for short identifiers)
+     */
+    out_reverseMappedName->Assign(name);
+}
+
+WebGLUniformInfo
+WebGLProgram::GetUniformInfoForMappedIdentifier(const nsACString& name)
+{
+    MOZ_ASSERT(mUniformInfoMap);
+
+    nsCString mutableName(name);
+    nsCString bracketPart;
+    bool hadBracketPart = SplitLastSquareBracket(mutableName, bracketPart);
+    // If there is a bracket, we're either an array or an entry in an array.
+    if (hadBracketPart)
+        mutableName.AppendLiteral("[0]");
+
+    WebGLUniformInfo info;
+    mUniformInfoMap->Get(mutableName, &info);
+    // We don't check if that Get failed, as if it did, it left info with
+    // default values.
+
+    return info;
 }
 
-////////////////////////////////////////////////////////////////////////////////
+bool
+WebGLProgram::UpdateInfo()
+{
+    mAttribMaxNameLength = 0;
+    for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
+        mAttribMaxNameLength = std::max(mAttribMaxNameLength,
+                                        mAttachedShaders[i]->mAttribMaxNameLength);
+    }
+
+    GLint attribCount;
+    mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &attribCount);
+
+    if (!mAttribsInUse.SetLength(mContext->mGLMaxVertexAttribs)) {
+        mContext->ErrorOutOfMemory("updateInfo: Out of memory to allocate %d"
+                                   " attribs.", mContext->mGLMaxVertexAttribs);
+        return false;
+    }
+
+    for (size_t i = 0; i < mAttribsInUse.Length(); i++)
+        mAttribsInUse[i] = false;
+
+    nsAutoArrayPtr<char> nameBuf(new char[mAttribMaxNameLength]);
+
+    for (int i = 0; i < attribCount; ++i) {
+        GLint attrnamelen;
+        GLint attrsize;
+        GLenum attrtype;
+        mContext->gl->fGetActiveAttrib(mGLName, i, mAttribMaxNameLength,
+                                       &attrnamelen, &attrsize, &attrtype,
+                                       nameBuf);
+        if (attrnamelen > 0) {
+            GLint loc = mContext->gl->fGetAttribLocation(mGLName, nameBuf);
+            MOZ_ASSERT(loc >= 0, "Major oops in managing the attributes of a"
+                                 " WebGL program.");
+            if (loc < mContext->mGLMaxVertexAttribs) {
+                mAttribsInUse[loc] = true;
+            } else {
+                mContext->GenerateWarning("Program exceeds MAX_VERTEX_ATTRIBS.");
+                return false;
+            }
+        }
+    }
 
-JSObject*
-WebGLProgram::WrapObject(JSContext* js)
-{
-    return dom::WebGLProgramBinding::Wrap(js, this);
+    // nsAutoPtr will delete old version first
+    mIdentifierMap = new CStringMap;
+    mIdentifierReverseMap = new CStringMap;
+    mUniformInfoMap = new CStringToUniformInfoMap;
+    for (size_t i = 0; i < mAttachedShaders.Length(); i++) {
+        // Loop through ATTRIBUTES
+        for (size_t j = 0; j < mAttachedShaders[i]->mAttributes.Length(); j++) {
+            const WebGLMappedIdentifier& attrib = mAttachedShaders[i]->mAttributes[j];
+
+            // FORWARD MAPPING
+            mIdentifierMap->Put(attrib.original, attrib.mapped);
+            // REVERSE MAPPING
+            mIdentifierReverseMap->Put(attrib.mapped, attrib.original);
+        }
+
+        // Loop through UNIFORMS
+        for (size_t j = 0; j < mAttachedShaders[i]->mUniforms.Length(); j++) {
+            // Add the uniforms name mapping to mIdentifier[Reverse]Map
+            const WebGLMappedIdentifier& uniform = mAttachedShaders[i]->mUniforms[j];
+
+            // FOWARD MAPPING
+            mIdentifierMap->Put(uniform.original, uniform.mapped);
+            // REVERSE MAPPING
+            mIdentifierReverseMap->Put(uniform.mapped, uniform.original);
+
+            // Add uniform info to mUniformInfoMap
+            const WebGLUniformInfo& info = mAttachedShaders[i]->mUniformInfos[j];
+            mUniformInfoMap->Put(uniform.mapped, info);
+        }
+    }
+
+    mActiveAttribMap.clear();
+
+    GLint numActiveAttrs = 0;
+    mContext->gl->fGetProgramiv(mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES, &numActiveAttrs);
+
+    // Spec says the maximum attrib name length is 256 chars, so this is
+    // sufficient to hold any attrib name.
+    char attrName[257];
+
+    GLint dummySize;
+    GLenum dummyType;
+    for (GLint i = 0; i < numActiveAttrs; i++) {
+        mContext->gl->fGetActiveAttrib(mGLName, i, 257, nullptr, &dummySize,
+                                       &dummyType, attrName);
+        GLint attrLoc = mContext->gl->fGetAttribLocation(mGLName, attrName);
+        MOZ_ASSERT(attrLoc >= 0);
+        mActiveAttribMap.insert(std::make_pair(attrLoc, nsCString(attrName)));
+    }
+
+    return true;
 }
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
+/*static*/ uint64_t
+WebGLProgram::IdentifierHashFunction(const char* ident, size_t size)
+{
+    uint64_t outhash[2];
+    // NB: we use the x86 function everywhere, even though it's suboptimal perf
+    // on x64.  They return different results; not sure if that's a requirement.
+    MurmurHash3_x86_128(ident, size, 0, &outhash[0]);
+    return outhash[0];
+}
+
+/*static*/ void
+WebGLProgram::HashMapIdentifier(const nsACString& name,
+                                nsCString* const out_hashedName)
+{
+    uint64_t hash = IdentifierHashFunction(name.BeginReading(), name.Length());
+    out_hashedName->Truncate();
+    // This MUST MATCH HASHED_NAME_PREFIX from
+    // angle/src/compiler/translator/HashNames.h .
+    out_hashedName->AppendPrintf("webgl_%llx", hash);
+}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mAttachedShaders)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLProgram, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLProgram, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -4,147 +4,135 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_PROGRAM_H_
 #define WEBGL_PROGRAM_H_
 
 #include <map>
 #include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
-#include "nsString.h"
 #include "nsWrapperCache.h"
-#include <set>
-#include <vector>
 #include "WebGLObjectModel.h"
 #include "WebGLShader.h"
+#include "WebGLUniformInfo.h"
 
 namespace mozilla {
 
-class WebGLActiveInfo;
-class WebGLProgram;
-class WebGLUniformLocation;
-
-namespace webgl {
-
-struct LinkedProgramInfo MOZ_FINAL
-    : public RefCounted<LinkedProgramInfo>
-    , public SupportsWeakPtr<LinkedProgramInfo>
-{
-    MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
-
-    WebGLProgram* const prog;
-    std::vector<nsRefPtr<WebGLActiveInfo>> activeAttribs;
-    std::vector<nsRefPtr<WebGLActiveInfo>> activeUniforms;
-
-    // Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
-    // user-facing `GLActiveInfo::name`s, without any final "[0]".
-    std::map<nsCString, const WebGLActiveInfo*> attribMap;
-    std::map<nsCString, const WebGLActiveInfo*> uniformMap;
-
-    // Needed for draw call validation.
-    std::set<GLuint> activeAttribLocs;
-
-    explicit LinkedProgramInfo(WebGLProgram* aProg);
-
-    bool FindAttrib(const nsCString& baseUserName,
-                    const WebGLActiveInfo** const out_activeInfo) const
-    {
-        auto itr = attribMap.find(baseUserName);
-        if (itr == attribMap.end())
-            return false;
-
-        *out_activeInfo = itr->second;
-        return true;
-    }
-
-    bool FindUniform(const nsCString& baseUserName,
-                     const WebGLActiveInfo** const out_activeInfo) const
-    {
-        auto itr = uniformMap.find(baseUserName);
-        if (itr == uniformMap.end())
-            return false;
-
-        *out_activeInfo = itr->second;
-        return true;
-    }
-
-    bool HasActiveAttrib(GLuint loc) const {
-        auto itr = activeAttribLocs.find(loc);
-        return itr != activeAttribLocs.end();
-    }
-};
-
-} // namespace webgl
-
 class WebGLShader;
+struct WebGLUniformInfo;
 
 typedef nsDataHashtable<nsCStringHashKey, nsCString> CStringMap;
+typedef nsDataHashtable<nsCStringHashKey,
+                        WebGLUniformInfo> CStringToUniformInfoMap;
 
 class WebGLProgram MOZ_FINAL
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLProgram>
     , public LinkedListElement<WebGLProgram>
     , public WebGLContextBoundObject
 {
 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(WebGLShader* shader);
-    already_AddRefed<WebGLActiveInfo> GetActiveAttrib(GLuint index) const;
-    already_AddRefed<WebGLActiveInfo> GetActiveUniform(GLuint index) const;
-    void GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const;
-    GLint GetAttribLocation(const nsAString& name) const;
-    void GetProgramInfoLog(nsAString* const out) const;
-    JS::Value GetProgramParameter(GLenum pname) const;
-    already_AddRefed<WebGLUniformLocation> GetUniformLocation(const nsAString& name) const;
-    bool LinkProgram();
-    bool UseProgram() const;
-    void ValidateProgram() const;
+    void DetachShaders() {
+        mAttachedShaders.Clear();
+    }
+
+    GLuint GLName() { return mGLName; }
+    const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const {
+        return mAttachedShaders;
+    }
+    bool LinkStatus() { return mLinkStatus; }
+    uint32_t Generation() const { return mGeneration.value(); }
+    void SetLinkStatus(bool val) { mLinkStatus = val; }
+
+    bool ContainsShader(WebGLShader* shader) {
+        return mAttachedShaders.Contains(shader);
+    }
+
+    // return true if the shader wasn't already attached
+    bool AttachShader(WebGLShader* shader);
+
+    // return true if the shader was found and removed
+    bool DetachShader(WebGLShader* shader);
+
+    bool HasAttachedShaderOfType(GLenum shaderType);
+
+    bool HasBothShaderTypesAttached() {
+        return HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) &&
+               HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
+    }
+
+    bool HasBadShaderAttached();
 
-    ////////////////
+    size_t UpperBoundNumSamplerUniforms();
+
+    bool NextGeneration() {
+        if (!(mGeneration + 1).isValid())
+            return false; // must exit without changing mGeneration
+
+        ++mGeneration;
+        return true;
+    }
+
+    // Called only after LinkProgram
+    bool UpdateInfo();
+
+    // Getters for cached program info
+    bool IsAttribInUse(uint32_t i) const { return mAttribsInUse[i]; }
 
-    bool FindAttribUserNameByMappedName(const nsACString& mappedName,
-                                        nsDependentCString* const out_userName) const;
-    bool FindUniformByMappedName(const nsACString& mappedName,
-                                 nsCString* const out_userName,
-                                 bool* const out_isArray) const;
+    // Maps identifier |name| to the mapped identifier |*mappedName|
+    // Both are ASCII strings.
+    void MapIdentifier(const nsACString& name, nsCString* out_mappedName);
 
-    bool IsLinked() const { return mMostRecentLinkInfo; }
+    // Un-maps mapped identifier |name| to the original identifier
+    // |*reverseMappedName|.
+    // Both are ASCII strings.
+    void ReverseMapIdentifier(const nsACString& name,
+                              nsCString* out_reverseMappedName);
 
-    const webgl::LinkedProgramInfo* LinkInfo() const {
-        return mMostRecentLinkInfo.get();
-    }
+    /* Returns the uniform array size (or 1 if the uniform is not an array) of
+     * the uniform with given mapped identifier.
+     *
+     * Note: The input string |name| is the mapped identifier, not the original
+     * identifier.
+     */
+    WebGLUniformInfo GetUniformInfoForMappedIdentifier(const nsACString& name);
 
     WebGLContext* GetParentObject() const {
         return Context();
     }
 
-    virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
+    virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
+
+    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLProgram)
+    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLProgram)
 
-private:
+    // public post-link data
+    std::map<GLint, nsCString> mActiveAttribMap;
+
+    static uint64_t IdentifierHashFunction(const char* ident, size_t size);
+    static void HashMapIdentifier(const nsACString& name,
+                                  nsCString* const out_hashedName);
+
+protected:
     ~WebGLProgram() {
         DeleteOnce();
     }
 
-    bool LinkAndUpdate();
-
-public:
-    const GLuint mGLName;
+    GLuint mGLName;
+    bool mLinkStatus;
+    // attached shaders of the program object
+    nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders;
+    CheckedUint32 mGeneration;
 
-private:
-    WebGLRefPtr<WebGLShader> mVertShader;
-    WebGLRefPtr<WebGLShader> mFragShader;
-    std::map<nsCString, GLuint> mBoundAttribLocs;
-    nsCString mLinkLog;
-    RefPtr<const webgl::LinkedProgramInfo> mMostRecentLinkInfo;
+    // post-link data
+    FallibleTArray<bool> mAttribsInUse;
+    nsAutoPtr<CStringMap> mIdentifierMap, mIdentifierReverseMap;
+    nsAutoPtr<CStringToUniformInfoMap> mUniformInfoMap;
+    int mAttribMaxNameLength;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_PROGRAM_H_
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -4,384 +4,61 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLShader.h"
 
 #include "angle/ShaderLang.h"
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "mozilla/MemoryReporting.h"
-#include "nsPrintfCString.h"
-#include "nsString.h"
 #include "WebGLContext.h"
 #include "WebGLObjectModel.h"
-#include "WebGLShaderValidator.h"
-#include "WebGLValidateStrings.h"
 
 namespace mozilla {
 
-// On success, writes to out_validator and out_translatedSource.
-// On failure, writes to out_translationLog.
-static bool
-Translate(const nsACString& source, webgl::ShaderValidator* validator,
-          nsACString* const out_translationLog, nsACString* const out_translatedSource)
-{
-    if (!validator->ValidateAndTranslate(source.BeginReading())) {
-        validator->GetInfoLog(out_translationLog);
-        return false;
-    }
-
-    // Success
-    validator->GetOutput(out_translatedSource);
-    return true;
-}
-
-template<size_t N>
-static bool
-SubstringStartsWith(const std::string& testStr, size_t offset, const char (& refStr)[N])
-{
-    for (size_t i = 0; i < N-1; i++) {
-        if (testStr[offset + i] != refStr[i])
-            return false;
-    }
-    return true;
-}
-
-/* On success, writes to out_translatedSource.
- * On failure, writes to out_translationLog.
- *
- * Requirements:
- *   #version is either omitted, `#version 100`, or `version 300 es`.
- */
-static bool
-TranslateWithoutValidation(const nsACString& sourceNS, bool isWebGL2,
-                           nsACString* const out_translationLog,
-                           nsACString* const out_translatedSource)
-{
-    std::string source = sourceNS.BeginReading();
-
-    size_t versionStrStart = source.find("#version");
-    size_t versionStrLen;
-    uint32_t glesslVersion;
-
-    if (versionStrStart != std::string::npos) {
-        static const char versionStr100[] = "#version 100\n";
-        static const char versionStr300es[] = "#version 300 es\n";
-
-        if (isWebGL2 && SubstringStartsWith(source, versionStrStart, versionStr300es)) {
-            glesslVersion = 300;
-            versionStrLen = strlen(versionStr300es);
-
-        } else if (SubstringStartsWith(source, versionStrStart, versionStr100)) {
-            glesslVersion = 100;
-            versionStrLen = strlen(versionStr100);
-
-        } else {
-            nsPrintfCString error("#version, if declared, must be %s.",
-                                  isWebGL2 ? "`100` or `300 es`"
-                                           : "`100`");
-            *out_translationLog = error;
-            return false;
-        }
-    } else {
-        versionStrStart = 0;
-        versionStrLen = 0;
-        glesslVersion = 100;
-    }
-
-    std::string reversionedSource = source;
-    reversionedSource.erase(versionStrStart, versionStrLen);
-
-    switch (glesslVersion) {
-    case 100:
-        break;
-    case 300:
-        reversionedSource.insert(versionStrStart, "#version 330\n");
-        break;
-    default:
-        MOZ_CRASH("Bad `glesslVersion`.");
-    }
-
-    out_translatedSource->Assign(reversionedSource.c_str(),
-                                 reversionedSource.length());
-    return true;
-}
-
-static void
-GetCompilationStatusAndLog(gl::GLContext* gl, GLuint shader, bool* const out_success,
-                           nsACString* const out_log)
-{
-    GLint compileStatus = LOCAL_GL_FALSE;
-    gl->fGetShaderiv(shader, LOCAL_GL_COMPILE_STATUS, &compileStatus);
-
-    // It's simpler if we always get the log.
-    GLint lenWithNull = 0;
-    gl->fGetShaderiv(shader, LOCAL_GL_INFO_LOG_LENGTH, &lenWithNull);
-
-    if (lenWithNull > 1) {
-        // SetLength takes the length without the null.
-        out_log->SetLength(lenWithNull - 1);
-        gl->fGetShaderInfoLog(shader, lenWithNull, nullptr, out_log->BeginWriting());
-    } else {
-        out_log->SetLength(0);
-    }
-
-    *out_success = (compileStatus == LOCAL_GL_TRUE);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-static GLuint
-CreateShader(gl::GLContext* gl, GLenum type)
-{
-    gl->MakeCurrent();
-    return gl->fCreateShader(type);
+JSObject*
+WebGLShader::WrapObject(JSContext* cx) {
+    return dom::WebGLShaderBinding::Wrap(cx, this);
 }
 
 WebGLShader::WebGLShader(WebGLContext* webgl, GLenum type)
     : WebGLContextBoundObject(webgl)
-    , mGLName(CreateShader(webgl->GL(), type))
     , mType(type)
-{
-    mContext->mShaders.insertBack(this);
-}
-
-WebGLShader::~WebGLShader()
-{
-    DeleteOnce();
-}
-
-void
-WebGLShader::ShaderSource(const nsAString& source)
+    , mNeedsTranslation(true)
+    , mAttribMaxNameLength(0)
+    , mCompileStatus(false)
 {
-    StripComments stripComments(source);
-    const nsAString& cleanSource = Substring(stripComments.result().Elements(),
-                                             stripComments.length());
-    if (!ValidateGLSLString(cleanSource, mContext, "shaderSource"))
-        return;
-
-    // We checked that the source stripped of comments is in the
-    // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
-    NS_LossyConvertUTF16toASCII sourceCString(cleanSource);
-
-    if (mContext->gl->WorkAroundDriverBugs()) {
-        const size_t maxSourceLength = 0x3ffff;
-        if (sourceCString.Length() > maxSourceLength) {
-            mContext->ErrorInvalidValue("shaderSource: Source has more than %d"
-                                        " characters. (Driver workaround)",
-                                        maxSourceLength);
-            return;
-        }
-    }
-
-    // HACK - dump shader source
-    {
-/*
-        printf_stderr("//-*- glsl -*-\n");
-        // Wow - Roll Your Own For Each Lines because printf_stderr has a hard-coded internal size, so long strings are truncated.
-        const nsString& src = shader->Source();
-        int32_t start = 0;
-        int32_t end = src.Find("\n", false, start, -1);
-        while (end > -1) {
-            printf_stderr("%s\n", NS_ConvertUTF16toUTF8(nsDependentSubstring(src, start, end - start)).get());
-            start = end + 1;
-            end = src.Find("\n", false, start, -1);
-        }
-        printf_stderr("//\n");
-*/
-    }
-    // HACK
-
-    mSource = source;
-    mCleanSource = sourceCString;
-}
-
-void
-WebGLShader::CompileShader()
-{
-    mValidator = nullptr;
-    mTranslationSuccessful = false;
-    mCompilationSuccessful = false;
-
-    gl::GLContext* gl = mContext->gl;
-
-    mValidator.reset(mContext->CreateShaderValidator(mType));
-
-    bool success;
-    if (mValidator) {
-        success = Translate(mCleanSource, mValidator.get(), &mValidationLog,
-                            &mTranslatedSource);
-    } else {
-        success = TranslateWithoutValidation(mCleanSource, mContext->IsWebGL2(),
-                                             &mValidationLog, &mTranslatedSource);
-    }
-
-    if (!success)
-        return;
-
-    mTranslationSuccessful = true;
-
-    gl->MakeCurrent();
-
-    const char* const parts[] = {
-        mTranslatedSource.BeginReading()
-    };
-    gl->fShaderSource(mGLName, ArrayLength(parts), parts, nullptr);
-
-    gl->fCompileShader(mGLName);
-
-    GetCompilationStatusAndLog(gl, mGLName, &mCompilationSuccessful, &mCompilationLog);
+    mContext->MakeContextCurrent();
+    mGLName = mContext->gl->fCreateShader(mType);
+    mContext->mShaders.insertBack(this);
 }
 
 void
-WebGLShader::GetShaderInfoLog(nsAString* out) const
-{
-    const nsCString& log = !mTranslationSuccessful ? mValidationLog
-                                                   : mCompilationLog;
-    CopyASCIItoUTF16(log, *out);
-}
-
-JS::Value
-WebGLShader::GetShaderParameter(GLenum pname) const
-{
-    switch (pname) {
-    case LOCAL_GL_SHADER_TYPE:
-        return JS::NumberValue(mType);
-
-    case LOCAL_GL_DELETE_STATUS:
-        return JS::BooleanValue(IsDeleteRequested());
-
-    case LOCAL_GL_COMPILE_STATUS:
-        return JS::BooleanValue(mCompilationSuccessful);
-
-    default:
-        mContext->ErrorInvalidEnumInfo("getShaderParameter: `pname`", pname);
-        return JS::NullValue();
-    }
-}
-
-void
-WebGLShader::GetShaderSource(nsAString* out) const
-{
-    out->SetIsVoid(false);
-    *out = mSource;
-}
-
-void
-WebGLShader::GetShaderTranslatedSource(nsAString* out) const
-{
-    if (!mCompilationSuccessful) {
-        mContext->ErrorInvalidOperation("getShaderTranslatedSource: Shader has"
-                                        " not been successfully compiled.");
-        return;
-    }
-
-    out->SetIsVoid(false);
-    CopyASCIItoUTF16(mTranslatedSource, *out);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool
-WebGLShader::CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const
-{
-    if (!mValidator)
-        return true;
-
-    return mValidator->CanLinkTo(prev->mValidator.get(), out_log);
-}
-
-size_t
-WebGLShader::CalcNumSamplerUniforms() const
+WebGLShader::Delete()
 {
-    if (mValidator)
-        return mValidator->CalcNumSamplerUniforms();
-
-    // TODO
-    return 0;
-}
-
-void
-WebGLShader::BindAttribLocation(GLuint prog, const nsCString& userName,
-                                GLuint index) const
-{
-    std::string userNameStr(userName.BeginReading());
-
-    const std::string* mappedNameStr = &userNameStr;
-    if (mValidator)
-        mValidator->FindAttribMappedNameByUserName(userNameStr, &mappedNameStr);
-
-    mContext->gl->fBindAttribLocation(prog, index, mappedNameStr->c_str());
-}
-
-bool
-WebGLShader::FindAttribUserNameByMappedName(const nsACString& mappedName,
-                                            nsDependentCString* const out_userName) const
-{
-    if (!mValidator)
-        return false;
-
-    const std::string mappedNameStr(mappedName.BeginReading());
-    const std::string* userNameStr;
-    if (!mValidator->FindAttribUserNameByMappedName(mappedNameStr, &userNameStr))
-        return false;
-
-    out_userName->Rebind(userNameStr->c_str());
-    return true;
-}
-
-bool
-WebGLShader::FindUniformByMappedName(const nsACString& mappedName,
-                                     nsCString* const out_userName,
-                                     bool* const out_isArray) const
-{
-    if (!mValidator)
-        return false;
-
-    const std::string mappedNameStr(mappedName.BeginReading(), mappedName.Length());
-    std::string userNameStr;
-    if (!mValidator->FindUniformByMappedName(mappedNameStr, &userNameStr, out_isArray))
-        return false;
-
-    *out_userName = userNameStr.c_str();
-    return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Boilerplate
-
-JSObject*
-WebGLShader::WrapObject(JSContext* js)
-{
-    return dom::WebGLShaderBinding::Wrap(js, this);
+    mSource.Truncate();
+    mTranslationLog.Truncate();
+    mContext->MakeContextCurrent();
+    mContext->gl->fDeleteShader(mGLName);
+    LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders);
 }
 
 size_t
 WebGLShader::SizeOfIncludingThis(MallocSizeOf mallocSizeOf) const
 {
-    size_t validatorSize = mValidator ? mallocSizeOf(mValidator.get())
-                                      : 0;
     return mallocSizeOf(this) +
            mSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
-           mCleanSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
-           validatorSize +
-           mValidationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
-           mTranslatedSource.SizeOfExcludingThisIfUnshared(mallocSizeOf) +
-           mCompilationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
+           mTranslationLog.SizeOfExcludingThisIfUnshared(mallocSizeOf);
 }
 
 void
-WebGLShader::Delete()
+WebGLShader::SetTranslationSuccess()
 {
-    gl::GLContext* gl = mContext->GL();
-
-    gl->MakeCurrent();
-    gl->fDeleteShader(mGLName);
-
-    LinkedListElement<WebGLShader>::removeFrom(mContext->mShaders);
+    mTranslationLog.SetIsVoid(true);
+    mNeedsTranslation = false;
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLShader)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLShader, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLShader, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -1,88 +1,106 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_SHADER_H_
 #define WEBGL_SHADER_H_
 
-#include "GLDefs.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsWrapperCache.h"
 #include "WebGLObjectModel.h"
+#include "WebGLUniformInfo.h"
 
 namespace mozilla {
 
-namespace webgl {
-class ShaderValidator;
-} // namespace webgl
+struct WebGLMappedIdentifier
+{
+    // ASCII strings
+    nsCString original;
+    nsCString mapped;
+
+    WebGLMappedIdentifier(const nsACString& o, const nsACString& m)
+        : original(o)
+        , mapped(m)
+    {}
+};
 
 class WebGLShader MOZ_FINAL
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLShader>
     , public LinkedListElement<WebGLShader>
     , public WebGLContextBoundObject
 {
     friend class WebGLContext;
     friend class WebGLProgram;
 
 public:
     WebGLShader(WebGLContext* webgl, GLenum type);
 
-protected:
-    ~WebGLShader();
+    size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
-public:
-    // GL funcs
-    void CompileShader();
-    JS::Value GetShaderParameter(GLenum pname) const;
-    void GetShaderInfoLog(nsAString* out) const;
-    void GetShaderSource(nsAString* out) const;
-    void GetShaderTranslatedSource(nsAString* out) const;
-    void ShaderSource(const nsAString& source);
+    GLuint GLName() { return mGLName; }
+    sh::GLenum ShaderType() { return mType; }
 
-    // Util funcs
-    bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
-    size_t CalcNumSamplerUniforms() const;
-    void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
-    bool FindAttribUserNameByMappedName(const nsACString& mappedName,
-                                        nsDependentCString* const out_userName) const;
-    bool FindUniformByMappedName(const nsACString& mappedName,
-                                 nsCString* const out_userName,
-                                 bool* const out_isArray) const;
+    void SetSource(const nsAString& src) {
+        // TODO: Do some quick gzip here maybe? Getting this will be very rare,
+        // and we have to keep it forever.
+        mSource.Assign(src);
+    }
 
-    bool IsCompiled() const {
-        return mTranslationSuccessful && mCompilationSuccessful;
+    const nsString& Source() const { return mSource; }
+
+    void SetNeedsTranslation() { mNeedsTranslation = true; }
+    bool NeedsTranslation() const { return mNeedsTranslation; }
+
+    void SetCompileStatus (bool status) {
+        mCompileStatus = status;
     }
 
-    // Other funcs
-    size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
     void Delete();
 
-    WebGLContext* GetParentObject() const { return Context(); }
+    bool CompileStatus() const {
+        return mCompileStatus;
+    }
+
+    void SetTranslationSuccess();
+
+    void SetTranslationFailure(const nsCString& msg) {
+        mTranslationLog.Assign(msg);
+    }
 
-    virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
+    const nsCString& TranslationLog() const { return mTranslationLog; }
+
+    const nsString& TranslatedSource() const { return mTranslatedSource; }
+
+    WebGLContext* GetParentObject() const {
+        return Context();
+    }
+
+    virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLShader)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLShader)
 
-public:
-    const GLuint mGLName;
-    const GLenum mType;
 protected:
-    nsString mSource;
-    nsCString mCleanSource;
+    ~WebGLShader() {
+        DeleteOnce();
+    }
 
-    UniquePtr<webgl::ShaderValidator> mValidator;
-    nsCString mValidationLog;
-    bool mTranslationSuccessful;
-    nsCString mTranslatedSource;
-
-    bool mCompilationSuccessful;
-    nsCString mCompilationLog;
+    GLuint mGLName;
+    GLenum mType;
+    nsString mSource;
+    nsString mTranslatedSource;
+    nsCString mTranslationLog; // The translation log should contain only ASCII characters
+    bool mNeedsTranslation;
+    nsTArray<WebGLMappedIdentifier> mAttributes;
+    nsTArray<WebGLMappedIdentifier> mUniforms;
+    nsTArray<WebGLUniformInfo> mUniformInfos;
+    int mAttribMaxNameLength;
+    bool mCompileStatus;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_SHADER_H_
deleted file mode 100644
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "WebGLShaderValidator.h"
-
-#include "angle/ShaderLang.h"
-#include "GLContext.h"
-#include "MurmurHash3.h"
-#include "nsPrintfCString.h"
-#include <string>
-#include <vector>
-#include "WebGLContext.h"
-
-namespace mozilla {
-namespace webgl {
-
-uint64_t
-IdentifierHashFunc(const char* name, size_t len)
-{
-    // NB: we use the x86 function everywhere, even though it's suboptimal perf
-    // on x64.  They return different results; not sure if that's a requirement.
-    uint64_t hash[2];
-    MurmurHash3_x86_128(name, len, 0, hash);
-    return hash[0];
-}
-
-static int
-ChooseValidatorCompileOptions(const ShBuiltInResources& resources,
-                              const mozilla::gl::GLContext* gl)
-{
-    int options = SH_VARIABLES |
-                  SH_ENFORCE_PACKING_RESTRICTIONS |
-                  SH_INIT_VARYINGS_WITHOUT_STATIC_USE |
-                  SH_OBJECT_CODE |
-                  SH_LIMIT_CALL_STACK_DEPTH;
-
-    if (resources.MaxExpressionComplexity > 0) {
-        options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
-    }
-
-#ifndef XP_MACOSX
-    // We want to do this everywhere, but to do this on Mac, we need
-    // to do it only on Mac OSX > 10.6 as this causes the shader
-    // compiler in 10.6 to crash
-    options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
-#endif
-
-#ifdef XP_MACOSX
-    if (gl->WorkAroundDriverBugs()) {
-        // Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
-        // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
-        options |= SH_UNFOLD_SHORT_CIRCUIT;
-
-        // Work around bug 665578 and bug 769810
-        if (gl->Vendor() == gl::GLVendor::ATI) {
-            options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
-        }
-
-        // Work around bug 735560
-        if (gl->Vendor() == gl::GLVendor::Intel) {
-            options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
-        }
-
-        // Work around bug 636926
-        if (gl->Vendor() == gl::GLVendor::NVIDIA) {
-            options |= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX;
-        }
-    }
-#endif
-
-    return options;
-}
-
-} // namespace webgl
-
-////////////////////////////////////////
-
-webgl::ShaderValidator*
-WebGLContext::CreateShaderValidator(GLenum shaderType) const
-{
-    if (mBypassShaderValidation)
-        return nullptr;
-
-    ShShaderSpec spec = SH_WEBGL_SPEC;
-    ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT
-                                                 : SH_GLSL_OUTPUT;
-
-    ShBuiltInResources resources;
-    memset(&resources, 0, sizeof(resources));
-    ShInitBuiltInResources(&resources);
-
-    resources.HashFunction = webgl::IdentifierHashFunc;
-
-    resources.MaxVertexAttribs = mGLMaxVertexAttribs;
-    resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
-    resources.MaxVaryingVectors = mGLMaxVaryingVectors;
-    resources.MaxVertexTextureImageUnits = mGLMaxVertexTextureImageUnits;
-    resources.MaxCombinedTextureImageUnits = mGLMaxTextureUnits;
-    resources.MaxTextureImageUnits = mGLMaxTextureImageUnits;
-    resources.MaxFragmentUniformVectors = mGLMaxFragmentUniformVectors;
-    resources.MaxDrawBuffers = mGLMaxDrawBuffers;
-
-    if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth))
-        resources.EXT_frag_depth = 1;
-
-    if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives))
-        resources.OES_standard_derivatives = 1;
-
-    if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers))
-        resources.EXT_draw_buffers = 1;
-
-    if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod))
-        resources.EXT_shader_texture_lod = 1;
-
-    // Tell ANGLE to allow highp in frag shaders. (unless disabled)
-    // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
-    resources.FragmentPrecisionHigh = mDisableFragHighP ? 0 : 1;
-
-    if (gl->WorkAroundDriverBugs()) {
-#ifdef XP_MACOSX
-        if (gl->Vendor() == gl::GLVendor::NVIDIA) {
-            // Work around bug 890432
-            resources.MaxExpressionComplexity = 1000;
-        }
-#endif
-    }
-
-    int compileOptions = webgl::ChooseValidatorCompileOptions(resources, gl);
-
-    return webgl::ShaderValidator::Create(shaderType, spec, outputLanguage, resources,
-                                          compileOptions);
-}
-
-////////////////////////////////////////
-
-namespace webgl {
-
-/*static*/ ShaderValidator*
-ShaderValidator::Create(GLenum shaderType, ShShaderSpec spec,
-                        ShShaderOutput outputLanguage,
-                        const ShBuiltInResources& resources, int compileOptions)
-{
-    ShHandle handle = ShConstructCompiler(shaderType, spec, outputLanguage, &resources);
-    if (!handle)
-        return nullptr;
-
-    return new ShaderValidator(handle, compileOptions);
-}
-
-ShaderValidator::~ShaderValidator()
-{
-    ShDestruct(mHandle);
-}
-
-bool
-ShaderValidator::ValidateAndTranslate(const char* source)
-{
-    MOZ_ASSERT(!mHasRun);
-    mHasRun = true;
-
-    const char* const parts[] = {
-        source
-    };
-    return ShCompile(mHandle, parts, ArrayLength(parts), mCompileOptions);
-}
-
-void
-ShaderValidator::GetInfo(ShShaderInfo pname, size_t* params) const
-{
-    MOZ_ASSERT(mHasRun);
-
-    ShGetInfo(mHandle, pname, params);
-}
-
-void
-ShaderValidator::GetInfoLog(nsACString* out) const
-{
-    MOZ_ASSERT(mHasRun);
-
-    size_t lenWithNull = 0;
-    GetInfo(SH_INFO_LOG_LENGTH, &lenWithNull);
-    MOZ_ASSERT(lenWithNull >= 1);
-
-    // SetLength allocates len+1, for the null-term.
-    out->SetLength(lenWithNull - 1);
-
-    ShGetInfoLog(mHandle, out->BeginWriting());
-}
-
-void
-ShaderValidator::GetOutput(nsACString* out) const
-{
-    MOZ_ASSERT(mHasRun);
-
-    size_t lenWithNull = 0;
-    GetInfo(SH_OBJECT_CODE_LENGTH, &lenWithNull);
-    MOZ_ASSERT(lenWithNull >= 1);
-
-    // SetLength allocates len+1, for the null-term.
-    out->SetLength(lenWithNull - 1);
-
-    ShGetObjectCode(mHandle, out->BeginWriting());
-}
-
-template<size_t N>
-static bool
-StartsWith(const std::string& haystack, const char (&needle)[N])
-{
-    return haystack.compare(0, N - 1, needle) == 0;
-}
-
-bool
-ShaderValidator::CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const
-{
-    {
-        const std::vector<sh::Uniform>& vertList = *ShGetUniforms(prev->mHandle);
-        const std::vector<sh::Uniform>& fragList = *ShGetUniforms(mHandle);
-
-        for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
-            for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
-                if (itrVert->name != itrFrag->name)
-                    continue;
-
-                if (!itrVert->isSameUniformAtLinkTime(*itrFrag)) {
-                    nsPrintfCString error("Uniform `%s`is not linkable between"
-                                          " attached shaders.",
-                                          itrFrag->name.c_str());
-                    *out_log = error;
-                    return false;
-                }
-
-                break;
-            }
-        }
-    }
-    {
-        const std::vector<sh::Varying>& vertList = *ShGetVaryings(prev->mHandle);
-        const std::vector<sh::Varying>& fragList = *ShGetVaryings(mHandle);
-
-        for (auto itrFrag = fragList.begin(); itrFrag != fragList.end(); ++itrFrag) {
-            static const char prefix[] = "gl_";
-            if (StartsWith(itrFrag->name, prefix))
-                continue;
-
-            bool definedInVertShader = false;
-
-            for (auto itrVert = vertList.begin(); itrVert != vertList.end(); ++itrVert) {
-                if (itrVert->name != itrFrag->name)
-                    continue;
-
-                if (!itrVert->isSameVaryingAtLinkTime(*itrFrag)) {
-                    nsPrintfCString error("Varying `%s`is not linkable between"
-                                          " attached shaders.",
-                                          itrFrag->name.c_str());
-                    *out_log = error;
-                    return false;
-                }
-
-                definedInVertShader = true;
-                break;
-            }
-
-            if (!definedInVertShader && itrFrag->staticUse) {
-                nsPrintfCString error("Varying `%s` has static-use in the frag"
-                                      " shader, but is undeclared in the vert"
-                                      " shader.", itrFrag->name.c_str());
-                *out_log = error;
-                return false;
-            }
-        }
-    }
-
-    return true;
-}
-
-size_t
-ShaderValidator::CalcNumSamplerUniforms() const
-{
-    size_t accum = 0;
-
-    const std::vector<sh::Uniform>& uniforms = *ShGetUniforms(mHandle);
-
-    for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) {
-        GLenum type = itr->type;
-        if (type == LOCAL_GL_SAMPLER_2D ||
-            type == LOCAL_GL_SAMPLER_CUBE)
-        {
-            accum += itr->arraySize;
-        }
-    }
-
-    return accum;
-}
-
-// Attribs cannot be structs or arrays, and neither can vertex inputs in ES3.
-// Therefore, attrib names are always simple.
-bool
-ShaderValidator::FindAttribUserNameByMappedName(const std::string& mappedName,
-                                                const std::string** const out_userName) const
-{
-    const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
-    for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
-        if (itr->mappedName == mappedName) {
-            *out_userName = &(itr->name);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-bool
-ShaderValidator::FindAttribMappedNameByUserName(const std::string& userName,
-                                                const std::string** const out_mappedName) const
-{
-    const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
-    for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
-        if (itr->name == userName) {
-            *out_mappedName = &(itr->mappedName);
-            return true;
-        }
-    }
-
-    return false;
-}
-
-// This must handle names like "foo.bar[0]".
-bool
-ShaderValidator::FindUniformByMappedName(const std::string& mappedName,
-                                         std::string* const out_userName,
-                                         bool* const out_isArray) const
-{
-    const std::vector<sh::Uniform>& uniforms = *ShGetUniforms(mHandle);
-    for (auto itr = uniforms.begin(); itr != uniforms.end(); ++itr) {
-        const sh::ShaderVariable* found;
-        if (!itr->findInfoByMappedName(mappedName, &found, out_userName))
-            continue;
-
-        *out_isArray = found->isArray();
-        return true;
-    }
-
-    return false;
-}
-
-} // namespace webgl
-} // namespace mozilla
deleted file mode 100644
--- a/dom/canvas/WebGLShaderValidator.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef WEBGL_SHADER_VALIDATOR_H_
-#define WEBGL_SHADER_VALIDATOR_H_
-
-#include "angle/ShaderLang.h"
-#include "GLDefs.h"
-#include "nsString.h"
-#include <string>
-
-namespace mozilla {
-namespace webgl {
-
-class ShaderValidator MOZ_FINAL
-{
-    const ShHandle mHandle;
-    const int mCompileOptions;
-    bool mHasRun;
-
-public:
-    static ShaderValidator* Create(GLenum shaderType, ShShaderSpec spec,
-                                   ShShaderOutput outputLanguage,
-                                   const ShBuiltInResources& resources,
-                                   int compileOptions);
-
-private:
-    ShaderValidator(ShHandle handle, int compileOptions)
-        : mHandle(handle)
-        , mCompileOptions(compileOptions)
-        , mHasRun(false)
-    { }
-
-public:
-    ~ShaderValidator();
-
-    bool ValidateAndTranslate(const char* source);
-    void GetInfo(ShShaderInfo pname, size_t* params) const;
-    void GetInfoLog(nsACString* out) const;
-    void GetOutput(nsACString* out) const;
-    bool CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const;
-    size_t CalcNumSamplerUniforms() const;
-
-    bool FindAttribUserNameByMappedName(const std::string& mappedName,
-                                        const std::string** const out_userName) const;
-
-    bool FindAttribMappedNameByUserName(const std::string& userName,
-                                        const std::string** const out_mappedName) const;
-
-    bool FindUniformByMappedName(const std::string& mappedName,
-                                 std::string* const out_userName,
-                                 bool* const out_isArray) const;
-};
-
-} // namespace webgl
-} // namespace mozilla
-
-#endif // WEBGL_SHADER_VALIDATOR_H_
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLUniformInfo.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WEBGLUNIFORMINFO_H_
+#define WEBGLUNIFORMINFO_H_
+
+#include "GLDefs.h"
+#include "angle/ShaderLang.h"
+
+namespace mozilla {
+
+struct WebGLUniformInfo {
+    uint32_t arraySize;
+    bool isArray;
+    sh::GLenum type;
+
+    explicit WebGLUniformInfo(uint32_t s = 0, bool a = false, sh::GLenum t = LOCAL_GL_NONE)
+        : arraySize(s), isArray(a), type(t) {}
+
+    int ElementSize() const {
+        switch (type) {
+            case LOCAL_GL_FLOAT:
+            case LOCAL_GL_INT:
+            case LOCAL_GL_UNSIGNED_INT:
+            case LOCAL_GL_BOOL:
+            case LOCAL_GL_SAMPLER_2D:
+            case LOCAL_GL_SAMPLER_3D:
+            case LOCAL_GL_SAMPLER_CUBE:
+            case LOCAL_GL_SAMPLER_2D_SHADOW:
+            case LOCAL_GL_SAMPLER_2D_ARRAY:
+            case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
+            case LOCAL_GL_SAMPLER_CUBE_SHADOW:
+            case LOCAL_GL_INT_SAMPLER_2D:
+            case LOCAL_GL_INT_SAMPLER_3D:
+            case LOCAL_GL_INT_SAMPLER_CUBE:
+            case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
+            case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
+            case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
+            case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
+            case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+                return 1;
+            case LOCAL_GL_FLOAT_VEC2:
+            case LOCAL_GL_INT_VEC2:
+            case LOCAL_GL_UNSIGNED_INT_VEC2:
+            case LOCAL_GL_BOOL_VEC2:
+                return 2;
+            case LOCAL_GL_FLOAT_VEC3:
+            case LOCAL_GL_INT_VEC3:
+            case LOCAL_GL_UNSIGNED_INT_VEC3:
+            case LOCAL_GL_BOOL_VEC3:
+                return 3;
+            case LOCAL_GL_FLOAT_VEC4:
+            case LOCAL_GL_INT_VEC4:
+            case LOCAL_GL_UNSIGNED_INT_VEC4:
+            case LOCAL_GL_BOOL_VEC4:
+            case LOCAL_GL_FLOAT_MAT2:
+                return 4;
+            case LOCAL_GL_FLOAT_MAT2x3:
+            case LOCAL_GL_FLOAT_MAT3x2:
+                return 6;
+            case LOCAL_GL_FLOAT_MAT2x4:
+            case LOCAL_GL_FLOAT_MAT4x2:
+                return 8;
+            case LOCAL_GL_FLOAT_MAT3:
+                return 9;
+            case LOCAL_GL_FLOAT_MAT3x4:
+            case LOCAL_GL_FLOAT_MAT4x3:
+                return 12;
+            case LOCAL_GL_FLOAT_MAT4:
+                return 16;
+            default:
+                MOZ_ASSERT(false); // should never get here
+                return 0;
+        }
+    }
+};
+
+} // namespace mozilla
+
+#endif
--- a/dom/canvas/WebGLUniformLocation.cpp
+++ b/dom/canvas/WebGLUniformLocation.cpp
@@ -1,278 +1,39 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGLUniformLocation.h"
 
-#include "GLContext.h"
-#include "mozilla/dom/ToJSValue.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
-#include "WebGLActiveInfo.h"
 #include "WebGLContext.h"
 #include "WebGLProgram.h"
+#include "WebGLShader.h"
 
 namespace mozilla {
 
-WebGLUniformLocation::WebGLUniformLocation(WebGLContext* webgl,
-                                           const webgl::LinkedProgramInfo* linkInfo,
-                                           GLuint loc, const WebGLActiveInfo* activeInfo)
-    : WebGLContextBoundObject(webgl)
-    , mLinkInfo(linkInfo)
-    , mLoc(loc)
-    , mActiveInfo(activeInfo)
-{ }
-
-WebGLUniformLocation::~WebGLUniformLocation()
-{ }
-
-bool
-WebGLUniformLocation::ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
-                                         const char* funcName) const
-{
-    // Check the weak-pointer.
-    if (!mLinkInfo) {
-        webgl->ErrorInvalidOperation("%s: This uniform location is obsolete because its"
-                                     " program has been successfully relinked.",
-                                     funcName);
-        return false;
-    }
-
-    if (mLinkInfo->prog != prog) {
-        webgl->ErrorInvalidOperation("%s: This uniform location corresponds to a"
-                                     " different program.", funcName);
-        return false;
-    }
-
-    return true;
-}
-
-static bool
-IsUniformSetterTypeValid(GLenum setterType, GLenum uniformType)
+JSObject*
+WebGLUniformLocation::WrapObject(JSContext* cx)
 {
-    switch (uniformType) {
-    case LOCAL_GL_BOOL:
-    case LOCAL_GL_BOOL_VEC2:
-    case LOCAL_GL_BOOL_VEC3:
-    case LOCAL_GL_BOOL_VEC4:
-        return setterType == LOCAL_GL_INT ||
-               setterType == LOCAL_GL_FLOAT; // GLfloat(0.0) sets a bool to false.
-
-    case LOCAL_GL_INT:
-    case LOCAL_GL_INT_SAMPLER_2D:
-    case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_INT_SAMPLER_3D:
-    case LOCAL_GL_INT_SAMPLER_CUBE:
-    case LOCAL_GL_INT_VEC2:
-    case LOCAL_GL_INT_VEC3:
-    case LOCAL_GL_INT_VEC4:
-    case LOCAL_GL_SAMPLER_2D:
-    case LOCAL_GL_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
-    case LOCAL_GL_SAMPLER_2D_SHADOW:
-    case LOCAL_GL_SAMPLER_CUBE:
-    case LOCAL_GL_SAMPLER_CUBE_SHADOW:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
-        return setterType == LOCAL_GL_INT;
-
-    case LOCAL_GL_FLOAT:
-    case LOCAL_GL_FLOAT_MAT2:
-    case LOCAL_GL_FLOAT_MAT2x3:
-    case LOCAL_GL_FLOAT_MAT2x4:
-    case LOCAL_GL_FLOAT_MAT3:
-    case LOCAL_GL_FLOAT_MAT3x2:
-    case LOCAL_GL_FLOAT_MAT3x4:
-    case LOCAL_GL_FLOAT_MAT4:
-    case LOCAL_GL_FLOAT_MAT4x2:
-    case LOCAL_GL_FLOAT_MAT4x3:
-    case LOCAL_GL_FLOAT_VEC2:
-    case LOCAL_GL_FLOAT_VEC3:
-    case LOCAL_GL_FLOAT_VEC4:
-        return setterType == LOCAL_GL_FLOAT;
-
-    default:
-        MOZ_CRASH("Bad `uniformType`.");
-    }
-}
-
-bool
-WebGLUniformLocation::ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
-                                          WebGLContext* webgl, const char* funcName) const
-{
-    MOZ_ASSERT(mLinkInfo);
-
-    if (setterElemSize != mActiveInfo->mElemSize) {
-        webgl->ErrorInvalidOperation("%s: Bad uniform size: %i", funcName,
-                                     mActiveInfo->mElemSize);
-        return false;
-    }
-
-    if (!IsUniformSetterTypeValid(setterType, mActiveInfo->mElemType)) {
-        webgl->ErrorInvalidOperation("%s: Bad uniform type: %i", funcName,
-                                     mActiveInfo->mElemSize);
-        return false;
-    }
-
-    return true;
+    return dom::WebGLUniformLocationBinding::Wrap(cx, this);
 }
 
-bool
-WebGLUniformLocation::ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
-                                          WebGLContext* webgl, const char* funcName) const
+WebGLUniformLocation::WebGLUniformLocation(WebGLContext* context,
+                                           WebGLProgram* program,
+                                           GLint location,
+                                           const WebGLUniformInfo& info)
+    : WebGLContextBoundObject(context)
+    , mProgram(program)
+    , mProgramGeneration(program->Generation())
+    , mLocation(location)
+    , mInfo(info)
 {
-    MOZ_ASSERT(mLinkInfo);
-
-    if (setterArraySize == 0 ||
-        setterArraySize % setterElemSize)
-    {
-        webgl->ErrorInvalidValue("%s: expected an array of length a multiple of"
-                                 " %d, got an array of length %d.",
-                                 funcName, setterElemSize, setterArraySize);
-        return false;
-    }
-
-    /* GLES 2.0.25, Section 2.10, p38
-     *   When loading `N` elements starting at an arbitrary position `k` in a uniform
-     *   declared as an array, elements `k` through `k + N - 1` in the array will be
-     *   replaced with the new values. Values for any array element that exceeds the
-     *   highest array element index used, as reported by `GetActiveUniform`, will be
-     *   ignored by GL.
-     */
-    if (!mActiveInfo->mIsArray &&
-        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.",
-                                     funcName, setterElemSize, setterArraySize);
-        return false;
-    }
-
-    return true;
-}
-
-bool
-WebGLUniformLocation::ValidateSamplerSetter(GLint value, WebGLContext* webgl,
-                                            const char* funcName) const
-{
-    MOZ_ASSERT(mLinkInfo);
-
-    if (mActiveInfo->mElemType != LOCAL_GL_SAMPLER_2D &&
-        mActiveInfo->mElemType != LOCAL_GL_SAMPLER_CUBE)
-    {
-        return true;
-    }
-
-    if (value >= 0 && value < (GLint)webgl->GLMaxTextureUnits())
-        return true;
-
-    webgl->ErrorInvalidValue("%s: This uniform location is a sampler, but %d is not a"
-                             " valid texture unit.",
-                             funcName, value);
-    return false;
+    mElementSize = info.ElementSize();
 }
 
-JS::Value
-WebGLUniformLocation::GetUniform(JSContext* js, WebGLContext* webgl) const
-{
-    MOZ_ASSERT(mLinkInfo);
-
-    uint8_t elemSize = mActiveInfo->mElemSize;
-    static const uint8_t kMaxElemSize = 16;
-    MOZ_ASSERT(elemSize <= kMaxElemSize);
-
-    GLuint prog = mLinkInfo->prog->mGLName;
-
-    gl::GLContext* gl = webgl->GL();
-    gl->MakeCurrent();
-
-    switch (mActiveInfo->mElemType) {
-    case LOCAL_GL_INT:
-    case LOCAL_GL_INT_VEC2:
-    case LOCAL_GL_INT_VEC3:
-    case LOCAL_GL_INT_VEC4:
-    case LOCAL_GL_SAMPLER_2D:
-    case LOCAL_GL_SAMPLER_CUBE:
-        {
-            GLint buffer[kMaxElemSize] = {0};
-            gl->fGetUniformiv(prog, mLoc, buffer);
-
-            if (elemSize == 1)
-                return JS::Int32Value(buffer[0]);
-
-            JSObject* obj = dom::Int32Array::Create(js, webgl, elemSize, buffer);
-            if (!obj) {
-                webgl->ErrorOutOfMemory("getUniform: out of memory");
-                return JS::NullValue();
-            }
-            return JS::ObjectOrNullValue(obj);
-        }
-
-    case LOCAL_GL_BOOL:
-    case LOCAL_GL_BOOL_VEC2:
-    case LOCAL_GL_BOOL_VEC3:
-    case LOCAL_GL_BOOL_VEC4:
-        {
-            GLint buffer[kMaxElemSize] = {0};
-            gl->fGetUniformiv(prog, mLoc, buffer);
-
-            if (elemSize == 1)
-                return JS::BooleanValue(buffer[0]);
-
-            bool boolBuffer[kMaxElemSize];
-            for (uint8_t i = 0; i < kMaxElemSize; i++)
-                boolBuffer[i] = buffer[i];
-
-            JS::RootedValue val(js);
-            // Be careful: we don't want to convert all of |uv|!
-            if (!dom::ToJSValue(js, boolBuffer, elemSize, &val)) {
-                webgl->ErrorOutOfMemory("getUniform: out of memory");
-                return JS::NullValue();
-            }
-            return val;
-        }
-
-    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:
-        {
-            GLfloat buffer[16] = {0.0f};
-            gl->fGetUniformfv(prog, mLoc, buffer);
-
-            if (elemSize == 1)
-                return JS::DoubleValue(buffer[0]);
-
-            JSObject* obj = dom::Float32Array::Create(js, webgl, elemSize, buffer);
-            if (!obj) {
-                webgl->ErrorOutOfMemory("getUniform: out of memory");
-                return JS::NullValue();
-            }
-            return JS::ObjectOrNullValue(obj);
-        }
-
-    default:
-        MOZ_CRASH("Invalid elemType.");
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-JSObject*
-WebGLUniformLocation::WrapObject(JSContext* js)
-{
-    return dom::WebGLUniformLocationBinding::Wrap(js, this);
-}
-
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLUniformLocation)
+NS_IMPL_CYCLE_COLLECTION(WebGLUniformLocation, mProgram)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLUniformLocation, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLUniformLocation, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLUniformLocation.h
+++ b/dom/canvas/WebGLUniformLocation.h
@@ -1,63 +1,55 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_UNIFORM_LOCATION_H_
 #define WEBGL_UNIFORM_LOCATION_H_
 
-#include "GLDefs.h"
-#include "mozilla/WeakPtr.h"
-#include "nsWrapperCache.h"
 #include "WebGLObjectModel.h"
-
-struct JSContext;
+#include "WebGLUniformInfo.h"
 
 namespace mozilla {
-class WebGLActiveInfo;
-class WebGLContext;
+
 class WebGLProgram;
 
-namespace webgl {
-struct LinkedProgramInfo;
-}
-
 class WebGLUniformLocation MOZ_FINAL
-    : public nsWrapperCache
-    , public WebGLContextBoundObject
+    : public WebGLContextBoundObject
 {
 public:
-    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
-    NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLUniformLocation)
-
-    const WeakPtr<const webgl::LinkedProgramInfo> mLinkInfo;
-    const GLuint mLoc;
-    const WebGLActiveInfo* const mActiveInfo;
-
-    WebGLUniformLocation(WebGLContext* webgl, const webgl::LinkedProgramInfo* linkInfo,
-                         GLuint loc, const WebGLActiveInfo* activeInfo);
+    WebGLUniformLocation(WebGLContext* context, WebGLProgram* program,
+                         GLint location, const WebGLUniformInfo& info);
 
-    bool ValidateForProgram(WebGLProgram* prog, WebGLContext* webgl,
-                            const char* funcName) const;
-    bool ValidateSamplerSetter(GLint value, WebGLContext* webgl,
-                               const char* funcName) const;
-    bool ValidateSizeAndType(uint8_t setterElemSize, GLenum setterType,
-                             WebGLContext* webgl, const char* funcName) const;
-    bool ValidateArrayLength(uint8_t setterElemSize, size_t setterArraySize,
-                             WebGLContext* webgl, const char* funcName) const;
-
-    JS::Value GetUniform(JSContext* js, WebGLContext* webgl) const;
-
-    // Needed for certain helper functions like ValidateObject.
-    // `WebGLUniformLocation`s can't be 'Deleted' in the WebGL sense.
+    // needed for certain helper functions like ValidateObject.
+    // WebGLUniformLocation's can't be 'Deleted' in the WebGL sense.
     bool IsDeleted() const { return false; }
 
-    virtual JSObject* WrapObject(JSContext* js) MOZ_OVERRIDE;
+    const WebGLUniformInfo& Info() const { return mInfo; }
+
+    WebGLProgram* Program() const { return mProgram; }
+    GLint Location() const { return mLocation; }
+    uint32_t ProgramGeneration() const { return mProgramGeneration; }
+    int ElementSize() const { return mElementSize; }
+
+    JSObject* WrapObject(JSContext* cx);
+
+    NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLUniformLocation)
+    NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(WebGLUniformLocation)
 
 protected:
-    ~WebGLUniformLocation();
+    ~WebGLUniformLocation() { }
+
+    // nsRefPtr, not WebGLRefPtr, so that we don't prevent the program from being explicitly deleted.
+    // we just want to avoid having a dangling pointer.
+    nsRefPtr<WebGLProgram> mProgram;
+
+    uint32_t mProgramGeneration;
+    GLint mLocation;
+    WebGLUniformInfo mInfo;
+    int mElementSize;
+    friend class WebGLProgram;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_UNIFORM_LOCATION_H_
deleted file mode 100644
--- a/dom/canvas/WebGLValidateStrings.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "WebGLValidateStrings.h"
-
-#include "nsString.h"
-#include "WebGLContext.h"
-
-namespace mozilla {
-// The following code was taken from the WebKit WebGL implementation,
-// which can be found here:
-// http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
-// Note that some modifications were done to adapt it to Mozilla.
-/****** BEGIN CODE TAKEN FROM WEBKIT ******/
-bool IsValidGLSLCharacter(char16_t c)
-{
-    // Printing characters are valid except " $ ` @ \ ' DEL.
-    if (c >= 32 && c <= 126 &&
-        c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
-    {
-         return true;
-    }
-
-    // Horizontal tab, line feed, vertical tab, form feed, carriage return
-    // are also valid.
-    if (c >= 9 && c <= 13) {
-         return true;
-    }
-
-    return false;
-}
-
-void StripComments::process(char16_t c)
-{
-    if (isNewline(c)) {
-        // No matter what state we are in, pass through newlines
-        // so we preserve line numbers.
-        emit(c);
-
-        if (m_parseState != InMultiLineComment)
-            m_parseState = BeginningOfLine;
-
-        return;
-    }
-
-    char16_t temp = 0;
-    switch (m_parseState) {
-    case BeginningOfLine:
-        // If it's an ASCII space.
-        if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
-            emit(c);
-            break;
-        }
-
-        if (c == '#') {
-            m_parseState = InPreprocessorDirective;
-            emit(c);
-            break;
-        }
-
-        // Transition to normal state and re-handle character.
-        m_parseState = MiddleOfLine;
-        process(c);
-        break;
-
-    case MiddleOfLine:
-        if (c == '/' && peek(temp)) {
-            if (temp == '/') {
-                m_parseState = InSingleLineComment;
-                emit(' ');
-                advance();
-                break;
-            }
-
-            if (temp == '*') {
-                m_parseState = InMultiLineComment;
-                // Emit the comment start in case the user has
-                // an unclosed comment and we want to later
-                // signal an error.
-                emit('/');
-                emit('*');
-                advance();
-                break;
-            }
-        }
-
-        emit(c);
-        break;
-
-    case InPreprocessorDirective:
-        // No matter what the character is, just pass it
-        // through. Do not parse comments in this state. This
-        // might not be the right thing to do long term, but it
-        // should handle the #error preprocessor directive.
-        emit(c);
-        break;
-
-    case InSingleLineComment:
-        // The newline code at the top of this function takes care
-        // of resetting our state when we get out of the
-        // single-line comment. Swallow all other characters.
-        break;
-
-    case InMultiLineComment:
-        if (c == '*' && peek(temp) && temp == '/') {
-            emit('*');
-            emit('/');
-            m_parseState = MiddleOfLine;
-            advance();
-            break;
-        }
-
-        // Swallow all other characters. Unclear whether we may
-        // want or need to just emit a space per character to try
-        // to preserve column numbers for debugging purposes.
-        break;
-    }
-}
-
-/****** END CODE TAKEN FROM WEBKIT ******/
-
-bool
-ValidateGLSLString(const nsAString& string, WebGLContext* webgl, const char* funcName)
-{
-    for (size_t i = 0; i < string.Length(); ++i) {
-        if (!IsValidGLSLCharacter(string.CharAt(i))) {
-           webgl->ErrorInvalidValue("%s: String contains the illegal character '%d'",
-                                    funcName, string.CharAt(i));
-           return false;
-        }
-    }
-
-    return true;
-}
-
-bool
-ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl, const char* funcName)
-{
-    if (name.IsEmpty())
-        return false;
-
-    const uint32_t maxSize = 256;
-    if (name.Length() > maxSize) {
-        webgl->ErrorInvalidValue("%s: Identifier is %d characters long, exceeds the"
-                                 " maximum allowed length of %d characters.",
-                                 funcName, name.Length(), maxSize);
-        return false;
-    }
-
-    if (!ValidateGLSLString(name, webgl, funcName))
-        return false;
-
-    nsString prefix1 = NS_LITERAL_STRING("webgl_");
-    nsString prefix2 = NS_LITERAL_STRING("_webgl_");
-
-    if (Substring(name, 0, prefix1.Length()).Equals(prefix1) ||
-        Substring(name, 0, prefix2.Length()).Equals(prefix2))
-    {
-        webgl->ErrorInvalidOperation("%s: String contains a reserved GLSL prefix.",
-                                     funcName);
-        return false;
-    }
-
-    return true;
-}
-
-} // namespace mozilla
--- a/dom/canvas/WebGLValidateStrings.h
+++ b/dom/canvas/WebGLValidateStrings.h
@@ -22,135 +22,231 @@
  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #ifndef WEBGL_VALIDATE_STRINGS_H_
 #define WEBGL_VALIDATE_STRINGS_H_
 
-#include "nsString.h"
-#include "nsTArray.h"
+#include "WebGLContext.h"
 
 namespace mozilla {
 
-class WebGLContext;
-
 // The following code was taken from the WebKit WebGL implementation,
 // which can be found here:
 // http://trac.webkit.org/browser/trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp?rev=93625#L121
 // Note that some modifications were done to adapt it to Mozilla.
 /****** BEGIN CODE TAKEN FROM WEBKIT ******/
-// Strips comments from shader text. This allows non-ASCII characters
-// to be used in comments without potentially breaking OpenGL
-// implementations not expecting characters outside the GLSL ES set.
-class StripComments {
-public:
-    explicit StripComments(const nsAString& str)
-        : m_parseState(BeginningOfLine)
-        , m_end(str.EndReading())
-        , m_current(str.BeginReading())
-        , m_position(0)
+    bool WebGLContext::ValidateGLSLCharacter(char16_t c)
     {
-        m_result.SetLength(str.Length());
-        parse();
+        // Printing characters are valid except " $ ` @ \ ' DEL.
+        if (c >= 32 && c <= 126 &&
+            c != '"' && c != '$' && c != '`' && c != '@' && c != '\\' && c != '\'')
+        {
+             return true;
+        }
+
+        // Horizontal tab, line feed, vertical tab, form feed, carriage return
+        // are also valid.
+        if (c >= 9 && c <= 13) {
+             return true;
+        }
+
+        return false;
     }
 
-    const nsTArray<char16_t>& result()
-    {
-        return m_result;
-    }
+    // Strips comments from shader text. This allows non-ASCII characters
+    // to be used in comments without potentially breaking OpenGL
+    // implementations not expecting characters outside the GLSL ES set.
+    class StripComments {
+    public:
+        explicit StripComments(const nsAString& str)
+            : m_parseState(BeginningOfLine)
+            , m_end(str.EndReading())
+            , m_current(str.BeginReading())
+            , m_position(0)
+        {
+            m_result.SetLength(str.Length());
+            parse();
+        }
+
+        const nsTArray<char16_t>& result()
+        {
+            return m_result;
+        }
+
+        size_t length()
+        {
+            return m_position;
+        }
+
+    private:
+        bool hasMoreCharacters()
+        {
+            return (m_current < m_end);
+        }
+
+        void parse()
+        {
+            while (hasMoreCharacters()) {
+                process(current());
+                // process() might advance the position.
+                if (hasMoreCharacters())
+                    advance();
+            }
+        }
+
+        void process(char16_t);
 
-    size_t length()
-    {
-        return m_position;
-    }
+        bool peek(char16_t& character)
+        {
+            if (m_current + 1 >= m_end)
+                return false;
+            character = *(m_current + 1);
+            return true;
+        }
+
+        char16_t current()
+        {
+            //ASSERT(m_position < m_length);
+            return *m_current;
+        }
+
+        void advance()
+        {
+            ++m_current;
+        }
+
+        bool isNewline(char16_t character)
+        {
+            // Don't attempt to canonicalize newline related characters.
+            return (character == '\n' || character == '\r');
+        }
+
+        void emit(char16_t character)
+        {
+            m_result[m_position++] = character;
+        }
+
+        enum ParseState {
+            // Have not seen an ASCII non-whitespace character yet on
+            // this line. Possible that we might see a preprocessor
+            // directive.
+            BeginningOfLine,
+
+            // Have seen at least one ASCII non-whitespace character
+            // on this line.
+            MiddleOfLine,
+
+            // Handling a preprocessor directive. Passes through all
+            // characters up to the end of the line. Disables comment
+            // processing.
+            InPreprocessorDirective,
+
+            // Handling a single-line comment. The comment text is
+            // replaced with a single space.
+            InSingleLineComment,
 
-private:
-    bool hasMoreCharacters()
+            // Handling a multi-line comment. Newlines are passed
+            // through to preserve line numbers.
+            InMultiLineComment
+        };
+
+        ParseState m_parseState;
+        const char16_t* m_end;
+        const char16_t* m_current;
+        size_t m_position;
+        nsTArray<char16_t> m_result;
+    };
+
+    void StripComments::process(char16_t c)
     {
-        return (m_current < m_end);
-    }
+        if (isNewline(c)) {
+            // No matter what state we are in, pass through newlines
+            // so we preserve line numbers.
+            emit(c);
+
+            if (m_parseState != InMultiLineComment)
+                m_parseState = BeginningOfLine;
+
+            return;
+        }
+
+        char16_t temp = 0;
+        switch (m_parseState) {
+        case BeginningOfLine:
+            // If it's an ASCII space.
+            if (c <= ' ' && (c == ' ' || (c <= 0xD && c >= 0x9))) {
+                emit(c);
+                break;
+            }
+
+            if (c == '#') {
+                m_parseState = InPreprocessorDirective;
+                emit(c);
+                break;
+            }
+
+            // Transition to normal state and re-handle character.
+            m_parseState = MiddleOfLine;
+            process(c);
+            break;
 
-    void parse()
-    {
-        while (hasMoreCharacters()) {
-            process(current());
-            // process() might advance the position.
-            if (hasMoreCharacters())
+        case MiddleOfLine:
+            if (c == '/' && peek(temp)) {
+                if (temp == '/') {
+                    m_parseState = InSingleLineComment;
+                    emit(' ');
+                    advance();
+                    break;
+                }
+
+                if (temp == '*') {
+                    m_parseState = InMultiLineComment;
+                    // Emit the comment start in case the user has
+                    // an unclosed comment and we want to later
+                    // signal an error.
+                    emit('/');
+                    emit('*');
+                    advance();
+                    break;
+                }
+            }
+
+            emit(c);
+            break;
+
+        case InPreprocessorDirective:
+            // No matter what the character is, just pass it
+            // through. Do not parse comments in this state. This
+            // might not be the right thing to do long term, but it
+            // should handle the #error preprocessor directive.
+            emit(c);
+            break;
+
+        case InSingleLineComment:
+            // The newline code at the top of this function takes care
+            // of resetting our state when we get out of the
+            // single-line comment. Swallow all other characters.
+            break;
+
+        case InMultiLineComment:
+            if (c == '*' && peek(temp) && temp == '/') {
+                emit('*');
+                emit('/');
+                m_parseState = MiddleOfLine;
                 advance();
+                break;
+            }
+
+            // Swallow all other characters. Unclear whether we may
+            // want or need to just emit a space per character to try
+            // to preserve column numbers for debugging purposes.
+            break;
         }
     }
 
-    void process(char16_t);
-
-    bool peek(char16_t& character)
-    {
-        if (m_current + 1 >= m_end)
-            return false;
-        character = *(m_current + 1);
-        return true;
-    }
-
-    char16_t current()
-    {
-        //ASSERT(m_position < m_length);
-        return *m_current;
-    }
-
-    void advance()
-    {
-        ++m_current;
-    }
-
-    bool isNewline(char16_t character)
-    {
-        // Don't attempt to canonicalize newline related characters.
-        return (character == '\n' || character == '\r');
-    }
-
-    void emit(char16_t character)
-    {
-        m_result[m_position++] = character;
-    }
-
-    enum ParseState {
-        // Have not seen an ASCII non-whitespace character yet on
-        // this line. Possible that we might see a preprocessor
-        // directive.
-        BeginningOfLine,
-
-        // Have seen at least one ASCII non-whitespace character
-        // on this line.
-        MiddleOfLine,
-
-        // Handling a preprocessor directive. Passes through all
-        // characters up to the end of the line. Disables comment
-        // processing.
-        InPreprocessorDirective,
-
-        // Handling a single-line comment. The comment text is
-        // replaced with a single space.
-        InSingleLineComment,
-
-        // Handling a multi-line comment. Newlines are passed
-        // through to preserve line numbers.
-        InMultiLineComment
-    };
-
-    ParseState m_parseState;
-    const char16_t* m_end;
-    const char16_t* m_current;
-    size_t m_position;
-    nsTArray<char16_t> m_result;
-};
-
 /****** END CODE TAKEN FROM WEBKIT ******/
 
-bool ValidateGLSLString(const nsAString& string, WebGLContext* webgl,
-                        const char* funcName);
-
-bool ValidateGLSLVariableName(const nsAString& name, WebGLContext* webgl,
-                              const char* funcName);
-
 } // namespace mozilla
 
 #endif // WEBGL_VALIDATE_STRINGS_H_
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -103,23 +103,21 @@ UNIFIED_SOURCES += [
     'WebGLFramebufferAttachable.cpp',
     'WebGLObjectModel.cpp',
     'WebGLProgram.cpp',
     'WebGLQuery.cpp',
     'WebGLRenderbuffer.cpp',
     'WebGLSampler.cpp',
     'WebGLShader.cpp',
     'WebGLShaderPrecisionFormat.cpp',
-    'WebGLShaderValidator.cpp',
     'WebGLSync.cpp',
     'WebGLTexelConversions.cpp',
     'WebGLTexture.cpp',
     'WebGLTransformFeedback.cpp',
     'WebGLUniformLocation.cpp',
-    'WebGLValidateStrings.cpp',
     'WebGLVertexArray.cpp',
     'WebGLVertexArrayFake.cpp',
     'WebGLVertexArrayGL.cpp',
 ]
 LOCAL_INCLUDES += [
     '/js/xpconnect/wrappers',
 ]
 
--- a/dom/canvas/test/webgl-conformance/conformance/misc/bad-arguments-test.html
+++ b/dom/canvas/test/webgl-conformance/conformance/misc/bad-arguments-test.html
@@ -63,23 +63,25 @@ var arguments = [
 
 var argument;
 
 function shouldBeEmptyString(command) {
   shouldBe(command, "''");
 }
 
 for (var i = 0; i < arguments.length; ++i) {
-  var func, func2;
+  var func, func2, func3;
   if (arguments[i].throws) {
     func = shouldThrow;
     func2 = shouldThrow;
+    func3 = shouldThrow;
   } else {
     func = shouldBeUndefined;
     func2 = shouldBeNull;
+    func3 = shouldBeEmptyString;
   }
   argument = arguments[i].value;
   func("context.compileShader(argument)");
   func("context.linkProgram(argument)");
   func("context.attachShader(program, argument)");
   func("context.attachShader(argument, shader)");
   func("context.detachShader(program, argument)");
   func("context.detachShader(argument, shader)");
@@ -91,24 +93,25 @@ for (var i = 0; i < arguments.length; ++
   func("context.bindRenderbuffer(context.RENDERBUFFER, argument)");
   func("context.bindTexture(context.TEXTURE_2D, argument)");
   func("context.framebufferRenderbuffer(context.FRAMEBUFFER, context.DEPTH_ATTACHMENT, context.RENDERBUFFER, argument)");
   func("context.framebufferTexture2D(context.FRAMEBUFFER, context.COLOR_ATTACHMENT0, context.TEXTURE_2D, argument, 0)");
   func("context.uniform2fv(argument, new Float32Array([0.0, 0.0]))");
   func("context.uniform2iv(argument, new Int32Array([0, 0]))");
   func("context.uniformMatrix2fv(argument, false, new Float32Array([0.0, 0.0, 0.0, 0.0]))");
 
-  func2("context.getProgramInfoLog(argument)");
   func2("context.getProgramParameter(argument, 0)");
-  func2("context.getShaderInfoLog(argument)");
   func2("context.getShaderParameter(argument, 0)");
-  func2("context.getShaderSource(argument)");
   func2("context.getUniform(argument, loc)");
   func2("context.getUniform(program, argument)");
   func2("context.getUniformLocation(argument, 'u_modelViewProjMatrix')");
+
+  func3("context.getProgramInfoLog(argument)");
+  func3("context.getShaderInfoLog(argument)");
+  func3("context.getShaderSource(argument)");
 }
 
 successfullyParsed = true;
 </script>
 
 <script>finishTest();</script>
 </body>
 </html>
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -2010,17 +2010,17 @@ public:
     }
 
     void fGetShaderSource(GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source) {
         BEFORE_GL_CALL;
         mSymbols.fGetShaderSource(obj, maxLength, length, source);
         AFTER_GL_CALL;
     }
 
-    void fShaderSource(GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths) {
+    void fShaderSource(GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths) {
         BEFORE_GL_CALL;
         mSymbols.fShaderSource(shader, count, strings, lengths);
         AFTER_GL_CALL;
     }
 
 private:
     void raw_fBindFramebuffer(GLenum target, GLuint framebuffer) {
         BEFORE_GL_CALL;
--- a/gfx/gl/GLContextSymbols.h
+++ b/gfx/gl/GLContextSymbols.h
@@ -303,17 +303,17 @@ struct GLContextSymbols
     typedef void (GLAPIENTRY * PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint* param);
     PFNGLGETSHADERIVPROC fGetShaderiv;
     typedef void (GLAPIENTRY * PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
     PFNGLGETSHADERINFOLOGPROC fGetShaderInfoLog;
     typedef void (GLAPIENTRY * PFNGETSHADERPRECISIONFORMAT) (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
     PFNGETSHADERPRECISIONFORMAT fGetShaderPrecisionFormat;
     typedef void (GLAPIENTRY * PFNGLGETSHADERSOURCEPROC) (GLint obj, GLsizei maxLength, GLsizei* length, GLchar* source);
     PFNGLGETSHADERSOURCEPROC fGetShaderSource;
-    typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar* const* strings, const GLint* lengths);
+    typedef void (GLAPIENTRY * PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const GLchar** strings, const GLint* lengths);
     PFNGLSHADERSOURCEPROC fShaderSource;
 
     typedef void (GLAPIENTRY * PFNGLBINDFRAMEBUFFER) (GLenum target, GLuint framebuffer);
     PFNGLBINDFRAMEBUFFER fBindFramebuffer;
     typedef void (GLAPIENTRY * PFNGLBINDRENDERBUFFER) (GLenum target, GLuint renderbuffer);
     PFNGLBINDRENDERBUFFER fBindRenderbuffer;
     typedef GLenum (GLAPIENTRY * PFNGLCHECKFRAMEBUFFERSTATUS) (GLenum target);
     PFNGLCHECKFRAMEBUFFERSTATUS fCheckFramebufferStatus;
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -3823,30 +3823,30 @@ pref("image.onload.decode.limit", 0);
 #ifdef ANDROID
 // Disable MSAA on mobile.
 pref("gl.msaa-level", 0);
 #else
 pref("gl.msaa-level", 2);
 #endif
 pref("webgl.force-enabled", false);
 pref("webgl.disabled", false);
+pref("webgl.shader_validator", true);
 pref("webgl.disable-angle", false);
 pref("webgl.min_capability_mode", false);
 pref("webgl.disable-extensions", false);
 pref("webgl.msaa-force", false);
 pref("webgl.prefer-16bpp", false);
 pref("webgl.default-no-alpha", false);
 pref("webgl.force-layers-readback", false);
 pref("webgl.lose-context-on-memory-pressure", false);
 pref("webgl.can-lose-context-in-foreground", true);
 pref("webgl.restore-context-when-visible", true);
 pref("webgl.max-warnings-per-context", 32);
 pref("webgl.enable-draft-extensions", false);
 pref("webgl.enable-privileged-extensions", false);
-pref("webgl.bypass-shader-validation", false);
 #ifdef XP_WIN
 pref("webgl.angle.try-d3d11", true);
 pref("webgl.angle.force-d3d11", false);
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 pref("gfx.gralloc.fence-with-readpixels", false);
 #endif