Bug 827106 - Cherry-pick ANGLE r1638 - r=jgilbert, a=lsblakk
authorBenoit Jacob <bjacob@mozilla.com>
Tue, 05 Feb 2013 20:53:38 -0500
changeset 128243 9acedf5c6da5daa1f1ac0ef78c8607939f024846
parent 128242 a902a25121c8db88bb1db17c0ce4f935e14ffe11
child 128244 d2f68c7e8153b2919c6aa922c9a98660f9dceb24
push id297
push userlsblakk@mozilla.com
push dateTue, 26 Mar 2013 17:28:00 +0000
treeherdermozilla-release@64d7b45c34e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, lsblakk
bugs827106
milestone20.0a2
Bug 827106 - Cherry-pick ANGLE r1638 - r=jgilbert, a=lsblakk
gfx/angle/Makefile.in
gfx/angle/angle-r1638.patch
gfx/angle/include/GLSLANG/ShaderLang.h
gfx/angle/src/compiler/ArrayBoundsClamper.cpp
gfx/angle/src/compiler/ArrayBoundsClamper.h
gfx/angle/src/compiler/Compiler.cpp
gfx/angle/src/compiler/OutputGLSLBase.cpp
gfx/angle/src/compiler/ShHandle.h
gfx/angle/src/compiler/TranslatorESSL.cpp
gfx/angle/src/compiler/TranslatorGLSL.cpp
gfx/angle/src/compiler/intermOut.cpp
gfx/angle/src/compiler/intermediate.h
gfx/angle/src/libGLESv2/Makefile.in
--- a/gfx/angle/Makefile.in
+++ b/gfx/angle/Makefile.in
@@ -66,16 +66,17 @@ CPPSRCS = \
         SymbolTable.cpp \
         VariableInfo.cpp \
         compilerdebug.cpp \
         util.cpp \
         ValidateLimitations.cpp \
         ForLoopUnroll.cpp \
         MapLongVariableNames.cpp \
         spooky.cpp \
+        ArrayBoundsClamper.cpp \
         BuiltInFunctionEmulator.cpp \
         Input.cpp \
         Lexer.cpp \
         Preprocessor.cpp \
         Token.cpp \
         VariablePacker.cpp \
         $(NULL)
 
