Bug 827106 - Cherry-pick ANGLE r1638 - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Tue, 05 Feb 2013 20:53:38 -0500
changeset 131640 57f2e0ad71a951ec321eb646cd627aad8f6d730e
parent 131639 b45420e3fa090064a31ed435543aafa2c371df82
child 131641 e6c3449a8ec625a80148499d6c38cee390648016
push id317
push userbbajaj@mozilla.com
push dateTue, 07 May 2013 01:20:33 +0000
treeherdermozilla-release@159a10910249 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs827106
milestone21.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 827106 - Cherry-pick ANGLE r1638 - r=jgilbert
gfx/angle/AUTHORS
gfx/angle/Makefile.in
gfx/angle/README.mozilla
gfx/angle/angle-r1638.patch
gfx/angle/include/GLSLANG/ShaderLang.h
gfx/angle/src/build_angle.gypi
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/compiler/translator_common.vcxproj
gfx/angle/src/libGLESv2/Makefile.in
--- 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
--- 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 \
--- 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
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
@@ -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();
--- 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',
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"
@@ -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;
+}
+
--- 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;
--- 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.
--- 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();
--- 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);
 }
--- 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
@@ -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) {}
--- 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>
--- 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 \