new file mode 100644
--- /dev/null
+++ b/gfx/angle/angle-r1638.patch
@@ -0,0 +1,475 @@
+# HG changeset patch
+# Parent faf255e4400222ee23c29ddcc76fb3dce56145f4
+
+diff --git a/gfx/angle/AUTHORS b/gfx/angle/AUTHORS
+--- a/gfx/angle/AUTHORS
++++ b/gfx/angle/AUTHORS
+@@ -7,16 +7,17 @@
+ #	Name or Organization
+ # Email addresses for individuals are tracked elsewhere to avoid spam.
+ 
+ Google Inc.
+ TransGaming Inc.
+ 3DLabs Inc. Ltd.
+ 
+ Adobe Systems Inc.
++Apple Inc.
+ Autodesk, Inc.
+ Cloud Party, Inc.
+ Intel Corporation
+ Mozilla Corporation
+ Turbulenz
+ Klarälvdalens Datakonsult AB
+ 
+ Jacek Caban
+diff --git a/gfx/angle/Makefile.in b/gfx/angle/Makefile.in
+--- a/gfx/angle/Makefile.in
++++ b/gfx/angle/Makefile.in
+@@ -51,16 +51,17 @@ LOCAL_INCLUDES += \
+   -I$(srcdir)/include/KHR \
+   -I$(srcdir)/src
+ 
+ DEFINES += -DCOMPILER_IMPLEMENTATION
+ 
+ VPATH += $(srcdir)/src/compiler
+ # src/compiler:
+ CPPSRCS += \
++  ArrayBoundsClamper.cpp \
+   BuiltInFunctionEmulator.cpp \
+   Compiler.cpp \
+   compiler_debug.cpp \
+   DetectRecursion.cpp \
+   Diagnostics.cpp \
+   DirectiveHandler.cpp \
+   ForLoopUnroll.cpp \
+   glslang_lex.cpp \
+diff --git a/gfx/angle/README.mozilla b/gfx/angle/README.mozilla
+--- a/gfx/angle/README.mozilla
++++ b/gfx/angle/README.mozilla
+@@ -21,16 +21,20 @@ In this order:
+   
+   angle-long-ident-spooky-hash.patch:
+     Use Spooky Hash for long identifier hashing. See bug 676071.
+   
+   angle-faceforward-emu.patch:
+     Adds emulation for faceforward(float,float,float), which is needed to
+     prevent crashing on Mac+Intel. See bug 771406.
+ 
++  angle-r1638.patch
++    Adds uniform array index clamping on non-Windows platforms.
++    Windows would require r1719, r1733, r1734.
++
+ In addition to these patches, the Makefile.in files are ours, they're not present in
+ upsteam ANGLE. Therefore, changes made to the Makefile.in files should not be stored
+ in the local .patch files.
+ 
+ 
+ == How to do a clean-slate upgrade ==
+ 1.  Backup our moz-specific files:
+       README.mozilla
+diff --git a/gfx/angle/include/GLSLANG/ShaderLang.h b/gfx/angle/include/GLSLANG/ShaderLang.h
+--- a/gfx/angle/include/GLSLANG/ShaderLang.h
++++ b/gfx/angle/include/GLSLANG/ShaderLang.h
+@@ -145,17 +145,23 @@ typedef enum {
+   // restrictions on fragment shaders.
+   // This flag only has an effect if all of the following are true:
+   // - The shader spec is SH_WEBGL_SPEC.
+   // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
+   // - The shader type is SH_FRAGMENT_SHADER.
+   SH_DEPENDENCY_GRAPH = 0x0400,
+ 
+   // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
+-  SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800
++  SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
++
++  // This flag ensures all indirect (expression-based) array indexing
++  // is clamped to the bounds of the array. This ensures, for example,
++  // that you cannot read off the end of a uniform, whether an array
++  // vec234, or mat234 type.
++  SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000
+ } ShCompileOptions;
+ 
+ //
+ // Driver must call this first, once, before doing any other
+ // compiler operations.
+ // If the function succeeds, the return value is nonzero, else zero.
+ //
+ COMPILER_EXPORT int ShInitialize();
+diff --git a/gfx/angle/src/build_angle.gypi b/gfx/angle/src/build_angle.gypi
+--- a/gfx/angle/src/build_angle.gypi
++++ b/gfx/angle/src/build_angle.gypi
+@@ -54,16 +54,18 @@
+       'include_dirs': [
+         '.',
+         '../include',
+       ],
+       'defines': [
+         'COMPILER_IMPLEMENTATION',
+       ],
+       'sources': [
++        'compiler/ArrayBoundsClamper.cpp',
++        'compiler/ArrayBoundsClamper.h',
+         'compiler/BaseTypes.h',
+         'compiler/BuiltInFunctionEmulator.cpp',
+         'compiler/BuiltInFunctionEmulator.h',
+         'compiler/Common.h',
+         'compiler/Compiler.cpp',
+         'compiler/ConstantUnion.h',
+         'compiler/debug.cpp',
+         'compiler/debug.h',
+diff --git a/gfx/angle/src/compiler/Compiler.cpp b/gfx/angle/src/compiler/Compiler.cpp
+--- a/gfx/angle/src/compiler/Compiler.cpp
++++ b/gfx/angle/src/compiler/Compiler.cpp
+@@ -1,14 +1,15 @@
+ //
+ // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
+ // Use of this source code is governed by a BSD-style license that can be
+ // found in the LICENSE file.
+ //
+ 
++#include "compiler/ArrayBoundsClamper.h"
+ #include "compiler/BuiltInFunctionEmulator.h"
+ #include "compiler/DetectRecursion.h"
+ #include "compiler/ForLoopUnroll.h"
+ #include "compiler/Initialize.h"
+ #include "compiler/InitializeParseContext.h"
+ #include "compiler/MapLongVariableNames.h"
+ #include "compiler/ParseHelper.h"
+ #include "compiler/RenameFunction.h"
+@@ -187,16 +188,20 @@ bool TCompiler::compile(const char* cons
+         // Unroll for-loop markup needs to happen after validateLimitations pass.
+         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
+             ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
+ 
+         // Built-in function emulation needs to happen after validateLimitations pass.
+         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
+             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
+ 
++        // Clamping uniform array bounds needs to happen after validateLimitations pass.
++        if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
++            arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
++
+         // Call mapLongVariableNames() before collectAttribsUniforms() so in
+         // collectAttribsUniforms() we already have the mapped symbol names and
+         // we could composite mapped and original variable names.
+         // Also, if we hash all the names, then no need to do this for long names.
+         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES) && hashFunction == NULL)
+             mapLongVariableNames(root);
+ 
+         if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
+@@ -232,16 +237,17 @@ bool TCompiler::InitBuiltInSymbolTable(c
+ 
+     builtIns.initialize(shaderType, shaderSpec, resources);
+     return InitializeSymbolTable(builtIns.getBuiltInStrings(),
+         shaderType, shaderSpec, resources, infoSink, symbolTable);
+ }
+ 
+ void TCompiler::clearResults()
+ {
++    arrayBoundsClamper.Cleanup();
+     infoSink.info.erase();
+     infoSink.obj.erase();
+     infoSink.debug.erase();
+ 
+     attribs.clear();
+     uniforms.clear();
+ 
+     builtInFunctionEmulator.Cleanup();
+@@ -348,8 +354,14 @@ const TExtensionBehavior& TCompiler::get
+ {
+     return extensionBehavior;
+ }
+ 
+ const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
+ {
+     return builtInFunctionEmulator;
+ }
++
++const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
++{
++    return arrayBoundsClamper;
++}
++
+diff --git a/gfx/angle/src/compiler/OutputGLSLBase.cpp b/gfx/angle/src/compiler/OutputGLSLBase.cpp
+--- a/gfx/angle/src/compiler/OutputGLSLBase.cpp
++++ b/gfx/angle/src/compiler/OutputGLSLBase.cpp
+@@ -207,18 +207,47 @@ bool TOutputGLSLBase::visitBinary(Visit 
+         case EOpVectorTimesMatrixAssign:
+         case EOpVectorTimesScalarAssign:
+         case EOpMatrixTimesScalarAssign:
+         case EOpMatrixTimesMatrixAssign:
+             writeTriplet(visit, "(", " *= ", ")");
+             break;
+ 
+         case EOpIndexDirect:
++            writeTriplet(visit, NULL, "[", "]");
++            break;
+         case EOpIndexIndirect:
+-            writeTriplet(visit, NULL, "[", "]");
++            if (node->getAddIndexClamp())
++            {
++                if (visit == InVisit)
++                {
++                    out << "[webgl_int_clamp(";
++                }
++                else if (visit == PostVisit)
++                {
++                    int maxSize;
++                    TIntermTyped *left = node->getLeft();
++                    TType leftType = left->getType();
++
++                    if (left->isArray())
++                    {
++                        // The shader will fail validation if the array length is not > 0.
++                        maxSize = leftType.getArraySize() - 1;
++                    }
++                    else
++                    {
++                        maxSize = leftType.getNominalSize() - 1;
++                    }
++                    out << ", 0, " << maxSize << ")]";
++                }
++            }
++            else
++            {
++                writeTriplet(visit, NULL, "[", "]");
++            }
+             break;
+         case EOpIndexDirectStruct:
+             if (visit == InVisit)
+             {
+                 out << ".";
+                 // TODO(alokp): ASSERT
+                 out << hashName(node->getType().getFieldName());
+                 visitChildren = false;
+diff --git a/gfx/angle/src/compiler/ShHandle.h b/gfx/angle/src/compiler/ShHandle.h
+--- a/gfx/angle/src/compiler/ShHandle.h
++++ b/gfx/angle/src/compiler/ShHandle.h
+@@ -11,16 +11,17 @@
+ // Machine independent part of the compiler private objects
+ // sent as ShHandle to the driver.
+ //
+ // This should not be included by driver code.
+ //
+ 
+ #include "GLSLANG/ShaderLang.h"
+ 
++#include "compiler/ArrayBoundsClamper.h"
+ #include "compiler/BuiltInFunctionEmulator.h"
+ #include "compiler/ExtensionBehavior.h"
+ #include "compiler/HashNames.h"
+ #include "compiler/InfoSink.h"
+ #include "compiler/SymbolTable.h"
+ #include "compiler/VariableInfo.h"
+ 
+ class LongNameMap;
+@@ -101,30 +102,32 @@ protected:
+     // Returns true if the shader does not use samplers.
+     bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
+     // Returns true if the shader does not use sampler dependent values to affect control 
+     // flow or in operations whose time can depend on the input values.
+     bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
+     // Get built-in extensions with default behavior.
+     const TExtensionBehavior& getExtensionBehavior() const;
+ 
++    const ArrayBoundsClamper& getArrayBoundsClamper() const;
+     const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
+ 
+ private:
+     ShShaderType shaderType;
+     ShShaderSpec shaderSpec;
+ 
+     int maxUniformVectors;
+ 
+     // Built-in symbol table for the given language, spec, and resources.
+     // It is preserved from compile-to-compile.
+     TSymbolTable symbolTable;
+     // Built-in extensions with default behavior.
+     TExtensionBehavior extensionBehavior;
+ 
++    ArrayBoundsClamper arrayBoundsClamper;
+     BuiltInFunctionEmulator builtInFunctionEmulator;
+ 
+     // Results of compilation.
+     TInfoSink infoSink;  // Output sink.
+     TVariableInfoList attribs;  // Active attributes in the compiled shader.
+     TVariableInfoList uniforms;  // Active uniforms in the compiled shader.
+ 
+     // Cached copy of the ref-counted singleton.
+diff --git a/gfx/angle/src/compiler/TranslatorESSL.cpp b/gfx/angle/src/compiler/TranslatorESSL.cpp
+--- a/gfx/angle/src/compiler/TranslatorESSL.cpp
++++ b/gfx/angle/src/compiler/TranslatorESSL.cpp
+@@ -17,16 +17,19 @@ void TranslatorESSL::translate(TIntermNo
+ 
+     // Write built-in extension behaviors.
+     writeExtensionBehavior();
+ 
+     // Write emulated built-in functions if needed.
+     getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+         sink, getShaderType() == SH_FRAGMENT_SHADER);
+ 
++    // Write array bounds clamping emulation if needed.
++    getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
++
+     // Write translated shader.
+     TOutputESSL outputESSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
+     root->traverse(&outputESSL);
+ }
+ 
+ void TranslatorESSL::writeExtensionBehavior() {
+     TInfoSinkBase& sink = getInfoSink().obj;
+     const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
+diff --git a/gfx/angle/src/compiler/TranslatorGLSL.cpp b/gfx/angle/src/compiler/TranslatorGLSL.cpp
+--- a/gfx/angle/src/compiler/TranslatorGLSL.cpp
++++ b/gfx/angle/src/compiler/TranslatorGLSL.cpp
+@@ -30,12 +30,15 @@ void TranslatorGLSL::translate(TIntermNo
+ 
+     // Write GLSL version.
+     writeVersion(getShaderType(), root, sink);
+ 
+     // Write emulated built-in functions if needed.
+     getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
+         sink, false);
+ 
++    // Write array bounds clamping emulation if needed.
++    getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
++
+     // Write translated shader.
+     TOutputGLSL outputGLSL(sink, getHashFunction(), getNameMap(), getSymbolTable());
+     root->traverse(&outputGLSL);
+ }
+diff --git a/gfx/angle/src/compiler/intermOut.cpp b/gfx/angle/src/compiler/intermOut.cpp
+--- a/gfx/angle/src/compiler/intermOut.cpp
++++ b/gfx/angle/src/compiler/intermOut.cpp
+@@ -37,17 +37,17 @@ protected:
+ 
+ TString TType::getCompleteString() const
+ {
+     TStringStream stream;
+ 
+     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
+         stream << getQualifierString() << " " << getPrecisionString() << " ";
+     if (array)
+-        stream << "array of ";
++        stream << "array[" << getArraySize() << "] of ";
+     if (matrix)
+         stream << size << "X" << size << " matrix of ";
+     else if (size > 1)
+         stream << size << "-component vector of ";
+ 
+     stream << getBasicString();
+     return stream.str();
+ }
+diff --git a/gfx/angle/src/compiler/intermediate.h b/gfx/angle/src/compiler/intermediate.h
+--- a/gfx/angle/src/compiler/intermediate.h
++++ b/gfx/angle/src/compiler/intermediate.h
+@@ -386,30 +386,36 @@ protected:
+     TOperator op;
+ };
+ 
+ //
+ // Nodes for all the basic binary math operators.
+ //
+ class TIntermBinary : public TIntermOperator {
+ public:
+-    TIntermBinary(TOperator o) : TIntermOperator(o) {}
++    TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
+ 
+     virtual TIntermBinary* getAsBinaryNode() { return this; }
+     virtual void traverse(TIntermTraverser*);
+ 
+     void setLeft(TIntermTyped* n) { left = n; }
+     void setRight(TIntermTyped* n) { right = n; }
+     TIntermTyped* getLeft() const { return left; }
+     TIntermTyped* getRight() const { return right; }
+     bool promote(TInfoSink&);
+ 
++    void setAddIndexClamp() { addIndexClamp = true; }
++    bool getAddIndexClamp() { return addIndexClamp; }
++
+ protected:
+     TIntermTyped* left;
+     TIntermTyped* right;
++
++    // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
++    bool addIndexClamp;
+ };
+ 
+ //
+ // Nodes for unary math operators.
+ //
+ class TIntermUnary : public TIntermOperator {
+ public:
+     TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
+diff --git a/gfx/angle/src/compiler/translator_common.vcxproj b/gfx/angle/src/compiler/translator_common.vcxproj
+--- a/gfx/angle/src/compiler/translator_common.vcxproj
++++ b/gfx/angle/src/compiler/translator_common.vcxproj
+@@ -133,16 +133,17 @@
+       </PrecompiledHeader>
+       <WarningLevel>Level4</WarningLevel>
+       <TreatWarningAsError>true</TreatWarningAsError>
+       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+       <DisableSpecificWarnings>4100;4127;4189;4239;4244;4245;4267;4512;4702;4718;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+     </ClCompile>
+   </ItemDefinitionGroup>
+   <ItemGroup>
++    <ClCompile Include="ArrayBoundsClamper.cpp" />
+     <ClCompile Include="BuiltInFunctionEmulator.cpp" />
+     <ClCompile Include="Compiler.cpp" />
+     <ClCompile Include="debug.cpp" />
+     <ClCompile Include="DetectRecursion.cpp" />
+     <ClCompile Include="Diagnostics.cpp" />
+     <ClCompile Include="DirectiveHandler.cpp" />
+     <ClCompile Include="ForLoopUnroll.cpp" />
+     <ClCompile Include="InfoSink.cpp" />
+@@ -220,16 +221,17 @@
+       <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+       </Message>
+       <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+       </Command>
+       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(Outputs)</Outputs>
+     </CustomBuild>
+   </ItemGroup>
+   <ItemGroup>
++    <ClInclude Include="ArrayBoundsClamper.h" />
+     <ClInclude Include="BaseTypes.h" />
+     <ClInclude Include="BuiltInFunctionEmulator.h" />
+     <ClInclude Include="Common.h" />
+     <ClInclude Include="ConstantUnion.h" />
+     <ClInclude Include="debug.h" />
+     <ClInclude Include="DetectRecursion.h" />
+     <ClInclude Include="Diagnostics.h" />
+     <ClInclude Include="DirectiveHandler.h" />
+@@ -274,9 +276,9 @@
+       <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>
+       <LinkLibraryDependencies>true</LinkLibraryDependencies>
+       <UseLibraryDependencyInputs>true</UseLibraryDependencyInputs>
+     </ProjectReference>
+   </ItemGroup>
+   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+   <ImportGroup Label="ExtensionTargets">
+   </ImportGroup>
+-</Project>
+\ No newline at end of file
++</Project>
+diff --git a/gfx/angle/src/libGLESv2/Makefile.in b/gfx/angle/src/libGLESv2/Makefile.in
+--- a/gfx/angle/src/libGLESv2/Makefile.in
++++ b/gfx/angle/src/libGLESv2/Makefile.in
+@@ -64,16 +64,17 @@ LOCAL_INCLUDES = \
+   -I$(srcdir)/../../include/KHR \
+   -I$(srcdir)/..
+ 
+ DEFINES += -DCOMPILER_IMPLEMENTATION
+ 
+ VPATH += $(srcdir)/../compiler
+ # src/compiler:
+ CPPSRCS += \
++  ArrayBoundsClamper.cpp \
+   BuiltInFunctionEmulator.cpp \
+   Compiler.cpp \
+   compiler_debug.cpp \
+   DetectRecursion.cpp \
+   Diagnostics.cpp \
+   DirectiveHandler.cpp \
+   ForLoopUnroll.cpp \
+   glslang_lex.cpp \
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -141,16 +141,22 @@ typedef enum {
   // This flag only has an effect if all of the following are true:
   // - The shader spec is SH_WEBGL_SPEC.
   // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
   // - The shader type is SH_FRAGMENT_SHADER.
   SH_DEPENDENCY_GRAPH = 0x0400,
 
   // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
   SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
+
+  // This flag ensures all indirect (expression-based) array indexing
+  // is clamped to the bounds of the array. This ensures, for example,
+  // that you cannot read off the end of a uniform, whether an array
+  // vec234, or mat234 type.
+  SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000
 } ShCompileOptions;
 
 //
 // Driver must call this first, once, before doing any other
 // compiler operations.
 // If the function succeeds, the return value is nonzero, else zero.
 //
 COMPILER_EXPORT int ShInitialize();
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/ArrayBoundsClamper.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * 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.
+ */
+
+#include "compiler/ArrayBoundsClamper.h"
+
+const char* kIntClampBegin = "// BEGIN: Generated code for array bounds clamping\n\n";
+const char* kIntClampEnd = "// END: Generated code for array bounds clamping\n\n";
+const char* kIntClampDefinition = "int webgl_int_clamp(int value, int minValue, int maxValue) { return ((value < minValue) ? minValue : ((value > maxValue) ? maxValue : value)); }\n\n";
+
+namespace {
+
+class ArrayBoundsClamperMarker : public TIntermTraverser {
+public:
+    ArrayBoundsClamperMarker()
+        : mNeedsClamp(false)
+   {
+   }
+
+   virtual bool visitBinary(Visit visit, TIntermBinary* node)
+   {
+       if (node->getOp() == EOpIndexIndirect)
+       {
+           TIntermTyped* left = node->getLeft();
+           if (left->isArray() || left->isVector() || left->isMatrix())
+           {
+               node->setAddIndexClamp();
+               mNeedsClamp = true;
+           }
+       }
+       return true;
+   }
+
+    bool GetNeedsClamp() { return mNeedsClamp; }
+
+private:
+    bool mNeedsClamp;
+};
+
+}  // anonymous namespace
+
+ArrayBoundsClamper::ArrayBoundsClamper()
+    : mArrayBoundsClampDefinitionNeeded(false)
+{
+}
+
+void ArrayBoundsClamper::OutputClampingFunctionDefinition(TInfoSinkBase& out) const
+{
+    if (!mArrayBoundsClampDefinitionNeeded)
+    {
+        return;
+    }
+    out << kIntClampBegin << kIntClampDefinition << kIntClampEnd;
+}
+
+void ArrayBoundsClamper::MarkIndirectArrayBoundsForClamping(TIntermNode* root)
+{
+    ASSERT(root);
+
+    ArrayBoundsClamperMarker clamper;
+    root->traverse(&clamper);
+    if (clamper.GetNeedsClamp())
+    {
+        SetArrayBoundsClampDefinitionNeeded();
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/angle/src/compiler/ArrayBoundsClamper.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * 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 COMPILER_ARRAY_BOUNDS_CLAMPER_H_
+#define COMPILER_ARRAY_BOUNDS_CLAMPER_H_
+
+#include "GLSLANG/ShaderLang.h"
+
+#include "compiler/InfoSink.h"
+#include "compiler/intermediate.h"
+
+class ArrayBoundsClamper {
+public:
+    ArrayBoundsClamper();
+
+    // Output array clamp function source into the shader source.
+    void OutputClampingFunctionDefinition(TInfoSinkBase& out) const;
+
+    // Marks nodes in the tree that index arrays indirectly as
+    // requiring clamping.
+    void MarkIndirectArrayBoundsForClamping(TIntermNode* root);
+
+    void Cleanup()
+    {
+        mArrayBoundsClampDefinitionNeeded = false;
+    }
+
+private:
+    bool GetArrayBoundsClampDefinitionNeeded() const { return mArrayBoundsClampDefinitionNeeded; }
+    void SetArrayBoundsClampDefinitionNeeded() { mArrayBoundsClampDefinitionNeeded = true; }
+    
+    bool mArrayBoundsClampDefinitionNeeded;
+};
+
+#endif // COMPILER_ARRAY_BOUNDS_CLAMPER_H_
--- a/gfx/angle/src/compiler/Compiler.cpp
+++ b/gfx/angle/src/compiler/Compiler.cpp
@@ -1,14 +1,15 @@
 //
 // Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
+#include "compiler/ArrayBoundsClamper.h"
 #include "compiler/BuiltInFunctionEmulator.h"
 #include "compiler/DetectRecursion.h"
 #include "compiler/ForLoopUnroll.h"
 #include "compiler/Initialize.h"
 #include "compiler/InitializeParseContext.h"
 #include "compiler/MapLongVariableNames.h"
 #include "compiler/ParseHelper.h"
 #include "compiler/RenameFunction.h"
@@ -185,16 +186,20 @@ bool TCompiler::compile(const char* cons
         // Unroll for-loop markup needs to happen after validateLimitations pass.
         if (success && (compileOptions & SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX))
             ForLoopUnroll::MarkForLoopsWithIntegerIndicesForUnrolling(root);
 
         // Built-in function emulation needs to happen after validateLimitations pass.
         if (success && (compileOptions & SH_EMULATE_BUILT_IN_FUNCTIONS))
             builtInFunctionEmulator.MarkBuiltInFunctionsForEmulation(root);
 
+        // Clamping uniform array bounds needs to happen after validateLimitations pass.
+        if (success && (compileOptions & SH_CLAMP_INDIRECT_ARRAY_BOUNDS))
+            arrayBoundsClamper.MarkIndirectArrayBoundsForClamping(root);
+
         // Call mapLongVariableNames() before collectAttribsUniforms() so in
         // collectAttribsUniforms() we already have the mapped symbol names and
         // we could composite mapped and original variable names.
         if (success && (compileOptions & SH_MAP_LONG_VARIABLE_NAMES))
             mapLongVariableNames(root);
 
         if (success && (compileOptions & SH_ATTRIBUTES_UNIFORMS)) {
             collectAttribsUniforms(root);
@@ -229,16 +234,17 @@ bool TCompiler::InitBuiltInSymbolTable(c
 
     builtIns.initialize(shaderType, shaderSpec, resources);
     return InitializeSymbolTable(builtIns.getBuiltInStrings(),
         shaderType, shaderSpec, resources, infoSink, symbolTable);
 }
 
 void TCompiler::clearResults()
 {
+    arrayBoundsClamper.Cleanup();
     infoSink.info.erase();
     infoSink.obj.erase();
     infoSink.debug.erase();
 
     attribs.clear();
     uniforms.clear();
 
     builtInFunctionEmulator.Cleanup();
@@ -343,8 +349,14 @@ const TExtensionBehavior& TCompiler::get
 {
     return extensionBehavior;
 }
 
 const BuiltInFunctionEmulator& TCompiler::getBuiltInFunctionEmulator() const
 {
     return builtInFunctionEmulator;
 }
+
+const ArrayBoundsClamper& TCompiler::getArrayBoundsClamper() const
+{
+    return arrayBoundsClamper;
+}
+
--- a/gfx/angle/src/compiler/OutputGLSLBase.cpp
+++ b/gfx/angle/src/compiler/OutputGLSLBase.cpp
@@ -230,18 +230,47 @@ bool TOutputGLSLBase::visitBinary(Visit 
         case EOpVectorTimesMatrixAssign:
         case EOpVectorTimesScalarAssign:
         case EOpMatrixTimesScalarAssign:
         case EOpMatrixTimesMatrixAssign:
             writeTriplet(visit, "(", " *= ", ")");
             break;
 
         case EOpIndexDirect:
+            writeTriplet(visit, NULL, "[", "]");
+            break;
         case EOpIndexIndirect:
-            writeTriplet(visit, NULL, "[", "]");
+            if (node->getAddIndexClamp())
+            {
+                if (visit == InVisit)
+                {
+                    out << "[webgl_int_clamp(";
+                }
+                else if (visit == PostVisit)
+                {
+                    int maxSize;
+                    TIntermTyped *left = node->getLeft();
+                    TType leftType = left->getType();
+
+                    if (left->isArray())
+                    {
+                        // The shader will fail validation if the array length is not > 0.
+                        maxSize = leftType.getArraySize() - 1;
+                    }
+                    else
+                    {
+                        maxSize = leftType.getNominalSize() - 1;
+                    }
+                    out << ", 0, " << maxSize << ")]";
+                }
+            }
+            else
+            {
+                writeTriplet(visit, NULL, "[", "]");
+            }
             break;
         case EOpIndexDirectStruct:
             if (visit == InVisit)
             {
                 out << ".";
                 // TODO(alokp): ASSERT
                 out << node->getType().getFieldName();
                 visitChildren = false;
--- a/gfx/angle/src/compiler/ShHandle.h
+++ b/gfx/angle/src/compiler/ShHandle.h
@@ -11,16 +11,17 @@
 // Machine independent part of the compiler private objects
 // sent as ShHandle to the driver.
 //
 // This should not be included by driver code.
 //
 
 #include "GLSLANG/ShaderLang.h"
 
+#include "compiler/ArrayBoundsClamper.h"
 #include "compiler/BuiltInFunctionEmulator.h"
 #include "compiler/ExtensionBehavior.h"
 #include "compiler/InfoSink.h"
 #include "compiler/SymbolTable.h"
 #include "compiler/VariableInfo.h"
 
 class LongNameMap;
 class TCompiler;
@@ -96,30 +97,32 @@ protected:
     // Returns true if the shader does not use samplers.
     bool enforceVertexShaderTimingRestrictions(TIntermNode* root);
     // Returns true if the shader does not use sampler dependent values to affect control 
     // flow or in operations whose time can depend on the input values.
     bool enforceFragmentShaderTimingRestrictions(const TDependencyGraph& graph);
     // Get built-in extensions with default behavior.
     const TExtensionBehavior& getExtensionBehavior() const;
 
+    const ArrayBoundsClamper& getArrayBoundsClamper() const;
     const BuiltInFunctionEmulator& getBuiltInFunctionEmulator() const;
 
 private:
     ShShaderType shaderType;
     ShShaderSpec shaderSpec;
 
     int maxUniformVectors;
 
     // Built-in symbol table for the given language, spec, and resources.
     // It is preserved from compile-to-compile.
     TSymbolTable symbolTable;
     // Built-in extensions with default behavior.
     TExtensionBehavior extensionBehavior;
 
+    ArrayBoundsClamper arrayBoundsClamper;
     BuiltInFunctionEmulator builtInFunctionEmulator;
 
     // Results of compilation.
     TInfoSink infoSink;  // Output sink.
     TVariableInfoList attribs;  // Active attributes in the compiled shader.
     TVariableInfoList uniforms;  // Active uniforms in the compiled shader.
 
     // Cached copy of the ref-counted singleton.
--- a/gfx/angle/src/compiler/TranslatorESSL.cpp
+++ b/gfx/angle/src/compiler/TranslatorESSL.cpp
@@ -17,16 +17,19 @@ void TranslatorESSL::translate(TIntermNo
 
     // Write built-in extension behaviors.
     writeExtensionBehavior();
 
     // Write emulated built-in functions if needed.
     getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
         sink, getShaderType() == SH_FRAGMENT_SHADER);
 
+    // Write array bounds clamping emulation if needed.
+    getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
     // Write translated shader.
     TOutputESSL outputESSL(sink);
     root->traverse(&outputESSL);
 }
 
 void TranslatorESSL::writeExtensionBehavior() {
     TInfoSinkBase& sink = getInfoSink().obj;
     const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
--- a/gfx/angle/src/compiler/TranslatorGLSL.cpp
+++ b/gfx/angle/src/compiler/TranslatorGLSL.cpp
@@ -30,12 +30,15 @@ void TranslatorGLSL::translate(TIntermNo
 
     // Write GLSL version.
     writeVersion(getShaderType(), root, sink);
 
     // Write emulated built-in functions if needed.
     getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
         sink, false);
 
+    // Write array bounds clamping emulation if needed.
+    getArrayBoundsClamper().OutputClampingFunctionDefinition(sink);
+
     // Write translated shader.
     TOutputGLSL outputGLSL(sink);
     root->traverse(&outputGLSL);
 }
--- a/gfx/angle/src/compiler/intermOut.cpp
+++ b/gfx/angle/src/compiler/intermOut.cpp
@@ -37,17 +37,17 @@ protected:
 
 TString TType::getCompleteString() const
 {
     TStringStream stream;
 
     if (qualifier != EvqTemporary && qualifier != EvqGlobal)
         stream << getQualifierString() << " " << getPrecisionString() << " ";
     if (array)
-        stream << "array of ";
+        stream << "array[" << getArraySize() << "] of ";
     if (matrix)
         stream << size << "X" << size << " matrix of ";
     else if (size > 1)
         stream << size << "-component vector of ";
 
     stream << getBasicString();
     return stream.str();
 }
--- a/gfx/angle/src/compiler/intermediate.h
+++ b/gfx/angle/src/compiler/intermediate.h
@@ -384,30 +384,36 @@ protected:
     TOperator op;
 };
 
 //
 // Nodes for all the basic binary math operators.
 //
 class TIntermBinary : public TIntermOperator {
 public:
-    TIntermBinary(TOperator o) : TIntermOperator(o) {}
+    TIntermBinary(TOperator o) : TIntermOperator(o), addIndexClamp(false) {}
 
     virtual TIntermBinary* getAsBinaryNode() { return this; }
     virtual void traverse(TIntermTraverser*);
 
     void setLeft(TIntermTyped* n) { left = n; }
     void setRight(TIntermTyped* n) { right = n; }
     TIntermTyped* getLeft() const { return left; }
     TIntermTyped* getRight() const { return right; }
     bool promote(TInfoSink&);
 
+    void setAddIndexClamp() { addIndexClamp = true; }
+    bool getAddIndexClamp() { return addIndexClamp; }
+
 protected:
     TIntermTyped* left;
     TIntermTyped* right;
+
+    // If set to true, wrap any EOpIndexIndirect with a clamp to bounds.
+    bool addIndexClamp;
 };
 
 //
 // Nodes for unary math operators.
 //
 class TIntermUnary : public TIntermOperator {
 public:
     TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0), useEmulatedFunction(false) {}
--- a/gfx/angle/src/libGLESv2/Makefile.in
+++ b/gfx/angle/src/libGLESv2/Makefile.in
@@ -79,16 +79,17 @@ CPPSRCS = \
         SymbolTable.cpp \
         VariableInfo.cpp \
         compilerdebug.cpp \
         util.cpp \
         ValidateLimitations.cpp \
         ForLoopUnroll.cpp \
         MapLongVariableNames.cpp \
         spooky.cpp \
+        ArrayBoundsClamper.cpp \
         BuiltInFunctionEmulator.cpp \
         Input.cpp \
         Lexer.cpp \
         Preprocessor.cpp \
         Token.cpp \
         VariablePacker.cpp \
         $(NULL)