Roll ANGLE from 44bdc2af94e0 to 9aa6d3daf6a3 (10 revisions)

https://chromium.googlesource.com/angle/angle.git/+log/44bdc2af94e0..9aa6d3daf6a3

Please enable autosubmit on changes if possible when approving them.

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/angle-android-autoroll
Please CC angle-team@google.com,cnorthrop@google.com,rmistry@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in ANGLE: https://bugs.chromium.org/p/angleproject/issues/entry

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md

Test: Presubmit checks will test this change.
Exempt-From-Owner-Approval: The autoroll bot does not require owner approval.
Bug: b/336386662
Bug: b/336844257
Bug: b/338429767
Change-Id: I6b4f2d99251ea86fa328bb5984a9d39205fdec63
diff --git a/Android.bp b/Android.bp
index 1eee1b6..8bbd862 100644
--- a/Android.bp
+++ b/Android.bp
@@ -58,7 +58,7 @@
     cflags: [
         "-DANDROID",
         "-DANDROID_NDK_VERSION_ROLL=r26b_1",
-        "-DCR_CLANG_REVISION=\"llvmorg-19-init-8943-gd8503a38-3\"",
+        "-DCR_CLANG_REVISION=\"llvmorg-19-init-9433-g76ea5feb-1\"",
         "-DDYNAMIC_ANNOTATIONS_ENABLED=0",
         "-DHAVE_SYS_UIO_H",
         "-DNDEBUG",
@@ -536,6 +536,7 @@
         "src/libANGLE/renderer/vulkan/vk_helpers.cpp",
         "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp",
         "src/libANGLE/renderer/vulkan/vk_mandatory_format_support_table_autogen.cpp",
+        "src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp",
         "src/libANGLE/renderer/vulkan/vk_renderer.cpp",
         "src/libANGLE/renderer/vulkan/vk_resource.cpp",
         "src/libANGLE/renderer/vulkan/vk_utils.cpp",
@@ -2537,6 +2538,8 @@
         "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.cpp",
         "src/libANGLE/renderer/vulkan/vk_internal_shaders_autogen.h",
         "src/libANGLE/renderer/vulkan/vk_mandatory_format_support_table_autogen.cpp",
+        "src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp",
+        "src/libANGLE/renderer/vulkan/vk_ref_counted_event.h",
         "src/libANGLE/renderer/vulkan/vk_renderer.cpp",
         "src/libANGLE/renderer/vulkan/vk_renderer.h",
         "src/libANGLE/renderer/vulkan/vk_resource.cpp",
@@ -3275,7 +3278,7 @@
         "third_party_abseil_cpp_absl_algorithm_container",
         "third_party_abseil_cpp_absl_base_core_headers",
         "third_party_abseil_cpp_absl_container_container_memory",
-        "third_party_abseil_cpp_absl_container_hash_function_defaults",
+        "third_party_abseil_cpp_absl_container_hash_container_defaults",
         "third_party_abseil_cpp_absl_container_raw_hash_set",
         "third_party_abseil_cpp_absl_memory_memory",
     ],
@@ -5518,6 +5521,31 @@
 }
 
 cc_defaults {
+    name: "third_party_abseil_cpp_absl_container_hash_container_defaults",
+    defaults: [
+        "angle_common_auto_cflags",
+        "angle_common_library_cflags",
+        "third_party_abseil_cpp_absl_base_config",
+        "third_party_abseil_cpp_absl_container_hash_function_defaults",
+    ],
+    local_include_dirs: [
+        "",
+        "third_party/abseil-cpp/",
+    ],
+    cflags: [
+        "-DABSL_ALLOCATOR_NOTHROW=1",
+        "-Wno-c++11-narrowing",
+        "-Wno-gcc-compat",
+        "-Wno-misleading-indentation",
+        "-Wno-unreachable-code-break",
+        "-Wno-unused-but-set-variable",
+        "-Wno-unused-variable",
+    ],
+    sdk_version: "28",
+    stl: "libc++_static",
+}
+
+cc_defaults {
     name: "third_party_abseil_cpp_absl_base_base_internal",
     defaults: [
         "angle_common_auto_cflags",
@@ -5776,7 +5804,7 @@
         "third_party_abseil_cpp_absl_algorithm_container",
         "third_party_abseil_cpp_absl_base_core_headers",
         "third_party_abseil_cpp_absl_container_container_memory",
-        "third_party_abseil_cpp_absl_container_hash_function_defaults",
+        "third_party_abseil_cpp_absl_container_hash_container_defaults",
         "third_party_abseil_cpp_absl_container_raw_hash_map",
         "third_party_abseil_cpp_absl_memory_memory",
     ],
diff --git a/DEPS b/DEPS
index eaeacbb..f349b14 100644
--- a/DEPS
+++ b/DEPS
@@ -43,7 +43,7 @@
   'checkout_angle_mesa': False,
 
   # Version of Chromium our Chromium-based DEPS are mirrored from.
-  'chromium_revision': 'bc4f0a08ba8d4453fc183d3ef4d59889a3b1cdde',
+  'chromium_revision': 'b689a9ee3ba235e256fd93c93247692e1e260351',
   # We never want to checkout chromium,
   # but need a dummy DEPS entry for the autoroller
   'dummy_checkout_chromium': False,
@@ -88,7 +88,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'e84a4942dc4ae51442d256009f9d75a98ac680ac',
+  'catapult_revision': '0421a22c029768a46f06bdcd399fa2d0db6a66cb',
 
   # the commit queue can handle CLs rolling Fuchsia sdk
   # and whatever else without interference from each other.
@@ -97,7 +97,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling luci-go
   # and whatever else without interference from each other.
-  'luci_go': 'git_revision:01d1863acbd3d4c41da2aa7407a0ea6a195c770f',
+  'luci_go': 'git_revision:69f852c6aea2797c75712d59145efd38d7032196',
 
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
@@ -415,7 +415,7 @@
 deps = {
 
   'build': {
-    'url': Var('chromium_git') + '/chromium/src/build.git@0347db4c4f2ea6518b19403284bc31fbb46d1e2a',
+    'url': Var('chromium_git') + '/chromium/src/build.git@ce8359ec575d6e0c0427414fd5cc7e4b02c42acd',
     'condition': 'not build_with_chromium',
   },
 
@@ -474,12 +474,12 @@
   },
 
   'testing': {
-    'url': '{chromium_git}/chromium/src/testing@6ed3b71a7d8bee00517b5fb7d459628ae9661ad9',
+    'url': '{chromium_git}/chromium/src/testing@cdf49d0710d7c3fdefb2557b16a39b06ea00e61e',
     'condition': 'not build_with_chromium',
   },
 
   'third_party/abseil-cpp': {
-    'url': Var('chromium_git') + '/chromium/src/third_party/abseil-cpp@2c1ad970da6bd5837bcee6671da262eac0bd5397',
+    'url': Var('chromium_git') + '/chromium/src/third_party/abseil-cpp@31bdf8fec41f04dfe86976734cbad22ded4ca1f7',
     'condition': 'not build_with_chromium',
   },
 
@@ -656,7 +656,7 @@
   },
 
   'third_party/depot_tools': {
-    'url': Var('chromium_git') + '/chromium/tools/depot_tools.git@e75b940aeabcca1ea7e38881231e73a32a352753',
+    'url': Var('chromium_git') + '/chromium/tools/depot_tools.git@39c8c75cf6a2690957f3de7367a301358c5f3c15',
     'condition': 'not build_with_chromium',
   },
 
@@ -859,7 +859,7 @@
   },
 
   'third_party/protobuf': {
-    'url': Var('chromium_git') + '/chromium/src/third_party/protobuf@4da68f31de3c95cc15ef5c381d05290eaf5f4585',
+    'url': Var('chromium_git') + '/chromium/src/third_party/protobuf@4abbe88863a7dd75dd11da0487e9b995133f7592',
     'condition': 'not build_with_chromium',
   },
 
@@ -872,7 +872,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/r8',
-              'version': 'eec4ZxEvkO7Pa1LUWDkVKiCv0bZjS7ctubjxW94ZYVYC',
+              'version': 'fXvmQSzprkeb1fs3dnkBm_gsAhb5aUtQGRmUq3Oi1WYC',
           },
       ],
       'condition': 'checkout_android and not build_with_chromium',
@@ -959,12 +959,12 @@
   },
 
   'tools/android': {
-    'url': Var('chromium_git') + '/chromium/src/tools/android@49bb033593621ee4977cd0dd58e0412035d6bab5',
+    'url': Var('chromium_git') + '/chromium/src/tools/android@cc51a5ea8611565ff48db1a11c08e90d03484bd2',
     'condition': 'checkout_android and not build_with_chromium',
   },
 
   'tools/clang': {
-    'url': Var('chromium_git') + '/chromium/src/tools/clang.git@cc8e1423f4ade8b4871bc33fa44f061826bff2ff',
+    'url': Var('chromium_git') + '/chromium/src/tools/clang.git@17956d4ffb817dcd19e19c60d5162bcf15ff2034',
     'condition': 'not build_with_chromium',
   },
 
@@ -995,7 +995,7 @@
   },
 
   'tools/mb': {
-    'url': Var('chromium_git') + '/chromium/src/tools/mb@880331b699ae470dbb88118f9155a238fe0d1b0f',
+    'url': Var('chromium_git') + '/chromium/src/tools/mb@668bf195ba3390e4208cc1edc4777fa5747cb9f7',
     'condition': 'not build_with_chromium',
   },
 
@@ -1010,7 +1010,7 @@
   },
 
   'tools/perf': {
-    'url': Var('chromium_git') + '/chromium/src/tools/perf@73a1c67b512eb876d032ebfb3b539150a4fcd801',
+    'url': Var('chromium_git') + '/chromium/src/tools/perf@7ef4ff5ba36be22f641d0f08f34402f85db18492',
     'condition': 'not build_with_chromium',
   },
 
@@ -1028,7 +1028,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/linux-amd64',
-          'version': 'AJacKGh5nnjmNZk56j2ia4-QtIE8eEAFELw48t8XinEC',
+          'version': '4Ox2OXGb8xipJPUsrFptKWJNJelzwWHBB3ORF1iHt94C',
         },
       ],
       'dep_type': 'cipd',
@@ -1039,7 +1039,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/windows-amd64',
-          'version': '4bTyiie8-MG6hBk2yGEE9d8p3HWHGevaAouvGfKKwtQC',
+          'version': 'CBmdgsk0TAPgochRHBMBS9LZzdhYMOsNaJSAPvA-e-YC',
         },
       ],
       'dep_type': 'cipd',
@@ -1050,7 +1050,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-amd64',
-          'version': 'uJJWpJUp-FSzEXlwqzoUD41p5swLKyDhxXdJBLShbMsC',
+          'version': '-H7DJpIRXUmi9ddRqVRJXThT1nlK7ns94UOnHMmeP4IC',
         },
       ],
       'dep_type': 'cipd',
@@ -1061,7 +1061,7 @@
       'packages': [
         {
           'package': 'skia/tools/goldctl/mac-arm64',
-          'version': 'ekRiJKPFBJKiZ3N4ev_vRuf2X13dgTDcZNXKYt2qZPoC',
+          'version': 'FclksBOdZsrGv0dS7P163Fl3zi60z6nQCDXMNOoAYLYC',
         },
       ],
       'dep_type': 'cipd',
diff --git a/build/android/docs/java_optimization.md b/build/android/docs/java_optimization.md
index da10222..7d32294 100644
--- a/build/android/docs/java_optimization.md
+++ b/build/android/docs/java_optimization.md
@@ -118,7 +118,7 @@
     * Caching the result of `ClassNameJni.get()` in a member variable.
     * Passing a native wrapper method reference instead of using a lambda (i.e.
       `Jni.get()::methodName` vs. `() -> Jni.get.methodName()`).
-  * For more debugging info, add to `base/android/proguard/chromium_code.flags`:
+  * For more debugging info, add to `base/android/proguard/chromium_apk.flags`:
       ```
       -whyareyounotinlining class org.chromium.base.library_loader.LibraryPrefetcherJni {
           <init>();
diff --git a/build/android/gyp/gcc_preprocess.py b/build/android/gyp/gcc_preprocess.py
index 0302c07..b43a55d 100755
--- a/build/android/gyp/gcc_preprocess.py
+++ b/build/android/gyp/gcc_preprocess.py
@@ -15,6 +15,10 @@
 import action_helpers  # build_utils adds //build to sys.path.
 import zip_helpers
 
+_CHROMIUM_SRC = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir,
+                             os.pardir)
+_LLVM_CLANG_PATH = os.path.join(_CHROMIUM_SRC, 'third_party', 'llvm-build',
+                                'Release+Asserts', 'bin', 'clang')
 
 def _ParsePackageName(data):
   m = re.match(r'^\s*package\s+(.*?)\s*;', data, re.MULTILINE)
@@ -22,17 +26,17 @@
 
 
 def ProcessJavaFile(template, defines, include_dirs):
-  gcc_cmd = [
-      'gcc',
+  clang_cmd = [
+      _LLVM_CLANG_PATH,
       '-E',  # stop after preprocessing.
       '-DANDROID',  # Specify ANDROID define for pre-processor.
       '-x',
       'c-header',  # treat sources as C header files
       '-P',  # disable line markers, i.e. '#line 309'
   ]
-  gcc_cmd.extend('-D' + x for x in defines)
-  gcc_cmd.extend('-I' + x for x in include_dirs)
-  data = build_utils.CheckOutput(gcc_cmd + [template])
+  clang_cmd.extend('-D' + x for x in defines)
+  clang_cmd.extend('-I' + x for x in include_dirs)
+  data = build_utils.CheckOutput(clang_cmd + [template])
   package_name = _ParsePackageName(data)
   if not package_name:
     raise Exception('Could not find java package of ' + template)
diff --git a/build/android/gyp/util/diff_utils.py b/build/android/gyp/util/diff_utils.py
index 445bbe3..6d980b5 100644
--- a/build/android/gyp/util/diff_utils.py
+++ b/build/android/gyp/util/diff_utils.py
@@ -4,6 +4,7 @@
 
 import difflib
 import os
+import pathlib
 import sys
 
 from util import build_utils
@@ -48,6 +49,8 @@
   return ''.join(filtered_diff)
 
 
+_REBASELINE_PROGUARD = os.environ.get('REBASELINE_PROGUARD', '0') != '0'
+
 def _DiffFileContents(expected_path, actual_data):
   """Check file contents for equality and return the diff or None."""
   # Remove all trailing whitespace and add it explicitly in the end.
@@ -60,6 +63,11 @@
   if expected_lines == actual_lines:
     return None
 
+  if _REBASELINE_PROGUARD:
+    pathlib.Path(expected_path).write_text('\n'.join(actual_lines))
+    print(f'Updated {expected_path}')
+    return None
+
   expected_path = os.path.relpath(expected_path, build_utils.DIR_SOURCE_ROOT)
 
   diff = difflib.unified_diff(
@@ -94,7 +102,6 @@
                      action='store_true',
                      help='Verify the expectation and exit.')
 
-
 def CheckExpectations(actual_data, options, custom_msg=''):
   if options.actual_file:
     with action_helpers.atomic_output(options.actual_file) as f:
@@ -107,6 +114,8 @@
   if not diff_text:
     fail_msg = ''
   else:
+    # The space before the `patch` command is intentional, as it causes the line
+    # to not be saved in bash history for most configurations.
     fail_msg = """
 Expectations need updating:
 https://chromium.googlesource.com/chromium/src/+/HEAD/chrome/android/expectations/README.md
@@ -122,6 +131,9 @@
 {}
 END_DIFF
 ############ END ############
+
+If you are running this locally, you can `export REBASELINE_PROGUARD=1` to
+automatically apply this patch.
 """.format(custom_msg, diff_text)
 
     sys.stderr.write(fail_msg)
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 26fad5a..b8cac29 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -713,6 +713,11 @@
     default_component_configs -=
         [ "//build/config/android:hide_all_but_jni_onload" ]
   }
+  if (is_win) {
+    # We don't want component dlls to statically load OS dlls that aren't
+    # loaded normally.
+    default_component_configs += [ "//build/config/win:delayloads" ]
+  }
 } else {
   default_component_configs = default_compiler_configs
 }
diff --git a/build/config/android/abi.gni b/build/config/android/abi.gni
index 09f0af8..0f1eb65 100644
--- a/build/config/android/abi.gni
+++ b/build/config/android/abi.gni
@@ -8,7 +8,7 @@
 # NOTE: Because Chrome OS builds may depend on targets built with the Android
 # toolchain, this GNI file may be read and processed from within Chrome OS
 # toolchains. Checking |is_android| here would therefore be too restrictive.
-assert(is_android || is_chromeos)
+assert(is_android || is_chromeos || is_robolectric)
 
 declare_args() {
   # Adds intrumentation to each function. Writes a file with the order that
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 20bd196..87fc7c9 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -2,127 +2,122 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/android/abi.gni")
+import("//build/config/android/copy_ex.gni")
+import("//build/config/clang/clang.gni")
+import("//build/config/sanitizers/sanitizers.gni")
 import("//build_overrides/build.gni")
 
 assert(
     is_android || is_robolectric,
     "current_toolchain=$current_toolchain default_toolchain=$default_toolchain")
 
-if (is_robolectric) {
-  template("create_native_executable_dist") {
-    not_needed(invoker, [ "*" ])
+_sanitizer_runtimes = []
+if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) {
+  _sanitizer_runtimes += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-$sanitizer_arch-android.so" ]
+}
+if (is_asan) {
+  _sanitizer_runtimes += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.asan-$sanitizer_arch-android.so" ]
+}
+
+# Creates a dist directory for a native executable.
+#
+# Running a native executable on a device requires all the shared library
+# dependencies of that executable. To make it easier to install and run such an
+# executable, this will create a directory containing the native exe and all
+# it's library dependencies.
+#
+# Note: It's usually better to package things as an APK than as a native
+# executable.
+#
+# Variables
+#   dist_dir: Directory for the exe and libraries. Everything in this directory
+#     will be deleted before copying in the exe and libraries.
+#   binary: Path to (stripped) executable.
+#   extra_files: List of extra files to copy in (optional).
+#
+# Example
+#   create_native_executable_dist("foo_dist") {
+#     dist_dir = "$root_build_dir/foo_dist"
+#     binary = "$root_build_dir/foo"
+#     deps = [ ":the_thing_that_makes_foo" ]
+#   }
+template("create_native_executable_dist") {
+  forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
+
+  _libraries_list = "${target_gen_dir}/${target_name}_library_dependencies.list"
+
+  _sanitizer_runtimes_target_name = "${target_name}__sanitizer_runtimes"
+  group(_sanitizer_runtimes_target_name) {
+    metadata = {
+      shared_libraries = _sanitizer_runtimes
+    }
   }
-} else if (enable_java_templates) {
-  import("//build/config/android/abi.gni")
+
+  generated_file("${target_name}__library_list") {
+    forward_variables_from(invoker, [ "deps" ])
+    if (!defined(deps)) {
+      deps = []
+    }
+    deps += [ ":${_sanitizer_runtimes_target_name}" ]
+    output_conversion = "json"
+    outputs = [ _libraries_list ]
+    data_keys = [ "shared_libraries" ]
+    walk_keys = [ "shared_libraries_barrier" ]
+    rebase = root_build_dir
+  }
+
+  copy_ex(target_name) {
+    inputs = [
+      _libraries_list,
+      invoker.binary,
+    ]
+
+    dest = invoker.dist_dir
+    data = [ "${invoker.dist_dir}/" ]
+
+    _rebased_libraries_list = rebase_path(_libraries_list, root_build_dir)
+    _rebased_binaries_list = rebase_path([ invoker.binary ], root_build_dir)
+    args = [
+      "--clear",
+      "--files=@FileArg($_rebased_libraries_list)",
+      "--files=$_rebased_binaries_list",
+    ]
+    if (defined(invoker.extra_files)) {
+      _rebased_extra_files = rebase_path(invoker.extra_files, root_build_dir)
+      args += [ "--files=$_rebased_extra_files" ]
+    }
+
+    _depfile = "$target_gen_dir/$target_name.d"
+    _stamp_file = "$target_gen_dir/$target_name.stamp"
+    outputs = [ _stamp_file ]
+    args += [
+      "--depfile",
+      rebase_path(_depfile, root_build_dir),
+      "--stamp",
+      rebase_path(_stamp_file, root_build_dir),
+    ]
+
+    deps = [ ":${target_name}__library_list" ]
+    if (defined(invoker.deps)) {
+      deps += invoker.deps
+    }
+  }
+}
+
+if (!is_robolectric && enable_java_templates) {
   import("//build/config/android/config.gni")
-  import("//build/config/android/copy_ex.gni")
   import("//build/config/android/internal_rules.gni")
-  import("//build/config/clang/clang.gni")
   import("//build/config/compiler/compiler.gni")
   import("//build/config/coverage/coverage.gni")
   import("//build/config/profiling/profiling.gni")
   import("//build/config/python.gni")
-  import("//build/config/sanitizers/sanitizers.gni")
   import("//build/config/zip.gni")
   import("//build/toolchain/toolchain.gni")
 
   _BUNDLETOOL_JAR_PATH =
       "//third_party/android_build_tools/bundletool/bundletool.jar"
 
-  _sanitizer_runtimes = []
-  if (use_cfi_diag || is_ubsan || is_ubsan_security || is_ubsan_vptr) {
-    _sanitizer_runtimes += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.ubsan_standalone-$sanitizer_arch-android.so" ]
-  }
-  if (is_asan) {
-    _sanitizer_runtimes += [ "$clang_base_path/lib/clang/$clang_version/lib/linux/libclang_rt.asan-$sanitizer_arch-android.so" ]
-  }
-
-  # Creates a dist directory for a native executable.
-  #
-  # Running a native executable on a device requires all the shared library
-  # dependencies of that executable. To make it easier to install and run such an
-  # executable, this will create a directory containing the native exe and all
-  # it's library dependencies.
-  #
-  # Note: It's usually better to package things as an APK than as a native
-  # executable.
-  #
-  # Variables
-  #   dist_dir: Directory for the exe and libraries. Everything in this directory
-  #     will be deleted before copying in the exe and libraries.
-  #   binary: Path to (stripped) executable.
-  #   extra_files: List of extra files to copy in (optional).
-  #
-  # Example
-  #   create_native_executable_dist("foo_dist") {
-  #     dist_dir = "$root_build_dir/foo_dist"
-  #     binary = "$root_build_dir/foo"
-  #     deps = [ ":the_thing_that_makes_foo" ]
-  #   }
-  template("create_native_executable_dist") {
-    forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
-
-    _libraries_list =
-        "${target_gen_dir}/${target_name}_library_dependencies.list"
-
-    _sanitizer_runtimes_target_name = "${target_name}__sanitizer_runtimes"
-    group(_sanitizer_runtimes_target_name) {
-      metadata = {
-        shared_libraries = _sanitizer_runtimes
-      }
-    }
-
-    generated_file("${target_name}__library_list") {
-      forward_variables_from(invoker, [ "deps" ])
-      if (!defined(deps)) {
-        deps = []
-      }
-      deps += [ ":${_sanitizer_runtimes_target_name}" ]
-      output_conversion = "json"
-      outputs = [ _libraries_list ]
-      data_keys = [ "shared_libraries" ]
-      walk_keys = [ "shared_libraries_barrier" ]
-      rebase = root_build_dir
-    }
-
-    copy_ex(target_name) {
-      inputs = [
-        _libraries_list,
-        invoker.binary,
-      ]
-
-      dest = invoker.dist_dir
-      data = [ "${invoker.dist_dir}/" ]
-
-      _rebased_libraries_list = rebase_path(_libraries_list, root_build_dir)
-      _rebased_binaries_list = rebase_path([ invoker.binary ], root_build_dir)
-      args = [
-        "--clear",
-        "--files=@FileArg($_rebased_libraries_list)",
-        "--files=$_rebased_binaries_list",
-      ]
-      if (defined(invoker.extra_files)) {
-        _rebased_extra_files = rebase_path(invoker.extra_files, root_build_dir)
-        args += [ "--files=$_rebased_extra_files" ]
-      }
-
-      _depfile = "$target_gen_dir/$target_name.d"
-      _stamp_file = "$target_gen_dir/$target_name.stamp"
-      outputs = [ _stamp_file ]
-      args += [
-        "--depfile",
-        rebase_path(_depfile, root_build_dir),
-        "--stamp",
-        rebase_path(_stamp_file, root_build_dir),
-      ]
-
-      deps = [ ":${target_name}__library_list" ]
-      if (defined(invoker.deps)) {
-        deps += invoker.deps
-      }
-    }
-  }
-
   # Declare a target for c-preprocessor-generated java files
   #
   # NOTE: For generating Java conterparts to enums prefer using the java_cpp_enum
diff --git a/build/config/compiler/compiler.gni b/build/config/compiler/compiler.gni
index dff2958..0cfbb31 100644
--- a/build/config/compiler/compiler.gni
+++ b/build/config/compiler/compiler.gni
@@ -39,7 +39,8 @@
 
   # If true, optimize for size.
   # Default to favoring speed over size for platforms not listed below.
-  optimize_for_size = !is_high_end_android && (is_android || is_castos)
+  optimize_for_size =
+      !is_high_end_android && (is_android || is_castos || is_fuchsia)
 }
 
 declare_args() {
diff --git a/build/config/fuchsia/size_optimized_cast_receiver_args.gn b/build/config/fuchsia/size_optimized_cast_receiver_args.gn
index 86abbc1..c716dab 100644
--- a/build/config/fuchsia/size_optimized_cast_receiver_args.gn
+++ b/build/config/fuchsia/size_optimized_cast_receiver_args.gn
@@ -34,7 +34,6 @@
 enable_logging_override = true
 enable_pdf = false
 enable_plugins = false
-optimize_for_size = true
 optional_trace_events_enabled = false
 
 # Ensure PGO and ThinLTO are disabled as these optimizations increase the binary
diff --git a/build/config/siso/clang_linux.star b/build/config/siso/clang_linux.star
index f0ad598..5604113 100644
--- a/build/config/siso/clang_linux.star
+++ b/build/config/siso/clang_linux.star
@@ -124,6 +124,9 @@
         ],
     })
     step_config["input_deps"].update(clang_all.input_deps)
+
+    # Disable remote compiles on Clang ToT builds.
+    remote = not config.get(ctx, "clang-tot")
     step_config["rules"].extend([
         {
             "name": "clang/cxx",
@@ -133,7 +136,7 @@
                 "third_party/llvm-build/Release+Asserts/bin/clang++",
             ],
             "exclude_input_patterns": ["*.stamp"],
-            "remote": True,
+            "remote": remote,
             "canonicalize_dir": True,
             "timeout": "2m",
         },
@@ -145,7 +148,7 @@
                 "third_party/llvm-build/Release+Asserts/bin/clang",
             ],
             "exclude_input_patterns": ["*.stamp"],
-            "remote": True,
+            "remote": remote,
             "canonicalize_dir": True,
             "timeout": "2m",
         },
@@ -156,7 +159,7 @@
             "inputs": [
                 "third_party/llvm-build/Release+Asserts/bin/clang",
             ],
-            "remote": config.get(ctx, "cog"),
+            "remote": remote and config.get(ctx, "cog"),
             "canonicalize_dir": True,
             "timeout": "2m",
         },
@@ -169,7 +172,7 @@
             ],
             "exclude_input_patterns": ["*.stamp"],
             "handler": "clang_compile_coverage",
-            "remote": True,
+            "remote": remote,
             "canonicalize_dir": True,
             "timeout": "2m",
         },
@@ -182,7 +185,7 @@
             ],
             "exclude_input_patterns": ["*.stamp"],
             "handler": "clang_compile_coverage",
-            "remote": True,
+            "remote": remote,
             "canonicalize_dir": True,
             "timeout": "2m",
         },
diff --git a/build/config/siso/clang_mac.star b/build/config/siso/clang_mac.star
index 5af698a..852189f 100644
--- a/build/config/siso/clang_mac.star
+++ b/build/config/siso/clang_mac.star
@@ -9,6 +9,7 @@
 load("@builtin//struct.star", "module")
 load("./clang_all.star", "clang_all")
 load("./clang_code_coverage_wrapper.star", "clang_code_coverage_wrapper")
+load("./config.star", "config")
 load("./rewrapper_cfg.star", "rewrapper_cfg")
 
 def __filegroups(ctx):
@@ -94,6 +95,9 @@
             # objc/objcxx uses hmap, which contains absolute path
             # see also b/256536089
             need_input_root_absolute_path_for_objc = True
+
+        # Disable remote compiles on Clang ToT builds.
+        remote = not config.get(ctx, "clang-tot")
         step_config["rules"].extend([
             {
                 "name": "clang/cxx",
@@ -104,7 +108,7 @@
                 ],
                 "exclude_input_patterns": ["*.stamp"],
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
             },
@@ -117,7 +121,7 @@
                 ],
                 "exclude_input_patterns": ["*.stamp"],
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
             },
@@ -130,7 +134,7 @@
                 ],
                 "exclude_input_patterns": ["*.stamp"],
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
                 "input_root_absolute_path": need_input_root_absolute_path_for_objc,
@@ -144,7 +148,7 @@
                 ],
                 "exclude_input_patterns": ["*.stamp"],
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
                 "input_root_absolute_path": need_input_root_absolute_path_for_objc,
@@ -159,7 +163,7 @@
                 "exclude_input_patterns": ["*.stamp"],
                 "handler": "clang_compile_coverage",
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
             },
@@ -173,7 +177,7 @@
                 "exclude_input_patterns": ["*.stamp"],
                 "handler": "clang_compile_coverage",
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
             },
@@ -187,7 +191,7 @@
                 "exclude_input_patterns": ["*.stamp"],
                 "handler": "clang_compile_coverage",
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
                 "input_root_absolute_path": need_input_root_absolute_path_for_objc,
@@ -202,7 +206,7 @@
                 "exclude_input_patterns": ["*.stamp"],
                 "handler": "clang_compile_coverage",
                 "platform_ref": "clang",
-                "remote": True,
+                "remote": remote,
                 "remote_wrapper": reproxy_config["remote_wrapper"],
                 "timeout": "2m",
                 "input_root_absolute_path": need_input_root_absolute_path_for_objc,
diff --git a/build/config/siso/clang_windows.star b/build/config/siso/clang_windows.star
index 3d755eb..42f306c 100644
--- a/build/config/siso/clang_windows.star
+++ b/build/config/siso/clang_windows.star
@@ -9,6 +9,7 @@
 load("@builtin//struct.star", "module")
 load("./clang_all.star", "clang_all")
 load("./clang_code_coverage_wrapper.star", "clang_code_coverage_wrapper")
+load("./config.star", "config")
 load("./rewrapper_cfg.star", "rewrapper_cfg")
 
 def __win_toolchain_dir(ctx):
@@ -75,9 +76,11 @@
         # missing build/win_toolchain.json), we can't run
         # clang-cl remotely as we can find sysroot files
         # under exec_root, so just run locally.
+        # When building with ToT Clang, we can't run clang-cl
+        # remotely, too.
         remote = False
         win_toolchain_dir = __win_toolchain_dir(ctx)
-        if win_toolchain_dir:
+        if win_toolchain_dir and not config.get(ctx, "clang-tot"):
             remote = True
             if reproxy_config["platform"]["OSFamily"] == "Windows":
                 step_config["input_deps"].update({
diff --git a/build/config/siso/config.star b/build/config/siso/config.star
index 800b90e..95c0c47 100644
--- a/build/config/siso/config.star
+++ b/build/config/siso/config.star
@@ -23,6 +23,9 @@
     # TODO: b/316267242 - Enable remote links after confirming performance.
     "remote-library-link",
     "remote-exec-link",
+
+    # Clang ToT builds don't run compile actions remotely.
+    "clang-tot",
 ]
 
 def __check(ctx):
diff --git a/build/config/siso/rust_linux.star b/build/config/siso/rust_linux.star
index 3301aa6..7b47477 100644
--- a/build/config/siso/rust_linux.star
+++ b/build/config/siso/rust_linux.star
@@ -103,12 +103,20 @@
 
     ctx.actions.fix(inputs = cmd.inputs + inputs)
 
+def __rust_build_handler(ctx, cmd):
+    inputs = []
+    for i, arg in enumerate(cmd.args):
+        if arg == "--src-dir":
+            inputs.append(ctx.fs.canonpath(cmd.args[i + 1]))
+    ctx.actions.fix(inputs = cmd.inputs + inputs)
+
 __handlers = {
     "rust_bin_handler": __rust_bin_handler,
+    "rust_build_handler": __rust_build_handler,
 }
 
 def __step_config(ctx, step_config):
-    remote_run = True  # Turn this to False when you do file access trace.
+    remote_run = not config.get(ctx, "clang-tot")  # Turn this to False when you do file access trace.
     platform_ref = "large"  # Rust actions run faster on large workers.
     clang_inputs = [
         "build/linux/debian_bullseye_amd64-sysroot:rustlink",
@@ -195,12 +203,8 @@
                 "build/gn_helpers.py",
                 "third_party/rust-toolchain:toolchain",
                 "third_party/rust:rustlib",
-                # XXX: -src-dir?
-                "third_party/rust-toolchain/lib/rustlib/src/rust/library/std",
-                "third_party/rust-toolchain/lib/rustlib/src/rust/vendor/libc-0.2.153",
-                "third_party/rust-toolchain/lib/rustlib/src/rust/vendor/memchr-2.5.0",
-                "third_party/rust-toolchain/lib/rustlib/src/rust/vendor/compiler_builtins-0.1.108",
             ],
+            "handler": "rust_build_handler",
             "remote": config.get(ctx, "cog"),
             "input_root_absolute_path": True,
             "timeout": "2m",
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index 6dbe648..1a15bf9 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1,2 +1,2 @@
-LASTCHANGE=0347db4c4f2ea6518b19403284bc31fbb46d1e2a-refs/heads/main@{#1294809}
+LASTCHANGE=ce8359ec575d6e0c0427414fd5cc7e4b02c42acd-refs/heads/main@{#1295863}
 LASTCHANGE_YEAR=2024
diff --git a/build/util/LASTCHANGE.committime b/build/util/LASTCHANGE.committime
index 95451e6..2bb340c 100644
--- a/build/util/LASTCHANGE.committime
+++ b/build/util/LASTCHANGE.committime
@@ -1 +1 @@
-1714550162
\ No newline at end of file
+1714695969
\ No newline at end of file
diff --git a/build/util/ide_query b/build/util/ide_query
index 5286df4..7f0fec7 100755
--- a/build/util/ide_query
+++ b/build/util/ide_query
@@ -89,7 +89,9 @@
         options.out_dir,
     ])
     args.extend(targets)
-    p = subprocess.run(args, cwd=repo_root, stdout=2, stderr=2)
+    env = os.environ.copy()
+    env['SISO_EXPERIMENTS'] = 'no-fast-deps'
+    p = subprocess.run(args, cwd=repo_root, stdout=2, stderr=2, env=env)
     if p.returncode != 0:
       # TODO: report error in IdeAnalysis.Status?
       sys.stderr.write('build failed with %d\n' % p.returncode)
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 0d6ca0f..f1983aa 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -46,6 +46,11 @@
     short_name: "asan"
   }
   builders {
+    name: "buildbucket/luci.angle.ci/linux-exp-test"
+    category: "test|linux|x64"
+    short_name: "exp"
+  }
+  builders {
     name: "buildbucket/luci.angle.ci/linux-tsan-test"
     category: "test|linux|x64"
     short_name: "tsan"
@@ -178,9 +183,6 @@
     name: "buildbucket/luci.angle.ci/linux-exp-asan-test"
   }
   builders {
-    name: "buildbucket/luci.angle.ci/linux-exp-test"
-  }
-  builders {
     name: "buildbucket/luci.angle.ci/linux-exp-tsan-test"
   }
   builders {
diff --git a/infra/config/main.star b/infra/config/main.star
index cd94109..1533f83 100755
--- a/infra/config/main.star
+++ b/infra/config/main.star
@@ -322,6 +322,7 @@
     active_experimental_builders = [
         "android-arm64-exp-test",
         "android-arm64-exp-s22-test",
+        "linux-exp-test",
         "mac-exp-test",
     ]
 
diff --git a/infra/specs/angle.json b/infra/specs/angle.json
index 560f08d..2d2cbff 100644
--- a/infra/specs/angle.json
+++ b/infra/specs/angle.json
@@ -16,7 +16,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -43,7 +43,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -70,7 +70,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -96,7 +96,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -122,7 +122,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -149,7 +149,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -175,7 +175,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -201,7 +201,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -231,7 +231,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -260,7 +260,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -289,7 +289,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -318,7 +318,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -348,7 +348,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -378,7 +378,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -407,7 +407,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -436,7 +436,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -465,7 +465,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -494,7 +494,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -521,7 +521,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -546,7 +546,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -572,7 +572,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -604,7 +604,7 @@
         "swarming": {
           "containment_type": "AUTO",
           "dimensions": {
-            "device_os": "UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002",
+            "device_os": "AP1A.240405.002",
             "device_os_type": "userdebug",
             "device_type": "oriole",
             "os": "Android",
@@ -2795,7 +2795,291 @@
     ]
   },
   "linux-amd": {},
-  "linux-exp-intel": {},
+  "linux-exp-intel": {
+    "gtest_tests": [
+      {
+        "args": [
+          "--use-angle=gl",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "script": "//scripts/angle_deqp_test_merge.py"
+        },
+        "name": "angle_deqp_gles2_gl_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_deqp_gles2_tests",
+        "test_id_prefix": "ninja://src/tests:angle_deqp_gles2_tests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "args": [
+          "--gtest_filter=-*Vulkan_SwiftShader*",
+          "--max-processes=4",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_end2end_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "angle_end2end_tests",
+        "test_id_prefix": "ninja://src/tests:angle_end2end_tests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "args": [
+          "--test-timeout=300",
+          "--batch-size=10",
+          "--no-xvfb"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_gles1_conformance_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_gles1_conformance_tests",
+        "test_id_prefix": "ninja://src/tests:angle_gles1_conformance_tests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_unittests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_unittests",
+        "test_id_prefix": "ninja://src/tests:angle_unittests/",
+        "use_isolated_scripts_api": true
+      },
+      {
+        "args": [
+          "--no-xvfb"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_white_box_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_white_box_tests",
+        "test_id_prefix": "ninja://src/tests:angle_white_box_tests/",
+        "use_isolated_scripts_api": true
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "args": [
+          "--log=debug"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_capture_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_capture_tests",
+        "test_id_prefix": "ninja://src/tests:angle_capture_tests/"
+      },
+      {
+        "args": [
+          "--log=debug",
+          "--smoke-test-mode",
+          "--show-test-stdout"
+        ],
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//scripts/process_angle_perf_results.py"
+        },
+        "name": "angle_perftests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "angle_perftests",
+        "test_id_prefix": "ninja://src/tests:angle_perftests/"
+      },
+      {
+        "args": [
+          "--test-machine-name",
+          "${buildername}",
+          "--trace-interpreter=gz",
+          "--filter=fishdom:geometry_dash:merge_dragons:minecraft_bedrock:new_legend_of_the_condor_heroes:street_fighter_duel:teslagrad:vainglory",
+          "--git-revision=${got_angle_revision}"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_restricted_trace_gold_interpreted_tests",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}",
+          "--use-permissive-pixel-comparison=${use_permissive_angle_pixel_comparison}"
+        ],
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_restricted_trace_gold_tests",
+        "test_id_prefix": "ninja://src/tests/restricted_traces:angle_restricted_trace_gold_tests/"
+      },
+      {
+        "args": [
+          "--test-machine-name",
+          "${buildername}",
+          "--git-revision=${got_angle_revision}"
+        ],
+        "merge": {
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "angle_restricted_trace_gold_tests",
+        "precommit_args": [
+          "--gerrit-issue=${patch_issue}",
+          "--gerrit-patchset=${patch_set}",
+          "--buildbucket-id=${buildbucket_build_id}",
+          "--use-permissive-pixel-comparison=${use_permissive_angle_pixel_comparison}"
+        ],
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "angle_restricted_trace_gold_tests",
+        "test_id_prefix": "ninja://src/tests/restricted_traces:angle_restricted_trace_gold_tests/"
+      },
+      {
+        "args": [
+          "--log=debug",
+          "--smoke-test-mode",
+          "--show-test-stdout",
+          "--use-gl=native",
+          "--trace-tests"
+        ],
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//scripts/process_angle_perf_results.py"
+        },
+        "name": "angle_trace_perf_native_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "angle_trace_perf_tests",
+        "test_id_prefix": "ninja://src/tests:angle_trace_perf_tests/"
+      },
+      {
+        "args": [
+          "--log=debug",
+          "--smoke-test-mode",
+          "--show-test-stdout",
+          "--use-angle=vulkan",
+          "--trace-tests"
+        ],
+        "merge": {
+          "args": [
+            "--smoke-test-mode"
+          ],
+          "script": "//scripts/process_angle_perf_results.py"
+        },
+        "name": "angle_trace_perf_vulkan_tests",
+        "swarming": {
+          "containment_type": "AUTO",
+          "dimensions": {
+            "display_attached": "1",
+            "gpu": "8086:9bc5-23.2.1",
+            "os": "Ubuntu-22.04.4",
+            "pool": "chromium.tests.gpu"
+          },
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
+          "shards": 2
+        },
+        "test": "angle_trace_perf_tests",
+        "test_id_prefix": "ninja://src/tests:angle_trace_perf_tests/"
+      }
+    ]
+  },
   "linux-exp-swiftshader": {},
   "linux-exp-swiftshader-asan": {},
   "linux-exp-swiftshader-tsan": {},
@@ -5743,192 +6027,7 @@
       }
     ]
   },
-  "mac-exp-intel": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--use-angle=gl",
-          "--max-processes=1"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_egl_gl_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_egl_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_egl_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--use-angle=metal"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_egl_metal_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_egl_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_egl_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--use-angle=gl",
-          "--flaky-retries=2"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_gles2_gl_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles2_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--use-angle=metal",
-          "--flaky-retries=2"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_gles2_metal_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_deqp_gles2_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_gles2_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--use-angle=gl",
-          "--flaky-retries=2"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_gles3_gl_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "angle_deqp_gles3_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--use-angle=metal",
-          "--flaky-retries=2"
-        ],
-        "merge": {
-          "script": "//scripts/angle_deqp_test_merge.py"
-        },
-        "name": "angle_deqp_gles3_metal_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "angle_deqp_gles3_tests",
-        "test_id_prefix": "ninja://src/tests:angle_deqp_gles3_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "args": [
-          "--gtest_filter=-*Vulkan_SwiftShader*",
-          "--flaky-retries=2"
-        ],
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "angle_end2end_tests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
-          "shards": 2
-        },
-        "test": "angle_end2end_tests",
-        "test_id_prefix": "ninja://src/tests:angle_end2end_tests/",
-        "use_isolated_scripts_api": true
-      },
-      {
-        "merge": {
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "angle_unittests",
-        "swarming": {
-          "containment_type": "AUTO",
-          "dimensions": {
-            "cpu": "x86-64",
-            "display_attached": "1",
-            "gpu": "8086:3e9b",
-            "os": "Mac-14.4.1"
-          },
-          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
-        },
-        "test": "angle_unittests",
-        "test_id_prefix": "ninja://src/tests:angle_unittests/",
-        "use_isolated_scripts_api": true
-      }
-    ]
-  },
+  "mac-exp-intel": {},
   "mac-exp-nvidia": {},
   "mac-intel": {
     "gtest_tests": [
@@ -5947,7 +6046,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
@@ -5969,7 +6068,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
@@ -5992,7 +6091,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
@@ -6015,7 +6114,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
@@ -6038,7 +6137,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 2
@@ -6062,7 +6161,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 2
@@ -6086,7 +6185,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com",
           "shards": 2
@@ -6106,7 +6205,7 @@
             "cpu": "x86-64",
             "display_attached": "1",
             "gpu": "8086:3e9b",
-            "os": "Mac-13.5|Mac-14.4.1"
+            "os": "Mac-14.4.1"
           },
           "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
         },
diff --git a/infra/specs/mixins.pyl b/infra/specs/mixins.pyl
index 2b6c0c6..5d1b22e 100644
--- a/infra/specs/mixins.pyl
+++ b/infra/specs/mixins.pyl
@@ -15,7 +15,7 @@
 
 { 'android_r': {'swarming': {'dimensions': {'device_os': 'R'}}},
   'android_t': {'swarming': {'dimensions': {'device_os': 'TP1A.220624.021'}}},
-  'android_u': { 'swarming': { 'dimensions': { 'device_os': 'UQ1A.240105.002|UQ1A.240205.002|AP1A.240405.002'}}},
+  'android_u': {'swarming': {'dimensions': {'device_os': 'AP1A.240405.002'}}},
   'angle_skia_gold_test': { 'args': ['--git-revision=${got_angle_revision}'],
                             'precommit_args': [ '--gerrit-issue=${patch_issue}',
                                                 '--gerrit-patchset=${patch_set}',
@@ -31,6 +31,10 @@
                                                           'gpu': '1002:7340-23.2.1',
                                                           'os': 'Ubuntu-22.04',
                                                           'pool': 'chromium.tests.gpu'}}},
+  'linux_intel_uhd_630_experimental': { 'swarming': { 'dimensions': { 'display_attached': '1',
+                                                                      'gpu': '8086:9bc5-23.2.1',
+                                                                      'os': 'Ubuntu-22.04.4',
+                                                                      'pool': 'chromium.tests.gpu'}}},
   'linux_intel_uhd_630_stable': { 'swarming': { 'dimensions': { 'gpu': '8086:9bc5-20.0.8',
                                                                 'os': 'Ubuntu-18.04.6',
                                                                 'pool': 'chromium.tests.gpu'}}},
@@ -44,7 +48,7 @@
   'mac_mini_intel_gpu_stable': { 'swarming': { 'dimensions': { 'cpu': 'x86-64',
                                                                'display_attached': '1',
                                                                'gpu': '8086:3e9b',
-                                                               'os': 'Mac-13.5|Mac-14.4.1'}}},
+                                                               'os': 'Mac-14.4.1'}}},
   'mac_retina_amd_gpu_experimental': { 'swarming': { 'dimensions': { 'cpu': 'x86-64',
                                                                      'display_attached': '1',
                                                                      'gpu': '1002:67ef',
diff --git a/infra/specs/waterfalls.pyl b/infra/specs/waterfalls.pyl
index 717f8f2..da96a99 100644
--- a/infra/specs/waterfalls.pyl
+++ b/infra/specs/waterfalls.pyl
@@ -102,9 +102,11 @@
       'linux-exp-intel': {
         'os_type': 'linux',
         'mixins': [
-          'linux_intel_uhd_630_stable',
+          'linux_intel_uhd_630_experimental',
         ],
         'test_suites': {
+          'gtest_tests': 'linux_intel_gtests',
+          'isolated_scripts': 'isolated_scripts_group_common',
         },
       },
       'linux-exp-swiftshader': {
@@ -247,7 +249,6 @@
           'mac_mini_intel_gpu_experimental',
         ],
         'test_suites': {
-          'gtest_tests': 'mac_amd_and_intel_gtests',
         },
       },
       'mac-exp-nvidia': {
diff --git a/scripts/code_generation_hashes/SPIR-V_helpers.json b/scripts/code_generation_hashes/SPIR-V_helpers.json
index cb1b596..944cf1a 100644
--- a/scripts/code_generation_hashes/SPIR-V_helpers.json
+++ b/scripts/code_generation_hashes/SPIR-V_helpers.json
@@ -1,8 +1,8 @@
 {
   "src/common/spirv/gen_spirv_builder_and_parser.py":
-    "e95670a30a4eda80a146b61c986fb03c",
+    "868a697edbc38c95e36be54cf5c71435",
   "src/common/spirv/spirv_instruction_builder_autogen.cpp":
-    "1b5f60a24d459e7a30c29cf7acfa2106",
+    "c149de371bcd571bd31cc8eb1e517910",
   "src/common/spirv/spirv_instruction_builder_autogen.h":
     "56b1309d8afabb2b64d7e16f0c4a4898",
   "src/common/spirv/spirv_instruction_parser_autogen.cpp":
diff --git a/src/common/MemoryBuffer.cpp b/src/common/MemoryBuffer.cpp
index aadffe8..2a6f572 100644
--- a/src/common/MemoryBuffer.cpp
+++ b/src/common/MemoryBuffer.cpp
@@ -62,6 +62,12 @@
     return true;
 }
 
+void MemoryBuffer::trim(size_t size)
+{
+    ASSERT(size <= mSize);
+    mSize = size;
+}
+
 void MemoryBuffer::fill(uint8_t datum)
 {
     if (!empty())
diff --git a/src/common/MemoryBuffer.h b/src/common/MemoryBuffer.h
index aeb96b9..9b3f976 100644
--- a/src/common/MemoryBuffer.h
+++ b/src/common/MemoryBuffer.h
@@ -27,6 +27,7 @@
     MemoryBuffer &operator=(MemoryBuffer &&other);
 
     [[nodiscard]] bool resize(size_t size);
+    void trim(size_t size);
     void clear() { (void)resize(0); }
     size_t size() const { return mSize; }
     bool empty() const { return mSize == 0; }
diff --git a/src/common/spirv/gen_spirv_builder_and_parser.py b/src/common/spirv/gen_spirv_builder_and_parser.py
index 5e8e9bc..c7e1f40 100755
--- a/src/common/spirv/gen_spirv_builder_and_parser.py
+++ b/src/common/spirv/gen_spirv_builder_and_parser.py
@@ -93,6 +93,15 @@
     ASSERT(length <= 0xFFFFu);
     ASSERT(op <= 0xFFFFu);
 
+    // It's easy for a complex shader to be crafted to hit the length limit,
+    // turn that into a crash instead of a security bug.  Ideally, the compiler
+    // would gracefully fail compilation, so this is more of a safety net.
+    if (ANGLE_UNLIKELY(length > 0xFFFFu))
+    {
+        ERR() << "Complex shader not representible in SPIR-V";
+        ANGLE_CRASH();
+    }
+
     return static_cast<uint32_t>(length) << 16 | op;
 }
 }  // anonymous namespace
diff --git a/src/common/spirv/spirv_instruction_builder_autogen.cpp b/src/common/spirv/spirv_instruction_builder_autogen.cpp
index 3c73c58..6e6ad6f 100644
--- a/src/common/spirv/spirv_instruction_builder_autogen.cpp
+++ b/src/common/spirv/spirv_instruction_builder_autogen.cpp
@@ -25,6 +25,15 @@
     ASSERT(length <= 0xFFFFu);
     ASSERT(op <= 0xFFFFu);
 
+    // It's easy for a complex shader to be crafted to hit the length limit,
+    // turn that into a crash instead of a security bug.  Ideally, the compiler
+    // would gracefully fail compilation, so this is more of a safety net.
+    if (ANGLE_UNLIKELY(length > 0xFFFFu))
+    {
+        ERR() << "Complex shader not representible in SPIR-V";
+        ANGLE_CRASH();
+    }
+
     return static_cast<uint32_t>(length) << 16 | op;
 }
 }  // anonymous namespace
diff --git a/src/common/spirv/spirv_types.h b/src/common/spirv/spirv_types.h
index 2b060d2..c97e4db 100644
--- a/src/common/spirv/spirv_types.h
+++ b/src/common/spirv/spirv_types.h
@@ -128,8 +128,9 @@
 // Returns whether SPIR-V is valid.  Useful for ASSERTs.  Automatically generates a warning if
 // SPIR-V is not valid.
 bool Validate(const Blob &blob);
+#if defined(ANGLE_ENABLE_ASSERTS)
 void Print(const Blob &blob);
-
+#endif
 }  // namespace spirv
 }  // namespace angle
 
diff --git a/src/libANGLE/angletypes.cpp b/src/libANGLE/angletypes.cpp
index d06db48..d8f3e2f 100644
--- a/src/libANGLE/angletypes.cpp
+++ b/src/libANGLE/angletypes.cpp
@@ -1074,6 +1074,7 @@
 {
     uLong uncompressedSize       = static_cast<uLong>(cacheSize);
     uLong expectedCompressedSize = zlib_internal::GzipExpectedCompressedSize(uncompressedSize);
+    uLong actualCompressedSize   = expectedCompressedSize;
 
     // Allocate memory.
     if (!compressedData->resize(expectedCompressedSize))
@@ -1082,7 +1083,7 @@
         return false;
     }
 
-    int zResult = zlib_internal::GzipCompressHelper(compressedData->data(), &expectedCompressedSize,
+    int zResult = zlib_internal::GzipCompressHelper(compressedData->data(), &actualCompressedSize,
                                                     cacheData, uncompressedSize, nullptr, nullptr);
 
     if (zResult != Z_OK)
@@ -1091,11 +1092,9 @@
         return false;
     }
 
-    // Resize it to expected size.
-    if (!compressedData->resize(expectedCompressedSize))
-    {
-        return false;
-    }
+    // Trim to actual size.
+    ASSERT(actualCompressedSize <= expectedCompressedSize);
+    compressedData->trim(actualCompressedSize);
 
     return true;
 }
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.cpp b/src/libANGLE/renderer/vulkan/ContextVk.cpp
index bd27717..44b937d 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.cpp
+++ b/src/libANGLE/renderer/vulkan/ContextVk.cpp
@@ -1165,7 +1165,12 @@
     }
     if (mRenderer->useDepthTestEnableDynamicState())
     {
-        mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED);
+        // Depth test affects depth write state too in GraphicsPipelineDesc, so the pipeline needs
+        // to stay dirty if depth test changes while depth write state is static.
+        if (mRenderer->useDepthWriteEnableDynamicState())
+        {
+            mPipelineDirtyBitsMask.reset(gl::state::DIRTY_BIT_DEPTH_TEST_ENABLED);
+        }
     }
     if (mRenderer->useDepthWriteEnableDynamicState())
     {
@@ -6619,6 +6624,8 @@
     ANGLE_TRY(setupDispatch(context));
 
     mOutsideRenderPassCommands->getCommandBuffer().dispatch(numGroupsX, numGroupsY, numGroupsZ);
+    // Track completion of compute.
+    mOutsideRenderPassCommands->flushSetEvents(this);
 
     return angle::Result::Continue;
 }
@@ -6646,6 +6653,9 @@
     mOutsideRenderPassCommands->getCommandBuffer().dispatchIndirect(buffer.getBuffer(),
                                                                     buffer.getOffset() + indirect);
 
+    // Track completion of compute.
+    mOutsideRenderPassCommands->flushSetEvents(this);
+
     return angle::Result::Continue;
 }
 
diff --git a/src/libANGLE/renderer/vulkan/ContextVk.h b/src/libANGLE/renderer/vulkan/ContextVk.h
index b11ffb4..ed473f7 100644
--- a/src/libANGLE/renderer/vulkan/ContextVk.h
+++ b/src/libANGLE/renderer/vulkan/ContextVk.h
@@ -588,6 +588,28 @@
         return angle::Result::Continue;
     }
 
+    void trackImageWithOutsideRenderPassEvent(vk::ImageHelper *image)
+    {
+        if (mRenderer->getFeatures().useVkEventForImageBarrier.enabled)
+        {
+            mOutsideRenderPassCommands->trackImageWithEvent(this, image);
+        }
+    }
+    void trackImagesWithOutsideRenderPassEvent(vk::ImageHelper *srcImage, vk::ImageHelper *dstImage)
+    {
+        if (mRenderer->getFeatures().useVkEventForImageBarrier.enabled)
+        {
+            mOutsideRenderPassCommands->trackImagesWithEvent(this, srcImage, dstImage);
+        }
+    }
+    void trackImagesWithOutsideRenderPassEvent(const vk::ImageHelperPtr *images, size_t count)
+    {
+        if (mRenderer->getFeatures().useVkEventForImageBarrier.enabled)
+        {
+            mOutsideRenderPassCommands->trackImagesWithEvent(this, images, count);
+        }
+    }
+
     angle::Result submitStagedTextureUpdates()
     {
         // Staged updates are recorded in outside RP cammand buffer, submit them.
diff --git a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
index 8c77f51..07554f8 100644
--- a/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
+++ b/src/libANGLE/renderer/vulkan/FramebufferVk.cpp
@@ -1386,13 +1386,20 @@
 
         if (canBlitWithCommand && areChannelsBlitCompatible && !reinterpretsColorspace)
         {
+            // Stash all images that involved with blit so that we can track them all at once.
+            angle::FixedVector<vk::ImageHelper *, 1 + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
+                accessedImages;
+            accessedImages.push_back(&readRenderTarget->getImageForCopy());
             for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
             {
                 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
                 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
                                           drawRenderTarget, filter, true, false, false, flipX,
                                           flipY));
+                accessedImages.push_back(&drawRenderTarget->getImageForWrite());
             }
+            contextVk->trackImagesWithOutsideRenderPassEvent(accessedImages.data(),
+                                                             accessedImages.size());
         }
         // If we're not flipping or rotating, use Vulkan's builtin resolve.
         else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible &&
@@ -1500,6 +1507,8 @@
             ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
                                       drawRenderTarget, filter, false, blitDepthBuffer,
                                       blitStencilBuffer, flipX, flipY));
+            contextVk->trackImagesWithOutsideRenderPassEvent(&readRenderTarget->getImageForCopy(),
+                                                             &drawRenderTarget->getImageForWrite());
         }
         else
         {
@@ -1843,6 +1852,9 @@
     dataUpload->copyBufferToImage(buffer->getBuffer().getHandle(),
                                   mFragmentShadingRateImage.getImage(),
                                   VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy);
+
+    contextVk->trackImageWithOutsideRenderPassEvent(&mFragmentShadingRateImage);
+
     return angle::Result::Continue;
 }
 
@@ -1997,6 +2009,8 @@
     resolveRegion.extent.depth                  = 1;
 
     angle::VulkanPerfCounters &perfCounters = contextVk->getPerfCounters();
+    angle::FixedVector<vk::ImageHelperPtr, 1 + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> accessedImages;
+    accessedImages.push_back(srcImage);
     for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
     {
         RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
@@ -2009,7 +2023,9 @@
         srcImage->resolve(&dstImage, resolveRegion, commandBuffer);
 
         perfCounters.resolveImageCommands++;
+        accessedImages.push_back(&dstImage);
     }
+    contextVk->trackImagesWithOutsideRenderPassEvent(accessedImages.data(), accessedImages.size());
 
     return angle::Result::Continue;
 }
diff --git a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
index 7bac2b9..326b8c7 100644
--- a/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
+++ b/src/libANGLE/renderer/vulkan/SurfaceVk.cpp
@@ -2212,6 +2212,8 @@
 
         mColorImageMS.resolve(image.image.get(), resolveRegion,
                               &commandBufferHelper->getCommandBuffer());
+
+        contextVk->trackImagesWithOutsideRenderPassEvent(&mColorImageMS, image.image.get());
         contextVk->getPerfCounters().swapchainResolveOutsideSubpass++;
     }
 
diff --git a/src/libANGLE/renderer/vulkan/TextureVk.cpp b/src/libANGLE/renderer/vulkan/TextureVk.cpp
index baa66a1..f49b975 100644
--- a/src/libANGLE/renderer/vulkan/TextureVk.cpp
+++ b/src/libANGLE/renderer/vulkan/TextureVk.cpp
@@ -1449,6 +1449,8 @@
 
         vk::ImageHelper::Copy(contextVk, srcImage, mImage, srcOffset, dstOffsetModified, extents,
                               srcSubresource, destSubresource, commandBuffer);
+
+        contextVk->trackImagesWithOutsideRenderPassEvent(srcImage, mImage);
     }
     else
     {
@@ -1483,6 +1485,8 @@
         vk::ImageHelper::Copy(contextVk, srcImage, &stagingImage->get(), srcOffset, gl::kOffsetZero,
                               extents, srcSubresource, destSubresource, commandBuffer);
 
+        contextVk->trackImagesWithOutsideRenderPassEvent(srcImage, &stagingImage->get());
+
         // Stage the copy for when the image storage is actually created.
         VkImageType imageType = gl_vk::GetImageType(mState.getType());
         const gl::ImageIndex stagingIndex =
@@ -2209,6 +2213,8 @@
     commandBuffer->copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(),
                                      mImage->getCurrentLayout(contextVk), 1, &region);
 
+    contextVk->trackImageWithOutsideRenderPassEvent(mImage);
+
     return angle::Result::Continue;
 }
 
@@ -2318,6 +2324,8 @@
         }
     }
 
+    contextVk->trackImageWithOutsideRenderPassEvent(mImage);
+
     return angle::Result::Continue;
 }
 
@@ -2519,6 +2527,8 @@
                                  stagingImage->get().getCurrentLayout(contextVk), 1, &copyRegion);
     }
 
+    contextVk->trackImagesWithOutsideRenderPassEvent(srcImage, &stagingImage->get());
+
     // Stage the staging image in the destination
     dstImage->stageSubresourceUpdatesFromAllImageLevels(stagingImage.release(),
                                                         previousFirstAllocateLevel);
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
index 46c2592..e1d1b3c 100644
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.cpp
@@ -4274,10 +4274,8 @@
 
 // DescriptorSetLayoutDesc implementation.
 DescriptorSetLayoutDesc::DescriptorSetLayoutDesc()
-    : mPackedDescriptorSetLayout{}, mValidDescriptorSetLayoutIndexMask()
-{
-    mImmutableSamplers.fill(VK_NULL_HANDLE);
-}
+    : mDescriptorSetLayoutBindings{}, mImmutableSamplers{}
+{}
 
 DescriptorSetLayoutDesc::~DescriptorSetLayoutDesc() = default;
 
@@ -4288,20 +4286,32 @@
 
 size_t DescriptorSetLayoutDesc::hash() const
 {
-    size_t genericHash = angle::ComputeGenericHash(mValidDescriptorSetLayoutIndexMask);
-    for (size_t bindingIndex : mValidDescriptorSetLayoutIndexMask)
+    size_t validDescriptorSetLayoutBindingsCount = mDescriptorSetLayoutBindings.size();
+    size_t validImmutableSamplersCount           = mImmutableSamplers.size();
+
+    ASSERT(validDescriptorSetLayoutBindingsCount != 0 || validImmutableSamplersCount == 0);
+
+    size_t genericHash = 0;
+    if (validDescriptorSetLayoutBindingsCount > 0)
     {
-        genericHash ^= angle::ComputeGenericHash(mPackedDescriptorSetLayout[bindingIndex]) ^
-                       angle::ComputeGenericHash(mImmutableSamplers[bindingIndex]);
+        genericHash = angle::ComputeGenericHash(
+            mDescriptorSetLayoutBindings.data(),
+            validDescriptorSetLayoutBindingsCount * sizeof(PackedDescriptorSetBinding));
     }
+
+    if (validImmutableSamplersCount > 0)
+    {
+        genericHash ^= angle::ComputeGenericHash(mImmutableSamplers.data(),
+                                                 validImmutableSamplersCount * sizeof(VkSampler));
+    }
+
     return genericHash;
 }
 
 bool DescriptorSetLayoutDesc::operator==(const DescriptorSetLayoutDesc &other) const
 {
-    return memcmp(&mPackedDescriptorSetLayout, &other.mPackedDescriptorSetLayout,
-                  sizeof(mPackedDescriptorSetLayout)) == 0 &&
-           memcmp(&mImmutableSamplers, &other.mImmutableSamplers, sizeof(mImmutableSamplers)) == 0;
+    return mDescriptorSetLayoutBindings == other.mDescriptorSetLayoutBindings &&
+           mImmutableSamplers == other.mImmutableSamplers;
 }
 
 void DescriptorSetLayoutDesc::update(uint32_t bindingIndex,
@@ -4310,43 +4320,46 @@
                                      VkShaderStageFlags stages,
                                      const Sampler *immutableSampler)
 {
-    ASSERT(static_cast<size_t>(descriptorType) < std::numeric_limits<uint16_t>::max());
+    ASSERT(static_cast<size_t>(descriptorType) < std::numeric_limits<uint8_t>::max());
     ASSERT(count < std::numeric_limits<uint16_t>::max());
+    ASSERT(bindingIndex < std::numeric_limits<uint16_t>::max());
 
-    PackedDescriptorSetBinding &packedBinding = mPackedDescriptorSetLayout[bindingIndex];
-
+    PackedDescriptorSetBinding packedBinding = {};
     SetBitField(packedBinding.type, descriptorType);
     SetBitField(packedBinding.count, count);
     SetBitField(packedBinding.stages, stages);
+    SetBitField(packedBinding.bindingIndex, bindingIndex);
+    SetBitField(packedBinding.hasImmutableSampler, 0);
 
     if (immutableSampler)
     {
         ASSERT(count == 1);
-        ASSERT(bindingIndex < gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
-
-        mImmutableSamplers[bindingIndex] = immutableSampler->getHandle();
+        SetBitField(packedBinding.hasImmutableSampler, 1);
+        mImmutableSamplers.push_back(immutableSampler->getHandle());
     }
 
-    mValidDescriptorSetLayoutIndexMask.set(bindingIndex, count > 0);
+    mDescriptorSetLayoutBindings.push_back(std::move(packedBinding));
 }
 
 void DescriptorSetLayoutDesc::unpackBindings(DescriptorSetLayoutBindingVector *bindings) const
 {
-    for (size_t bindingIndex : mValidDescriptorSetLayoutIndexMask)
+    size_t immutableSamplersIndex = 0;
+
+    // Unpack all valid descriptor set layout bindings
+    for (const PackedDescriptorSetBinding &packedBinding : mDescriptorSetLayoutBindings)
     {
-        const PackedDescriptorSetBinding &packedBinding = mPackedDescriptorSetLayout[bindingIndex];
         ASSERT(packedBinding.count != 0);
 
         VkDescriptorSetLayoutBinding binding = {};
-        binding.binding                      = static_cast<uint32_t>(bindingIndex);
+        binding.binding                      = static_cast<uint32_t>(packedBinding.bindingIndex);
         binding.descriptorCount              = packedBinding.count;
         binding.descriptorType               = static_cast<VkDescriptorType>(packedBinding.type);
         binding.stageFlags = static_cast<VkShaderStageFlags>(packedBinding.stages);
-        if (mImmutableSamplers[bindingIndex] != VK_NULL_HANDLE)
+
+        if (packedBinding.hasImmutableSampler)
         {
             ASSERT(packedBinding.count == 1);
-            ASSERT(bindingIndex < gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES);
-            binding.pImmutableSamplers = &mImmutableSamplers[bindingIndex];
+            binding.pImmutableSamplers = &mImmutableSamplers[immutableSamplersIndex++];
         }
 
         bindings->push_back(binding);
@@ -4371,12 +4384,18 @@
 
 size_t PipelineLayoutDesc::hash() const
 {
-    return angle::ComputeGenericHash(*this);
+    size_t genericHash = angle::ComputeGenericHash(mPushConstantRange);
+    for (const DescriptorSetLayoutDesc &descriptorSetLayoutDesc : mDescriptorSetLayouts)
+    {
+        genericHash ^= descriptorSetLayoutDesc.hash();
+    }
+    return genericHash;
 }
 
 bool PipelineLayoutDesc::operator==(const PipelineLayoutDesc &other) const
 {
-    return memcmp(this, &other, sizeof(PipelineLayoutDesc)) == 0;
+    return mPushConstantRange == other.mPushConstantRange &&
+           mDescriptorSetLayouts == other.mDescriptorSetLayouts;
 }
 
 void PipelineLayoutDesc::updateDescriptorSetLayout(DescriptorSetIndex setIndex,
diff --git a/src/libANGLE/renderer/vulkan/vk_cache_utils.h b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
index 4db163d..b04b604 100644
--- a/src/libANGLE/renderer/vulkan/vk_cache_utils.h
+++ b/src/libANGLE/renderer/vulkan/vk_cache_utils.h
@@ -984,17 +984,11 @@
 constexpr size_t kGraphicsPipelineDescSize = sizeof(GraphicsPipelineDesc);
 static_assert(kGraphicsPipelineDescSize == kGraphicsPipelineDescSumOfSizes, "Size mismatch");
 
-constexpr uint32_t kMaxDescriptorSetLayoutBindings =
-    std::max(gl::IMPLEMENTATION_MAX_ACTIVE_TEXTURES,
-             gl::IMPLEMENTATION_MAX_UNIFORM_BUFFER_BINDINGS);
-
+// Values are based on data recorded here -> https://anglebug.com/8677#c4
+constexpr size_t kDefaultDescriptorSetLayoutBindingsCount = 8;
+constexpr size_t kDefaultImmutableSamplerBindingsCount    = 1;
 using DescriptorSetLayoutBindingVector =
-    angle::FixedVector<VkDescriptorSetLayoutBinding, kMaxDescriptorSetLayoutBindings>;
-
-// Technically this needs to only be kMaxDescriptorSetLayoutBindings but due to struct padding
-// issues round up size to 64.
-constexpr uint32_t kMaxDescriptorSetLayoutCount = roundUpPow2(kMaxDescriptorSetLayoutBindings, 64u);
-using DescriptorSetLayoutIndexMask              = angle::BitSet<kMaxDescriptorSetLayoutCount>;
+    angle::FastVector<VkDescriptorSetLayoutBinding, kDefaultDescriptorSetLayoutBindingsCount>;
 
 // A packed description of a descriptor set layout. Use similarly to RenderPassDesc and
 // GraphicsPipelineDesc. Currently we only need to differentiate layouts based on sampler and ubo
@@ -1018,39 +1012,53 @@
 
     void unpackBindings(DescriptorSetLayoutBindingVector *bindings) const;
 
-    bool empty() const { return !mValidDescriptorSetLayoutIndexMask.any(); }
+    bool empty() const { return mDescriptorSetLayoutBindings.empty(); }
 
   private:
     // There is a small risk of an issue if the sampler cache is evicted but not the descriptor
     // cache we would have an invalid handle here. Thus propose follow-up work:
     // TODO: https://issuetracker.google.com/issues/159156775: Have immutable sampler use serial
-    struct PackedDescriptorSetBinding
+    union PackedDescriptorSetBinding
     {
-        uint8_t type;    // Stores a packed VkDescriptorType descriptorType.
-        uint8_t stages;  // Stores a packed VkShaderStageFlags.
-        uint16_t count;  // Stores a packed uint32_t descriptorCount.
+        struct
+        {
+            uint8_t type;                  // Stores a packed VkDescriptorType descriptorType.
+            uint8_t stages;                // Stores a packed VkShaderStageFlags.
+            uint16_t count;                // Stores a packed uint32_t descriptorCount
+            uint16_t bindingIndex;         // Stores the binding index
+            uint16_t hasImmutableSampler;  // Whether this binding has an immutable sampler
+        };
+        uint64_t value;
+
+        bool operator==(const PackedDescriptorSetBinding &other) const
+        {
+            return value == other.value;
+        }
     };
 
-    // 1x 32bit
-    static_assert(sizeof(PackedDescriptorSetBinding) == 4, "Unexpected size");
+    // 1x 64bit
+    static_assert(sizeof(PackedDescriptorSetBinding) == 8, "Unexpected size");
 
-    // This is a compact representation of a descriptor set layout.
-    std::array<PackedDescriptorSetBinding, kMaxDescriptorSetLayoutBindings>
-        mPackedDescriptorSetLayout;
-    gl::ActiveTextureArray<VkSampler> mImmutableSamplers;
-
-    DescriptorSetLayoutIndexMask mValidDescriptorSetLayoutIndexMask;
+    angle::FastVector<PackedDescriptorSetBinding, kDefaultDescriptorSetLayoutBindingsCount>
+        mDescriptorSetLayoutBindings;
+    angle::FastVector<VkSampler, kDefaultImmutableSamplerBindingsCount> mImmutableSamplers;
 };
 
 // The following are for caching descriptor set layouts. Limited to max three descriptor set
 // layouts. This can be extended in the future.
-constexpr size_t kMaxDescriptorSetLayouts = 3;
+constexpr size_t kMaxDescriptorSetLayouts = ToUnderlying(DescriptorSetIndex::EnumCount);
 
-struct PackedPushConstantRange
+union PackedPushConstantRange
 {
-    uint8_t offset;
-    uint8_t size;
-    uint16_t stageMask;
+    struct
+    {
+        uint8_t offset;
+        uint8_t size;
+        uint16_t stageMask;
+    };
+    uint32_t value;
+
+    bool operator==(const PackedPushConstantRange &other) const { return value == other.value; }
 };
 
 static_assert(sizeof(PackedPushConstantRange) == sizeof(uint32_t), "Unexpected Size");
@@ -2559,6 +2567,10 @@
         const vk::DescriptorSetLayoutDesc &desc,
         vk::AtomicBindingPointer<vk::DescriptorSetLayout> *descriptorSetLayoutOut);
 
+    // Helpers for white box tests
+    size_t getCacheHitCount() const { return mCacheStats.getHitCount(); }
+    size_t getCacheMissCount() const { return mCacheStats.getMissCount(); }
+
   private:
     mutable std::mutex mMutex;
     std::unordered_map<vk::DescriptorSetLayoutDesc, vk::RefCountedDescriptorSetLayout> mPayload;
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.cpp b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
index 1ad847e..109bb09 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.cpp
@@ -1507,10 +1507,18 @@
     mCommandAllocator.init();
 }
 
-void CommandBufferHelperCommon::resetImpl()
+void CommandBufferHelperCommon::resetImpl(Context *context)
 {
     ASSERT(!mAcquireNextImageSemaphore.valid());
     mCommandAllocator.resetAllocator();
+
+    // Clean up event garbage. Note that ImageHelper object may still holding reference count to it,
+    // so the event itself will not gets destroyed until the last refCount goes away.
+    if (!mRefCountedEventGarbage.empty())
+    {
+        context->getRenderer()->collectRefCountedEventGarbage(mQueueSerial,
+                                                              std::move(mRefCountedEventGarbage));
+    }
 }
 
 template <class DerivedT>
@@ -1693,6 +1701,46 @@
     }
 }
 
+void CommandBufferHelperCommon::retainImage(Context *context, ImageHelper *image)
+{
+    image->setQueueSerial(mQueueSerial);
+
+    if (context->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled)
+    {
+        image->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    }
+}
+
+template <typename CommandBufferT>
+void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
+{
+    if (mRefCountedEvents.mask.none())
+    {
+        return;
+    }
+
+    // Add VkCmdSetEvent here to track the completion of this renderPass.
+    for (ImageLayout layout : mRefCountedEvents.mask)
+    {
+        RefCountedEvent &refCountedEvent = mRefCountedEvents.map[layout];
+        ASSERT(refCountedEvent.valid());
+        const ImageMemoryBarrierData &layoutData =
+            kImageMemoryBarrierData[refCountedEvent.getImageLayout()];
+        commandBuffer->setEvent(refCountedEvent.getEvent().getHandle(),
+                                GetImageLayoutDstStageMask(context, layoutData));
+        // We no longer need event, so garbage collect it.
+        mRefCountedEventGarbage.add(&refCountedEvent);
+    }
+    mRefCountedEvents.mask.reset();
+}
+
+template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
+    Context *context,
+    priv::SecondaryCommandBuffer *commandBuffer);
+template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
+    Context *context,
+    VulkanSecondaryCommandBuffer *commandBuffer);
+
 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
 {
     mPipelineBarriers.addDiagnosticsString(*out);
@@ -1723,7 +1771,7 @@
     Context *context,
     SecondaryCommandBufferCollector *commandBufferCollector)
 {
-    resetImpl();
+    resetImpl(context);
 
     // Collect/Reset the command buffer
     commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
@@ -1760,13 +1808,17 @@
 {
     imageReadImpl(contextVk, aspectFlags, imageLayout, image);
 
-    if (!contextVk->isRenderPassStartedAndUsesImage(*image))
+    if (contextVk->isRenderPassStartedAndUsesImage(*image))
     {
         // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
         // because the layout will be different, except with image sampled from compute shader. In
         // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
-        // read, since its queueSerial must be greater than outsideRP.
-        image->setQueueSerial(mQueueSerial);
+        // read, since its queueSerial must be greater than outsideRP. So dont update queueSerial
+        // here.
+    }
+    else
+    {
+        retainImage(contextVk, image);
     }
 }
 
@@ -1779,7 +1831,33 @@
                                                       ImageHelper *image)
 {
     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout, image);
-    image->setQueueSerial(mQueueSerial);
+    retainImage(contextVk, image);
+}
+
+void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
+{
+    image->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    flushSetEventsImpl(context, &mCommandBuffer);
+}
+
+void OutsideRenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
+                                                                ImageHelper *srcImage,
+                                                                ImageHelper *dstImage)
+{
+    srcImage->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    dstImage->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    flushSetEventsImpl(context, &mCommandBuffer);
+}
+
+void OutsideRenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
+                                                                const ImageHelperPtr *images,
+                                                                size_t count)
+{
+    for (size_t i = 0; i < count; i++)
+    {
+        images[i]->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    }
+    flushSetEventsImpl(context, &mCommandBuffer);
 }
 
 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
@@ -1805,6 +1883,9 @@
     ASSERT(mIsCommandBufferEnded);
     mCommandBuffer.executeCommands(&commandsState->primaryCommands);
 
+    // Call VkCmdSetEvent to track the completion of this renderPass.
+    flushSetEventsImpl(context, &commandsState->primaryCommands);
+
     // Restart the command buffer.
     return reset(context, &commandsState->secondaryCommands);
 }
@@ -1986,7 +2067,7 @@
     Context *context,
     SecondaryCommandBufferCollector *commandBufferCollector)
 {
-    resetImpl();
+    resetImpl(context);
 
     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
          ++index)
@@ -2039,7 +2120,7 @@
     imageReadImpl(contextVk, aspectFlags, imageLayout, image);
     // As noted in the header we don't support multiple read layouts for Images.
     // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
-    image->setQueueSerial(mQueueSerial);
+    retainImage(contextVk, image);
 }
 
 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
@@ -2051,7 +2132,7 @@
                                                ImageHelper *image)
 {
     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout, image);
-    image->setQueueSerial(mQueueSerial);
+    retainImage(contextVk, image);
 }
 
 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
@@ -2571,6 +2652,16 @@
     mDepthAttachment.getImage()->resetRenderPassUsageFlags();
 }
 
+void RenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
+                                                         const ImageHelperPtr *images,
+                                                         size_t count)
+{
+    for (size_t i = 0; i < count; i++)
+    {
+        images[i]->setCurrentRefCountedEvent(context, mRefCountedEvents);
+    }
+}
+
 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
     ContextVk *contextVk,
     RenderPassFramebuffer &&framebuffer,
@@ -2615,40 +2706,55 @@
 {
     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
 
+    // *2 for resolve attachments
+    angle::FixedVector<ImageHelperPtr, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS << 1>
+        accessedImages;
     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
          ++index)
     {
         if (mColorAttachments[index].getImage() != nullptr)
         {
             finalizeColorImageLayoutAndLoadStore(contextVk, index);
+            accessedImages.push_back(mColorAttachments[index].getImage());
         }
         if (mColorResolveAttachments[index].getImage() != nullptr)
         {
             finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
                                      true);
+            accessedImages.push_back(mColorResolveAttachments[index].getImage());
         }
     }
 
     if (mFragmentShadingRateAtachment.getImage() != nullptr)
     {
         finalizeFragmentShadingRateImageLayout(contextVk);
+        accessedImages.push_back(mFragmentShadingRateAtachment.getImage());
     }
 
-    if (mDepthStencilAttachmentIndex == kAttachmentIndexInvalid)
+    if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
     {
-        return angle::Result::Continue;
+        // Do depth stencil layout change and load store optimization.
+        ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
+        ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
+        if (mDepthAttachment.getImage() != nullptr)
+        {
+            finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
+            accessedImages.push_back(mDepthAttachment.getImage());
+        }
+        if (mDepthResolveAttachment.getImage() != nullptr)
+        {
+            finalizeDepthStencilResolveImageLayout(contextVk);
+            accessedImages.push_back(mDepthResolveAttachment.getImage());
+        }
     }
 
-    // Do depth stencil layout change and load store optimization.
-    ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
-    ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
-    if (mDepthAttachment.getImage() != nullptr)
+    if (contextVk->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled)
     {
-        finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
-    }
-    if (mDepthResolveAttachment.getImage() != nullptr)
-    {
-        finalizeDepthStencilResolveImageLayout(contextVk);
+        // Even if there is no layout change, we always have to update event. In case of feedback
+        // loop, the sampler code should already set the event, which means we will be set it twice
+        // here. But since they uses the same layout and event is refCounted, it should work just
+        // fine.
+        trackImagesWithEvent(contextVk, accessedImages.data(), accessedImages.size());
     }
 
     return angle::Result::Continue;
@@ -2819,6 +2925,9 @@
     }
     primary.endRenderPass();
 
+    // Call VkCmdSetEvent to track the completion of this renderPass.
+    flushSetEventsImpl(context, &primary);
+
     // Restart the command buffer.
     return reset(context, &commandsState->secondaryCommands);
 }
@@ -6002,6 +6111,7 @@
         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
                                   mVmaAllocation.getHandle());
     }
+    mCurrentEvent.release(renderer->getDevice());
 
     renderer->collectGarbage(mUse, &mImage, &mDeviceMemory, &mVmaAllocation);
     mViewFormats.clear();
@@ -6477,6 +6587,7 @@
                                   mVmaAllocation.getHandle());
     }
 
+    mCurrentEvent.release(device);
     mImage.destroy(device);
     mDeviceMemory.destroy(device);
     mVmaAllocation.destroy(renderer->getAllocator());
@@ -7213,6 +7324,26 @@
     *semaphoreOut = mAcquireNextImageSemaphore.release();
 }
 
+void ImageHelper::setCurrentRefCountedEvent(Context *context, ImageLayoutEventMaps &layoutEventMaps)
+{
+    ASSERT(context->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled);
+
+    // Create the event if we have not yet so. Otherwise just use the already created event. This
+    // means all images used in the same render pass that has the same layout will be tracked by the
+    // same event.
+    if (!layoutEventMaps.map[mCurrentLayout].valid())
+    {
+        layoutEventMaps.map[mCurrentLayout].init(context, mCurrentLayout);
+        layoutEventMaps.mask.set(mCurrentLayout);
+    }
+
+    // If there is already an event, release it first.
+    mCurrentEvent.release(context->getDevice());
+    // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
+    // refcount to the underlying VkEvent.
+    mCurrentEvent = layoutEventMaps.map[mCurrentLayout];
+}
+
 void ImageHelper::clearColor(Context *context,
                              const VkClearColorValue &color,
                              LevelIndex baseMipLevelVk,
@@ -7476,6 +7607,8 @@
         ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
     }
 
+    contextVk->trackImagesWithOutsideRenderPassEvent(srcImage, dstImage);
+
     return angle::Result::Continue;
 }
 
@@ -7587,6 +7720,8 @@
     mCurrentShaderReadStageMask  = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
     mCurrentLayout               = ImageLayout::FragmentShaderReadOnly;
 
+    contextVk->trackImageWithOutsideRenderPassEvent(this);
+
     return angle::Result::Continue;
 }
 
@@ -9364,6 +9499,12 @@
         *levelUpdates = std::move(updatesToKeep);
     }
 
+    if (commandBuffer != nullptr)
+    {
+        // Track completion of this copy operation.
+        contextVk->trackImageWithOutsideRenderPassEvent(this);
+    }
+
     return angle::Result::Continue;
 }
 
@@ -9828,6 +9969,8 @@
 
     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(contextVk), bufferHandle, regionCount,
                                      &regions);
+    // Track completion of this copy.
+    contextVk->trackImageWithOutsideRenderPassEvent(this);
 
     return angle::Result::Continue;
 }
@@ -10446,12 +10589,15 @@
 
             copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(contextVk),
                                                  packBuffer.getBuffer().getHandle(), 1, &region);
+            contextVk->trackImageWithOutsideRenderPassEvent(this);
             return angle::Result::Continue;
         }
         if (canCopyWithComputeForReadPixels(packPixelsParams, readFormat, pixelsOffset))
         {
-            return readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
-                                         pixelsOffset, srcSubresource);
+            ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
+                                            pixelsOffset, srcSubresource));
+            contextVk->trackImageWithOutsideRenderPassEvent(this);
+            return angle::Result::Continue;
         }
     }
 
diff --git a/src/libANGLE/renderer/vulkan/vk_helpers.h b/src/libANGLE/renderer/vulkan/vk_helpers.h
index 1d0a79b..f93c40a 100644
--- a/src/libANGLE/renderer/vulkan/vk_helpers.h
+++ b/src/libANGLE/renderer/vulkan/vk_helpers.h
@@ -14,6 +14,7 @@
 #include "libANGLE/renderer/vulkan/Suballocation.h"
 #include "libANGLE/renderer/vulkan/vk_cache_utils.h"
 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
+#include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
 
 #include <functional>
 
@@ -167,6 +168,14 @@
 
 VkImageLayout ConvertImageLayoutToVkImageLayout(Context *context, ImageLayout imageLayout);
 
+struct ImageLayoutEventMaps
+{
+    // The list of RefCountedEvents that have been tracked. The mask is used to accelerate the
+    // loop of map
+    angle::PackedEnumMap<ImageLayout, RefCountedEvent> map;
+    angle::PackedEnumBitSet<ImageLayout, uint64_t> mask;
+};
+
 // A dynamic buffer is conceptually an infinitely long buffer. Each time you write to the buffer,
 // you will always write to a previously unused portion. After a series of writes, you must flush
 // the buffer data to the device. Buffer lifetime currently assumes that each new allocation will
@@ -1123,6 +1132,7 @@
 };
 
 class ImageHelper;
+using ImageHelperPtr = ImageHelper *;
 
 // Reference to a render pass attachment (color or depth/stencil) alongside render-pass-related
 // tracking such as when the attachment is last written to or invalidated.  This is used to
@@ -1322,6 +1332,14 @@
         writeResource->setWriteQueueSerial(mQueueSerial);
     }
 
+    // Update image with this command buffer's queueSerial. If VkEvent is enabled, image's current
+    // event is also updated with this command's event.
+    void retainImage(Context *context, ImageHelper *image);
+
+    // Issue VkCmdSetEvent call for events in this command buffer.
+    template <typename CommandBufferT>
+    void flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer);
+
     const QueueSerial &getQueueSerial() const { return mQueueSerial; }
 
     void setAcquireNextImageSemaphore(VkSemaphore semaphore)
@@ -1340,7 +1358,7 @@
 
     void initializeImpl();
 
-    void resetImpl();
+    void resetImpl(Context *context);
 
     template <class DerivedT>
     angle::Result attachCommandPoolImpl(Context *context, SecondaryCommandPool *commandPool);
@@ -1413,6 +1431,11 @@
 
     // Only used for swapChain images
     Semaphore mAcquireNextImageSemaphore;
+
+    // The list of RefCountedEvents that have be tracked
+    ImageLayoutEventMaps mRefCountedEvents;
+    // The list of RefCountedEvents that should be garbage collected when it gets reset.
+    RefCountedEventGarbageObjects mRefCountedEventGarbage;
 };
 
 class SecondaryCommandBufferCollector;
@@ -1480,6 +1503,14 @@
                     ImageLayout imageLayout,
                     ImageHelper *image);
 
+    // Call SetEvent and have image's current event pointing to it.
+    void trackImageWithEvent(Context *context, ImageHelper *image);
+    void trackImagesWithEvent(Context *context, ImageHelper *srcImage, ImageHelper *dstImage);
+    void trackImagesWithEvent(Context *context, const ImageHelperPtr *images, size_t count);
+
+    // Issues VkCmdSetEvent calls.
+    void flushSetEvents(Context *context) { flushSetEventsImpl(context, &mCommandBuffer); }
+
     angle::Result flushToPrimary(Context *context, CommandsState *commandsState);
 
     void setGLMemoryBarrierIssued()
@@ -1864,6 +1895,8 @@
     void finalizeDepthStencilImageLayoutAndLoadStore(Context *context);
     void finalizeFragmentShadingRateImageLayout(Context *context);
 
+    void trackImagesWithEvent(Context *context, const ImageHelperPtr *images, size_t count);
+
     // When using Vulkan secondary command buffers, each subpass must be recorded in a separate
     // command buffer.  Currently ANGLE produces render passes with at most 2 subpasses.
     static constexpr size_t kMaxSubpassCount = 2;
@@ -2684,6 +2717,9 @@
 
     size_t getLevelUpdateCount(gl::LevelIndex level) const;
 
+    // Create event if needed and record the event in ImageHelper::mCurrentEvent.
+    void setCurrentRefCountedEvent(Context *context, ImageLayoutEventMaps &layoutEventMaps);
+
   private:
     ANGLE_ENABLE_STRUCT_PADDING_WARNINGS
     struct ClearUpdate
@@ -3028,6 +3064,10 @@
     // The QueueSerial that associated with the last barrier.
     QueueSerial mBarrierQueueSerial;
 
+    // The current refCounted event. When barrier or layout change is needed, we should wait for
+    // this event.
+    RefCountedEvent mCurrentEvent;
+
     // Whether ANGLE currently has ownership of this resource or it's released to external.
     bool mIsReleasedToExternal;
 
diff --git a/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
new file mode 100644
index 0000000..22b5a81
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.cpp
@@ -0,0 +1,58 @@
+//
+// Copyright 2024 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.
+//
+// RefCountedEvent:
+//    Manages reference count of VkEvent and its associated functions.
+//
+
+#include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
+#include "libANGLE/renderer/vulkan/vk_helpers.h"
+#include "libANGLE/renderer/vulkan/vk_renderer.h"
+
+namespace rx
+{
+namespace vk
+{
+
+void ReleaseRefcountedEvent(VkDevice device, RefCountedEventAndLayoutHandle atomicRefCountedEvent)
+{
+    const bool isLastReference = atomicRefCountedEvent->getAndReleaseRef() == 1;
+    if (isLastReference)
+    {
+        atomicRefCountedEvent->get().event.destroy(device);
+        SafeDelete(atomicRefCountedEvent);
+    }
+}
+
+void RefCountedEvent::init(Context *context, ImageLayout layout)
+{
+    ASSERT(mHandle == nullptr);
+    ASSERT(layout != ImageLayout::Undefined);
+
+    mHandle                      = new AtomicRefCounted<EventAndLayout>;
+    VkEventCreateInfo createInfo = {};
+    createInfo.sType             = VK_STRUCTURE_TYPE_EVENT_CREATE_INFO;
+    createInfo.flags             = 0;
+    mHandle->get().event.init(context->getDevice(), createInfo);
+    mHandle->addRef();
+    mHandle->get().imageLayout = layout;
+}
+
+// RefCountedEventGarbageObjects implementation
+void RefCountedEventGarbageObjects::add(RefCountedEvent *event)
+{
+    mGarbageObjects.emplace_back(GetGarbage(event));
+}
+
+void RefCountedEventGarbageObjects::add(std::vector<RefCountedEvent> *events)
+{
+    while (!events->empty())
+    {
+        mGarbageObjects.emplace_back(GetGarbage(&events->back()));
+        events->pop_back();
+    }
+}
+}  // namespace vk
+}  // namespace rx
diff --git a/src/libANGLE/renderer/vulkan/vk_ref_counted_event.h b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.h
new file mode 100644
index 0000000..1667dad
--- /dev/null
+++ b/src/libANGLE/renderer/vulkan/vk_ref_counted_event.h
@@ -0,0 +1,163 @@
+//
+// Copyright 2024 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.
+//
+// RefCountedEvent:
+//    Manages reference count of VkEvent and its associated functions.
+//
+
+#ifndef LIBANGLE_RENDERER_VULKAN_REFCOUNTED_EVENT_H_
+#define LIBANGLE_RENDERER_VULKAN_REFCOUNTED_EVENT_H_
+
+#include <atomic>
+#include <limits>
+#include <queue>
+
+#include "common/PackedEnums.h"
+#include "common/debug.h"
+#include "libANGLE/renderer/serial_utils.h"
+#include "libANGLE/renderer/vulkan/vk_utils.h"
+#include "libANGLE/renderer/vulkan/vk_wrapper.h"
+
+namespace rx
+{
+namespace vk
+{
+enum class ImageLayout;
+
+// There are two ways to implement a barrier: Using VkCmdPipelineBarrier or VkCmdWaitEvents. The
+// BarrierType enum will be passed around to indicate which barrier caller want to use.
+enum class BarrierType
+{
+    Pipeline,
+    Event,
+};
+
+// VkCmdWaitEvents requires srcStageMask must be the bitwise OR of the stageMask parameter used in
+// previous calls to vkCmdSetEvent (See VUID-vkCmdWaitEvents-srcStageMask-01158). This mean we must
+// keep the record of what stageMask each event has been used in VkCmdSetEvent call so that we can
+// retrieve that information when we need to wait for the event. Instead of keeping just stageMask
+// here, we keep the ImageLayout for now which gives us more information for debugging.
+struct EventAndLayout
+{
+    bool valid() const { return event.valid(); }
+    Event event;
+    ImageLayout imageLayout;
+};
+
+// The VkCmdSetEvent is called after VkCmdEndRenderPass and all images that used at the given
+// pipeline stage (i.e, they have the same stageMask) will be tracked by the same event. This means
+// there will be multiple objects pointing to the same event. Events are thus reference counted so
+// that we do not destroy it while other objects still referencing to it.
+using RefCountedEventAndLayoutHandle = AtomicRefCounted<EventAndLayout> *;
+
+void ReleaseRefcountedEvent(VkDevice device, RefCountedEventAndLayoutHandle atomicRefCountedEvent);
+
+// Wrapper for RefCountedEventAndLayoutHandle.
+class RefCountedEvent final : public WrappedObject<RefCountedEvent, RefCountedEventAndLayoutHandle>
+{
+  public:
+    RefCountedEvent() = default;
+
+    // Move constructor moves reference of the underline object from other to this.
+    RefCountedEvent(RefCountedEvent &&other)
+    {
+        mHandle       = other.mHandle;
+        other.mHandle = nullptr;
+    }
+
+    // Copy constructor adds reference to the underline object.
+    RefCountedEvent(const RefCountedEvent &other)
+    {
+        mHandle = other.mHandle;
+        if (mHandle != nullptr)
+        {
+            mHandle->addRef();
+        }
+    }
+
+    // Move assignment moves reference of the underline object from other to this.
+    RefCountedEvent &operator=(RefCountedEvent &&other)
+    {
+        ASSERT(!valid());
+        std::swap(mHandle, other.mHandle);
+        return *this;
+    }
+
+    // Copy assignment adds reference to the underline object.
+    RefCountedEvent &operator=(const RefCountedEvent &other)
+    {
+        ASSERT(!valid());
+        ASSERT(other.valid());
+        mHandle = other.mHandle;
+        mHandle->addRef();
+        return *this;
+    }
+
+    // Returns true if both points to the same underline object.
+    bool operator==(const RefCountedEvent &other) const { return mHandle == other.mHandle; }
+
+    // Create VkEvent and associated it with given layout
+    void init(Context *context, ImageLayout layout);
+
+    // Release one reference count to the underline Event object and destroy if this is the
+    // very last reference.
+    void release(VkDevice device)
+    {
+        if (!valid())
+        {
+            return;
+        }
+        ReleaseRefcountedEvent(device, mHandle);
+        mHandle = nullptr;
+    }
+
+    bool valid() const { return mHandle != nullptr; }
+
+    // Returns the underlying Event object
+    const Event &getEvent() const
+    {
+        ASSERT(valid());
+        return mHandle->get().event;
+    }
+
+    // Returns the ImageLayout associated with the event.
+    ImageLayout getImageLayout() const
+    {
+        ASSERT(valid());
+        return mHandle->get().imageLayout;
+    }
+};
+
+template <>
+struct HandleTypeHelper<RefCountedEvent>
+{
+    constexpr static HandleType kHandleType = HandleType::RefCountedEvent;
+};
+
+// This class tracks a vector of RefcountedEvent garbage. For performance reason, instead of
+// individually tracking each VkEvent garbage, we collect all events that are accessed in the
+// CommandBufferHelper into this class. After we submit the command buffer, we treat this vector of
+// events as one garbage object and add it to renderer's garbage list. The garbage clean up will
+// decrement the refCount and destroy event only when last refCount goes away. Basically all GPU
+// usage will use one refCount and that refCount ensures we never destroy event until GPU is
+// finished.
+class RefCountedEventGarbageObjects final
+{
+  public:
+    // Move event to the garbage list
+    void add(RefCountedEvent *event);
+    // Move the vector of events to the garbage list
+    void add(std::vector<RefCountedEvent> *events);
+
+    bool empty() const { return mGarbageObjects.empty(); }
+
+    GarbageObjects &&release() { return std::move(mGarbageObjects); }
+
+  private:
+    GarbageObjects mGarbageObjects;
+};
+}  // namespace vk
+}  // namespace rx
+#endif  // LIBANGLE_RENDERER_VULKAN_REFCOUNTED_EVENT_H_
diff --git a/src/libANGLE/renderer/vulkan/vk_renderer.cpp b/src/libANGLE/renderer/vulkan/vk_renderer.cpp
index 8b4ef65..5386378 100644
--- a/src/libANGLE/renderer/vulkan/vk_renderer.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_renderer.cpp
@@ -284,6 +284,8 @@
     // https://issuetracker.google.com/336847261
     "VUID-VkImageCreateInfo-pNext-02397",
     "VUID-vkCmdDraw-None-06550",
+    // https://anglebug.com/8680
+    "VUID-VkSwapchainCreateInfoKHR-presentMode-02839",
 };
 
 // Validation messages that should be ignored only when VK_EXT_primitive_topology_list_restart is
diff --git a/src/libANGLE/renderer/vulkan/vk_renderer.h b/src/libANGLE/renderer/vulkan/vk_renderer.h
index 3064821..dde956b 100644
--- a/src/libANGLE/renderer/vulkan/vk_renderer.h
+++ b/src/libANGLE/renderer/vulkan/vk_renderer.h
@@ -338,6 +338,14 @@
         mSuballocationGarbageList.add(this, std::move(garbage));
     }
 
+    void collectRefCountedEventGarbage(const QueueSerial &queueSerial,
+                                       vk::RefCountedEventGarbageObjects &&garbageObjets)
+    {
+        ASSERT(!garbageObjets.empty());
+        vk::SharedGarbage garbage(vk::ResourceUse(queueSerial), std::move(garbageObjets.release()));
+        mSharedGarbageList.add(this, std::move(garbage));
+    }
+
     angle::Result getPipelineCache(vk::Context *context, vk::PipelineCacheAccess *pipelineCacheOut);
     angle::Result mergeIntoPipelineCache(vk::Context *context,
                                          const vk::PipelineCache &pipelineCache);
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.cpp b/src/libANGLE/renderer/vulkan/vk_utils.cpp
index c7fd784..d49bdcc 100644
--- a/src/libANGLE/renderer/vulkan/vk_utils.cpp
+++ b/src/libANGLE/renderer/vulkan/vk_utils.cpp
@@ -16,6 +16,7 @@
 #include "libANGLE/renderer/vulkan/DisplayVk.h"
 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
 #include "libANGLE/renderer/vulkan/vk_mem_alloc_wrapper.h"
+#include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
 #include "libANGLE/renderer/vulkan/vk_renderer.h"
 #include "libANGLE/renderer/vulkan/vk_resource.h"
 
@@ -714,6 +715,9 @@
         case HandleType::PipelineLayout:
             vkDestroyPipelineLayout(device, (VkPipelineLayout)mHandle, nullptr);
             break;
+        case HandleType::RefCountedEvent:
+            ReleaseRefcountedEvent(device, (RefCountedEventAndLayoutHandle)mHandle);
+            break;
         case HandleType::RenderPass:
             vkDestroyRenderPass(device, (VkRenderPass)mHandle, nullptr);
             break;
diff --git a/src/libANGLE/renderer/vulkan/vk_utils.h b/src/libANGLE/renderer/vulkan/vk_utils.h
index a4e53d3..1eec37a 100644
--- a/src/libANGLE/renderer/vulkan/vk_utils.h
+++ b/src/libANGLE/renderer/vulkan/vk_utils.h
@@ -701,7 +701,9 @@
     unsigned int getAndReleaseRef()
     {
         ASSERT(isReferenced());
-        return mRefCount.fetch_sub(1, std::memory_order_relaxed);
+        // This is used by RefCountedEvent which will decrement in clean up thread, so
+        // memory_order_acq_rel is needed.
+        return mRefCount.fetch_sub(1, std::memory_order_acq_rel);
     }
 
     bool isReferenced() const { return mRefCount.load(std::memory_order_relaxed) != 0; }
diff --git a/src/libANGLE/renderer/vulkan/vk_wrapper.h b/src/libANGLE/renderer/vulkan/vk_wrapper.h
index c0ab78d..098ac43 100644
--- a/src/libANGLE/renderer/vulkan/vk_wrapper.h
+++ b/src/libANGLE/renderer/vulkan/vk_wrapper.h
@@ -61,6 +61,7 @@
 {
     Invalid,
     CommandBuffer,
+    RefCountedEvent,
     ANGLE_HANDLE_TYPES_X(ANGLE_COMMA_SEP_FUNC) EnumCount
 };
 
diff --git a/src/libANGLE/renderer/vulkan/vulkan_backend.gni b/src/libANGLE/renderer/vulkan/vulkan_backend.gni
index 225d31c..89b80cf 100644
--- a/src/libANGLE/renderer/vulkan/vulkan_backend.gni
+++ b/src/libANGLE/renderer/vulkan/vulkan_backend.gni
@@ -98,6 +98,8 @@
   "vk_internal_shaders_autogen.cpp",
   "vk_internal_shaders_autogen.h",
   "vk_mandatory_format_support_table_autogen.cpp",
+  "vk_ref_counted_event.cpp",
+  "vk_ref_counted_event.h",
   "vk_renderer.cpp",
   "vk_renderer.h",
   "vk_resource.cpp",
diff --git a/src/tests/angle_end2end_tests_expectations.txt b/src/tests/angle_end2end_tests_expectations.txt
index 9ed33d0..769939a 100644
--- a/src/tests/angle_end2end_tests_expectations.txt
+++ b/src/tests/angle_end2end_tests_expectations.txt
@@ -1409,6 +1409,18 @@
 8485 WGPU : RendererTest.SimpleOperation/* = SKIP
 8582 WGPU : ClearTest.* = SKIP
 
+// Linux/UHD 630 failures caused by OS/driver upgrade.
+8683 LINUX INTEL OPENGL : AtomicCounterBufferTest31.AtomicCounterReadCompute/* = SKIP
+8683 LINUX INTEL OPENGL : ClipControlTest.OriginFragCoord/* = SKIP
+8683 LINUX INTEL VULKAN : CubeMapTextureTest.SampleCoordinateTransformGrad/* = SKIP
+8683 LINUX INTEL OPENGL : EGLMultiContextTest.ReuseUnterminatedDisplay/* = SKIP
+8683 LINUX INTEL OPENGL : GLSLTest.FragCoordConsistency/* = SKIP
+8683 LINUX INTEL OPENGL : GLSLTest_ES31.StructAndArrayEqualOperator/* = SKIP
+8683 LINUX INTEL VULKAN : TransformFeedbackTest.BufferOutOfMemory/* = SKIP
+8683 LINUX INTEL OPENGL : WEBGLVideoTextureTest.VerifySamplerVideoWEBGL/* = SKIP
+8683 LINUX INTEL OPENGL : WEBGLVideoTextureTest.VerifySamplerVideoWEBGLAsParameter/* = SKIP
+8683 LINUX INTEL OPENGL : WEBGLVideoTextureTest.VerifyStateManagerKnowsBindingVideoImage/* = SKIP
+
 // Slow tests, should appear last in this file
 5076 : GLSLTest.VerifyMaxVertexUniformVectors* = TIMEOUT
 5076 : GLSLTest.VerifyMaxFragmentUniformVectors* = TIMEOUT
diff --git a/src/tests/gl_tests/StateChangeTest.cpp b/src/tests/gl_tests/StateChangeTest.cpp
index 4222aed..ed0e19f 100644
--- a/src/tests/gl_tests/StateChangeTest.cpp
+++ b/src/tests/gl_tests/StateChangeTest.cpp
@@ -9609,6 +9609,49 @@
     ASSERT_GL_NO_ERROR();
 }
 
+// Tests state change for depth test while depth write is enabled
+TEST_P(StateChangeTestES3, DepthTestToggleWithDepthWrite)
+{
+    ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
+    glUseProgram(program);
+
+    GLint colorLoc = glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
+    ASSERT_NE(colorLoc, -1);
+
+    const int w = getWindowWidth();
+    const int h = getWindowHeight();
+
+    glClearColor(0, 0, 0, 1);
+    glClearDepthf(0.5);
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Enable depth write, but keep depth test disabled.  Internally, depth write may be disabled
+    // because of the depth test.
+    glDisable(GL_DEPTH_TEST);
+    glDepthMask(GL_TRUE);
+    glDepthFunc(GL_LESS);
+
+    // Draw with a different depth, but because depth test is disabled, depth is not actually
+    // changed.
+    glUniform4f(colorLoc, 1, 0, 0, 1);
+    drawQuad(program, essl1_shaders::PositionAttrib(), -0.3f);
+
+    // Enable depth test, but don't change state otherwise.  The following draw must change depth.
+    glEnable(GL_DEPTH_TEST);
+
+    glUniform4f(colorLoc, 0, 1, 0, 1);
+    drawQuad(program, essl1_shaders::PositionAttrib(), -0.2f);
+
+    // Verify that depth was changed in the last draw call.
+    EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::green);
+
+    glDepthFunc(GL_GREATER);
+    glUniform4f(colorLoc, 0, 0, 1, 1);
+    drawQuad(program, essl1_shaders::PositionAttrib(), -0.1f);
+    EXPECT_PIXEL_RECT_EQ(0, 0, w, h, GLColor::blue);
+    ASSERT_GL_NO_ERROR();
+}
+
 // Tests state change for stencil test and function
 TEST_P(StateChangeTestES3, StencilTestAndFunc)
 {
@@ -11007,6 +11050,7 @@
 ANGLE_INSTANTIATE_TEST_ES3_AND(
     StateChangeTestES3,
     ES3_VULKAN().disable(Feature::SupportsIndexTypeUint8),
+    ES3_VULKAN().disable(Feature::UseDepthWriteEnableDynamicState),
     ES3_VULKAN()
         .disable(Feature::SupportsExtendedDynamicState)
         .disable(Feature::SupportsExtendedDynamicState2),
diff --git a/src/tests/gl_tests/VulkanDescriptorSetTest.cpp b/src/tests/gl_tests/VulkanDescriptorSetTest.cpp
index 068f411..7ec9b4a 100644
--- a/src/tests/gl_tests/VulkanDescriptorSetTest.cpp
+++ b/src/tests/gl_tests/VulkanDescriptorSetTest.cpp
@@ -11,6 +11,7 @@
 #include "test_utils/gl_raii.h"
 
 #include "libANGLE/Context.h"
+#include "libANGLE/Display.h"
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/vulkan/ContextVk.h"
 #include "libANGLE/renderer/vulkan/ProgramVk.h"
@@ -97,6 +98,117 @@
     }
 }
 
+class VulkanDescriptorSetLayoutDescTest : public ANGLETest<>
+{
+  protected:
+    VulkanDescriptorSetLayoutDescTest() {}
+
+    void testSetUp() override { ANGLETest::testSetUp(); }
+
+    void testTearDown() override { ANGLETest::testTearDown(); }
+
+    gl::Context *hackContext() const
+    {
+        egl::Display *display   = static_cast<egl::Display *>(getEGLWindow()->getDisplay());
+        gl::ContextID contextID = {
+            static_cast<GLuint>(reinterpret_cast<uintptr_t>(getEGLWindow()->getContext()))};
+        return display->getContext(contextID);
+    }
+
+    rx::ContextVk *hackANGLE() const
+    {
+        // Hack the angle!
+        return rx::GetImplAs<rx::ContextVk>(hackContext());
+    }
+
+    struct DescriptorSetBinding
+    {
+        uint32_t bindingIndex;
+        VkDescriptorType type;
+        uint32_t bindingCount;
+        VkShaderStageFlagBits shaderStage;
+    };
+
+    const std::array<DescriptorSetBinding, 12> mBindings = {{
+        {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+        {2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {3, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+        {4, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {5, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+        {6, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {7, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+        {8, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {9, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+        {10, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT},
+        {11, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_FRAGMENT_BIT},
+    }};
+
+    void updateBindings(const std::vector<uint32_t> &bindingIndices,
+                        rx::vk::DescriptorSetLayoutDesc *desc)
+    {
+        for (uint32_t index : bindingIndices)
+        {
+            ASSERT(index < mBindings.size());
+            const DescriptorSetBinding &binding = mBindings[index];
+            desc->update(binding.bindingIndex, binding.type, binding.bindingCount,
+                         binding.shaderStage, nullptr);
+        }
+    }
+
+    rx::vk::DescriptorSetLayoutDesc mDescriptorSetLayoutDesc;
+    rx::DescriptorSetLayoutCache mDescriptorSetLayoutCache;
+};
+
+// Test basic interaction between DescriptorSetLayoutDesc and DescriptorSetLayoutCache
+TEST_P(VulkanDescriptorSetLayoutDescTest, Basic)
+{
+    const std::vector<uint32_t> bindingsPattern1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+    const std::vector<uint32_t> bindingsPattern2 = {0, 1};
+    const std::vector<uint32_t> bindingsPattern3 = {0, 1, 5, 9};
+
+    angle::Result result;
+    rx::ContextVk *contextVk = hackANGLE();
+    rx::vk::AtomicBindingPointer<rx::vk::DescriptorSetLayout> descriptorSetLayout;
+
+    mDescriptorSetLayoutDesc = {};
+    updateBindings(bindingsPattern1, &mDescriptorSetLayoutDesc);
+    result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
+                                                              &descriptorSetLayout);
+    EXPECT_EQ(result, angle::Result::Continue);
+    EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 1u);
+
+    mDescriptorSetLayoutDesc = {};
+    updateBindings(bindingsPattern2, &mDescriptorSetLayoutDesc);
+    result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
+                                                              &descriptorSetLayout);
+    EXPECT_EQ(result, angle::Result::Continue);
+    EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 2u);
+
+    mDescriptorSetLayoutDesc = {};
+    updateBindings(bindingsPattern3, &mDescriptorSetLayoutDesc);
+    size_t reusedDescHash = mDescriptorSetLayoutDesc.hash();
+    result = mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, mDescriptorSetLayoutDesc,
+                                                              &descriptorSetLayout);
+    EXPECT_EQ(result, angle::Result::Continue);
+    EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
+
+    rx::vk::DescriptorSetLayoutDesc desc;
+    updateBindings(bindingsPattern3, &desc);
+    size_t newDescHash = desc.hash();
+    EXPECT_EQ(reusedDescHash, newDescHash);
+
+    result =
+        mDescriptorSetLayoutCache.getDescriptorSetLayout(contextVk, desc, &descriptorSetLayout);
+    EXPECT_EQ(result, angle::Result::Continue);
+    EXPECT_EQ(mDescriptorSetLayoutCache.getCacheHitCount(), 1u);
+    EXPECT_EQ(mDescriptorSetLayoutCache.getCacheMissCount(), 3u);
+
+    descriptorSetLayout.reset();
+    mDescriptorSetLayoutCache.destroy(contextVk->getRenderer());
+}
+
 ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetTest, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER());
+ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetLayoutDescTest, ES31_VULKAN());
 
 }  // namespace
diff --git a/src/tests/perf_tests/TracePerfTest.cpp b/src/tests/perf_tests/TracePerfTest.cpp
index 7d3dd3a..ccc98b9 100644
--- a/src/tests/perf_tests/TracePerfTest.cpp
+++ b/src/tests/perf_tests/TracePerfTest.cpp
@@ -1204,6 +1204,11 @@
         {
             skipTest("TODO: http://anglebug.com/5943 GL_INVALID_ENUM on Windows/Intel");
         }
+
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
     }
 
     if (traceNameIs("pokemon_go"))
@@ -1335,6 +1340,11 @@
         {
             skipTest("http://anglebug.com/6658 Crashing in Vulkan backend");
         }
+
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
     }
 
     if (traceNameIs("township"))
@@ -1531,6 +1541,10 @@
 
     if (traceNameIs("minetest"))
     {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
         addExtensionPrerequisite("GL_EXT_texture_format_BGRA8888");
         addIntegerPrerequisite(GL_MAX_TEXTURE_UNITS, 4);
     }
@@ -1649,6 +1663,11 @@
 
     if (traceNameIs("street_fighter_iv_ce"))
     {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+
         if (mParams->isSwiftshader())
         {
             skipTest("https://anglebug.com/8243 Too slow on Swiftshader (large keyframe)");
@@ -1682,6 +1701,62 @@
         addIntegerPrerequisite(GL_MAX_TEXTURE_SIZE, 16383);
     }
 
+    if (traceNameIs("dr_driving"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("plague_inc"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("sonic_the_hedgehog"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("wayward_souls"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("wordscapes"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("zenonia_4"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
+    if (traceNameIs("zombie_smasher"))
+    {
+        if (isIntelLinuxNative)
+        {
+            skipTest("https://anglebug.com/8682 fails on newer OS/driver");
+        }
+    }
+
     if (IsGalaxyS22())
     {
         if (traceNameIs("cod_mobile") || traceNameIs("dota_underlords") ||
diff --git a/third_party/abseil-cpp/CMake/AbseilDll.cmake b/third_party/abseil-cpp/CMake/AbseilDll.cmake
index 31b39af..28ba25c 100644
--- a/third_party/abseil-cpp/CMake/AbseilDll.cmake
+++ b/third_party/abseil-cpp/CMake/AbseilDll.cmake
@@ -65,6 +65,7 @@
   "cleanup/internal/cleanup.h"
   "container/btree_map.h"
   "container/btree_set.h"
+  "container/hash_container_defaults.h"
   "container/fixed_array.h"
   "container/flat_hash_map.h"
   "container/flat_hash_set.h"
diff --git a/third_party/abseil-cpp/README.chromium b/third_party/abseil-cpp/README.chromium
index f24402e..35175fe 100644
--- a/third_party/abseil-cpp/README.chromium
+++ b/third_party/abseil-cpp/README.chromium
@@ -4,7 +4,7 @@
 License: Apache 2.0
 License File: LICENSE
 Version: N/A
-Revision: e022c806b07c661932967a2680e32cafdf572895
+Revision: f638e34270be76d15decb08f0e5d48b6f1f1b2c8
 Security Critical: yes
 Shipped: yes
 
diff --git a/third_party/abseil-cpp/absl/base/internal/spinlock.h b/third_party/abseil-cpp/absl/base/internal/spinlock.h
index 301c3e3..1bb260f 100644
--- a/third_party/abseil-cpp/absl/base/internal/spinlock.h
+++ b/third_party/abseil-cpp/absl/base/internal/spinlock.h
@@ -89,7 +89,8 @@
   // acquisition was successful.  If the lock was not acquired, false is
   // returned.  If this SpinLock is free at the time of the call, TryLock
   // will return true with high probability.
-  inline bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+  ABSL_MUST_USE_RESULT inline bool TryLock()
+      ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
     bool res = TryLockImpl();
     ABSL_TSAN_MUTEX_POST_LOCK(
@@ -120,7 +121,7 @@
   // Determine if the lock is held.  When the lock is held by the invoking
   // thread, true will always be returned. Intended to be used as
   // CHECK(lock.IsHeld()).
-  inline bool IsHeld() const {
+  ABSL_MUST_USE_RESULT inline bool IsHeld() const {
     return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
   }
 
diff --git a/third_party/abseil-cpp/absl/container/BUILD.bazel b/third_party/abseil-cpp/absl/container/BUILD.bazel
index 2eaece6..859163f 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/container/BUILD.bazel
@@ -248,7 +248,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":container_memory",
-        ":hash_function_defaults",
+        ":hash_container_defaults",
         ":raw_hash_map",
         "//absl/algorithm:container",
         "//absl/base:core_headers",
@@ -285,7 +285,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":container_memory",
-        ":hash_function_defaults",
+        ":hash_container_defaults",
         ":raw_hash_set",
         "//absl/algorithm:container",
         "//absl/base:core_headers",
@@ -324,7 +324,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":container_memory",
-        ":hash_function_defaults",
+        ":hash_container_defaults",
         ":node_slot_policy",
         ":raw_hash_map",
         "//absl/algorithm:container",
@@ -359,7 +359,7 @@
     linkopts = ABSL_DEFAULT_LINKOPTS,
     deps = [
         ":container_memory",
-        ":hash_function_defaults",
+        ":hash_container_defaults",
         ":node_slot_policy",
         ":raw_hash_set",
         "//absl/algorithm:container",
@@ -433,6 +433,17 @@
     ],
 )
 
+cc_library(
+    name = "hash_container_defaults",
+    hdrs = ["hash_container_defaults.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":hash_function_defaults",
+        "//absl/base:config",
+    ],
+)
+
 cc_test(
     name = "hash_function_defaults_test",
     srcs = ["internal/hash_function_defaults_test.cc"],
diff --git a/third_party/abseil-cpp/absl/container/BUILD.gn b/third_party/abseil-cpp/absl/container/BUILD.gn
index f0ba125..04eb34f 100644
--- a/third_party/abseil-cpp/absl/container/BUILD.gn
+++ b/third_party/abseil-cpp/absl/container/BUILD.gn
@@ -98,7 +98,7 @@
   public = [ "flat_hash_map.h" ]
   deps = [
     ":container_memory",
-    ":hash_function_defaults",
+    ":hash_container_defaults",
     ":raw_hash_map",
     "//third_party/abseil-cpp/absl/algorithm:container",
     "//third_party/abseil-cpp/absl/base:core_headers",
@@ -126,7 +126,7 @@
   public = [ "flat_hash_set.h" ]
   deps = [
     ":container_memory",
-    ":hash_function_defaults",
+    ":hash_container_defaults",
     ":raw_hash_set",
     "//third_party/abseil-cpp/absl/algorithm:container",
     "//third_party/abseil-cpp/absl/base:core_headers",
@@ -156,7 +156,7 @@
   public = [ "node_hash_map.h" ]
   deps = [
     ":container_memory",
-    ":hash_function_defaults",
+    ":hash_container_defaults",
     ":node_slot_policy",
     ":raw_hash_map",
     "//third_party/abseil-cpp/absl/algorithm:container",
@@ -169,7 +169,7 @@
   public = [ "node_hash_set.h" ]
   deps = [
     ":container_memory",
-    ":hash_function_defaults",
+    ":hash_container_defaults",
     ":node_slot_policy",
     ":raw_hash_set",
     "//third_party/abseil-cpp/absl/algorithm:container",
@@ -214,6 +214,15 @@
   ]
 }
 
+absl_source_set("hash_container_defaults") {
+  public = [ "hash_container_defaults.h" ]
+  visibility = [ "//third_party/abseil-cpp/absl/container:*" ]
+  deps = [
+    ":hash_function_defaults",
+    "//third_party/abseil-cpp/absl/base:config",
+  ]
+}
+
 absl_test("hash_function_defaults_test") {
   sources = [ "internal/hash_function_defaults_test.cc" ]
   deps = [
diff --git a/third_party/abseil-cpp/absl/container/CMakeLists.txt b/third_party/abseil-cpp/absl/container/CMakeLists.txt
index 576e83e..b1f5f9d 100644
--- a/third_party/abseil-cpp/absl/container/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/container/CMakeLists.txt
@@ -289,7 +289,7 @@
   DEPS
     absl::container_memory
     absl::core_headers
-    absl::hash_function_defaults
+    absl::hash_container_defaults
     absl::raw_hash_map
     absl::algorithm_container
     absl::memory
@@ -326,7 +326,7 @@
     ${ABSL_DEFAULT_COPTS}
   DEPS
     absl::container_memory
-    absl::hash_function_defaults
+    absl::hash_container_defaults
     absl::raw_hash_set
     absl::algorithm_container
     absl::core_headers
@@ -368,7 +368,7 @@
   DEPS
     absl::container_memory
     absl::core_headers
-    absl::hash_function_defaults
+    absl::hash_container_defaults
     absl::node_slot_policy
     absl::raw_hash_map
     absl::algorithm_container
@@ -404,7 +404,7 @@
   DEPS
     absl::container_memory
     absl::core_headers
-    absl::hash_function_defaults
+    absl::hash_container_defaults
     absl::node_slot_policy
     absl::raw_hash_set
     absl::algorithm_container
@@ -430,6 +430,19 @@
     GTest::gmock_main
 )
 
+absl_cc_library(
+  NAME
+    hash_container_defaults
+  HDRS
+    "hash_container_defaults.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::config
+    absl::hash_function_defaults
+  PUBLIC
+)
+
 # Internal-only target, do not depend on directly.
 absl_cc_library(
   NAME
diff --git a/third_party/abseil-cpp/absl/container/flat_hash_map.h b/third_party/abseil-cpp/absl/container/flat_hash_map.h
index a33c794..aa2c5c8 100644
--- a/third_party/abseil-cpp/absl/container/flat_hash_map.h
+++ b/third_party/abseil-cpp/absl/container/flat_hash_map.h
@@ -31,16 +31,15 @@
 #define ABSL_CONTAINER_FLAT_HASH_MAP_H_
 
 #include <cstddef>
-#include <new>
+#include <memory>
 #include <type_traits>
 #include <utility>
 
 #include "absl/algorithm/container.h"
 #include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
 #include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
-#include "absl/memory/memory.h"
 
 namespace absl {
 ABSL_NAMESPACE_BEGIN
@@ -119,9 +118,8 @@
 //  if (result != ducks.end()) {
 //    std::cout << "Result: " << result->second << std::endl;
 //  }
-template <class K, class V,
-          class Hash = absl::container_internal::hash_default_hash<K>,
-          class Eq = absl::container_internal::hash_default_eq<K>,
+template <class K, class V, class Hash = DefaultHashContainerHash<K>,
+          class Eq = DefaultHashContainerEq<K>,
           class Allocator = std::allocator<std::pair<const K, V>>>
 class flat_hash_map : public absl::container_internal::raw_hash_map<
                           absl::container_internal::FlatHashMapPolicy<K, V>,
diff --git a/third_party/abseil-cpp/absl/container/flat_hash_set.h b/third_party/abseil-cpp/absl/container/flat_hash_set.h
index 5f72f95..e558b07 100644
--- a/third_party/abseil-cpp/absl/container/flat_hash_set.h
+++ b/third_party/abseil-cpp/absl/container/flat_hash_set.h
@@ -36,8 +36,8 @@
 
 #include "absl/algorithm/container.h"
 #include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
 #include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
 #include "absl/memory/memory.h"
 
@@ -114,8 +114,8 @@
 //  if (ducks.contains("dewey")) {
 //    std::cout << "We found dewey!" << std::endl;
 //  }
-template <class T, class Hash = absl::container_internal::hash_default_hash<T>,
-          class Eq = absl::container_internal::hash_default_eq<T>,
+template <class T, class Hash = DefaultHashContainerHash<T>,
+          class Eq = DefaultHashContainerEq<T>,
           class Allocator = std::allocator<T>>
 class flat_hash_set
     : public absl::container_internal::raw_hash_set<
diff --git a/third_party/abseil-cpp/absl/container/hash_container_defaults.h b/third_party/abseil-cpp/absl/container/hash_container_defaults.h
new file mode 100644
index 0000000..eb944a7
--- /dev/null
+++ b/third_party/abseil-cpp/absl/container/hash_container_defaults.h
@@ -0,0 +1,45 @@
+// Copyright 2024 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
+#define ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
+
+#include "absl/base/config.h"
+#include "absl/container/internal/hash_function_defaults.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+
+// DefaultHashContainerHash is a convenience alias for the functor that is used
+// by default by Abseil hash-based (unordered) containers for hashing when
+// `Hash` type argument is not explicitly specified.
+//
+// This type alias can be used by generic code that wants to provide more
+// flexibility for defining underlying containers.
+template <typename T>
+using DefaultHashContainerHash = absl::container_internal::hash_default_hash<T>;
+
+// DefaultHashContainerEq is a convenience alias for the functor that is used by
+// default by Abseil hash-based (unordered) containers for equality check when
+// `Eq` type argument is not explicitly specified.
+//
+// This type alias can be used by generic code that wants to provide more
+// flexibility for defining underlying containers.
+template <typename T>
+using DefaultHashContainerEq = absl::container_internal::hash_default_eq<T>;
+
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
diff --git a/third_party/abseil-cpp/absl/container/node_hash_map.h b/third_party/abseil-cpp/absl/container/node_hash_map.h
index cb41543..31beb1d 100644
--- a/third_party/abseil-cpp/absl/container/node_hash_map.h
+++ b/third_party/abseil-cpp/absl/container/node_hash_map.h
@@ -37,14 +37,13 @@
 #define ABSL_CONTAINER_NODE_HASH_MAP_H_
 
 #include <cstddef>
-#include <tuple>
+#include <memory>
 #include <type_traits>
 #include <utility>
 
 #include "absl/algorithm/container.h"
-#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
 #include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/node_slot_policy.h"
 #include "absl/container/internal/raw_hash_map.h"  // IWYU pragma: export
 #include "absl/memory/memory.h"
@@ -114,9 +113,8 @@
 //  if (result != ducks.end()) {
 //    std::cout << "Result: " << result->second << std::endl;
 //  }
-template <class Key, class Value,
-          class Hash = absl::container_internal::hash_default_hash<Key>,
-          class Eq = absl::container_internal::hash_default_eq<Key>,
+template <class Key, class Value, class Hash = DefaultHashContainerHash<Key>,
+          class Eq = DefaultHashContainerEq<Key>,
           class Alloc = std::allocator<std::pair<const Key, Value>>>
 class node_hash_map
     : public absl::container_internal::raw_hash_map<
diff --git a/third_party/abseil-cpp/absl/container/node_hash_set.h b/third_party/abseil-cpp/absl/container/node_hash_set.h
index 8cc4b62..deeb49c 100644
--- a/third_party/abseil-cpp/absl/container/node_hash_set.h
+++ b/third_party/abseil-cpp/absl/container/node_hash_set.h
@@ -36,12 +36,12 @@
 #define ABSL_CONTAINER_NODE_HASH_SET_H_
 
 #include <cstddef>
+#include <memory>
 #include <type_traits>
 
 #include "absl/algorithm/container.h"
-#include "absl/base/macros.h"
+#include "absl/container/hash_container_defaults.h"
 #include "absl/container/internal/container_memory.h"
-#include "absl/container/internal/hash_function_defaults.h"  // IWYU pragma: export
 #include "absl/container/internal/node_slot_policy.h"
 #include "absl/container/internal/raw_hash_set.h"  // IWYU pragma: export
 #include "absl/memory/memory.h"
@@ -109,9 +109,8 @@
 //  if (ducks.contains("dewey")) {
 //    std::cout << "We found dewey!" << std::endl;
 //  }
-template <class T, class Hash = absl::container_internal::hash_default_hash<T>,
-          class Eq = absl::container_internal::hash_default_eq<T>,
-          class Alloc = std::allocator<T>>
+template <class T, class Hash = DefaultHashContainerHash<T>,
+          class Eq = DefaultHashContainerEq<T>, class Alloc = std::allocator<T>>
 class node_hash_set
     : public absl::container_internal::raw_hash_set<
           absl::container_internal::NodeHashSetPolicy<T>, Hash, Eq, Alloc> {
diff --git a/third_party/abseil-cpp/absl/functional/any_invocable.h b/third_party/abseil-cpp/absl/functional/any_invocable.h
index 68d8825..176077a 100644
--- a/third_party/abseil-cpp/absl/functional/any_invocable.h
+++ b/third_party/abseil-cpp/absl/functional/any_invocable.h
@@ -98,9 +98,9 @@
 // `AnyInvocable` also properly respects `const` qualifiers, reference
 // qualifiers, and the `noexcept` specification (only in C++ 17 and beyond) as
 // part of the user-specified function type (e.g.
-// `AnyInvocable<void()&& const noexcept>`). These qualifiers will be applied to
-// the `AnyInvocable` object's `operator()`, and the underlying invocable must
-// be compatible with those qualifiers.
+// `AnyInvocable<void() const && noexcept>`). These qualifiers will be applied
+// to the `AnyInvocable` object's `operator()`, and the underlying invocable
+// must be compatible with those qualifiers.
 //
 // Comparison of const and non-const function types:
 //
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.bazel b/third_party/abseil-cpp/absl/strings/BUILD.bazel
index d93a78a..48793ed 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.bazel
+++ b/third_party/abseil-cpp/absl/strings/BUILD.bazel
@@ -917,6 +917,7 @@
         "//absl/base:config",
         "//absl/base:core_headers",
         "//absl/base:endian",
+        "//absl/base:no_destructor",
         "//absl/container:fixed_array",
         "//absl/functional:function_ref",
         "//absl/hash",
diff --git a/third_party/abseil-cpp/absl/strings/BUILD.gn b/third_party/abseil-cpp/absl/strings/BUILD.gn
index f0ad679..9ac0db9 100644
--- a/third_party/abseil-cpp/absl/strings/BUILD.gn
+++ b/third_party/abseil-cpp/absl/strings/BUILD.gn
@@ -611,6 +611,7 @@
 #     "//third_party/abseil-cpp/absl/base:config",
 #     "//third_party/abseil-cpp/absl/base:core_headers",
 #     "//third_party/abseil-cpp/absl/base:endian",
+#     "//third_party/abseil-cpp/absl/base:no_destructor",
 #     "//third_party/abseil-cpp/absl/container:fixed_array",
 #     "//third_party/abseil-cpp/absl/functional:function_ref",
 #     "//third_party/abseil-cpp/absl/hash",
diff --git a/third_party/abseil-cpp/absl/strings/CMakeLists.txt b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
index 53e8518..99156cf 100644
--- a/third_party/abseil-cpp/absl/strings/CMakeLists.txt
+++ b/third_party/abseil-cpp/absl/strings/CMakeLists.txt
@@ -1075,6 +1075,7 @@
     absl::function_ref
     absl::hash
     absl::hash_testing
+    absl::no_destructor
     absl::log
     absl::optional
     absl::random_random
diff --git a/third_party/abseil-cpp/absl/strings/cord.cc b/third_party/abseil-cpp/absl/strings/cord.cc
index 025904c..f0f4f31 100644
--- a/third_party/abseil-cpp/absl/strings/cord.cc
+++ b/third_party/abseil-cpp/absl/strings/cord.cc
@@ -75,7 +75,7 @@
 using ::absl::cord_internal::kInlinedVectorSize;
 using ::absl::cord_internal::kMaxBytesToCopy;
 
-static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data,
+static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
                      absl::Nonnull<std::ostream*> os, int indent = 0);
 static bool VerifyNode(absl::Nonnull<CordRep*> root,
                        absl::Nonnull<CordRep*> start_node);
@@ -1457,12 +1457,13 @@
   }
 }
 
-static void DumpNode(absl::Nonnull<CordRep*> rep, bool include_data,
+static void DumpNode(absl::Nonnull<CordRep*> nonnull_rep, bool include_data,
                      absl::Nonnull<std::ostream*> os, int indent) {
+  CordRep* rep = nonnull_rep;
   const int kIndentStep = 1;
   for (;;) {
-    *os << std::setw(3) << rep->refcount.Get();
-    *os << " " << std::setw(7) << rep->length;
+    *os << std::setw(3) << (rep == nullptr ? 0 : rep->refcount.Get());
+    *os << " " << std::setw(7) << (rep == nullptr ? 0 : rep->length);
     *os << " [";
     if (include_data) *os << static_cast<void*>(rep);
     *os << "]";
diff --git a/third_party/abseil-cpp/absl/strings/cord_test.cc b/third_party/abseil-cpp/absl/strings/cord_test.cc
index 658ad55..ad96aaf 100644
--- a/third_party/abseil-cpp/absl/strings/cord_test.cc
+++ b/third_party/abseil-cpp/absl/strings/cord_test.cc
@@ -38,6 +38,7 @@
 #include "absl/base/config.h"
 #include "absl/base/internal/endian.h"
 #include "absl/base/macros.h"
+#include "absl/base/no_destructor.h"
 #include "absl/base/options.h"
 #include "absl/container/fixed_array.h"
 #include "absl/functional/function_ref.h"
@@ -2796,34 +2797,15 @@
   absl::string_view expected_;
 };
 
-// Deliberately prevents the destructor for an absl::Cord from running. The cord
-// is accessible via the cord member during the lifetime of the CordLeaker.
-// After the CordLeaker is destroyed, pointers to the cord will remain valid
-// until the CordLeaker's memory is deallocated.
-struct CordLeaker {
-  union {
-    absl::Cord cord;
-  };
-
-  template <typename Str>
-  constexpr explicit CordLeaker(const Str& str) : cord(str) {}
-
-  ~CordLeaker() {
-    // Don't do anything, including running cord's destructor. (cord's
-    // destructor won't run automatically because cord is hidden inside a
-    // union.)
-  }
-};
-
 template <typename Str>
-void TestConstinitConstructor(Str) {
+void TestAfterExit(Str) {
   const auto expected = Str::value;
   // Defined before `cord` to be destroyed after it.
   static AfterExitCordTester exit_tester;  // NOLINT
-  ABSL_CONST_INIT static CordLeaker cord_leaker(Str{});  // NOLINT
+  static absl::NoDestructor<absl::Cord> cord_leaker(Str{});
   // cord_leaker is static, so this reference will remain valid through the end
   // of program execution.
-  static absl::Cord& cord = cord_leaker.cord;
+  static absl::Cord& cord = *cord_leaker;
   static bool init_exit_tester = exit_tester.Set(&cord, expected);
   (void)init_exit_tester;
 
@@ -2875,11 +2857,9 @@
 };
 
 
-TEST_P(CordTest, ConstinitConstructor) {
-  TestConstinitConstructor(
-      absl::strings_internal::MakeStringConstant(ShortView{}));
-  TestConstinitConstructor(
-      absl::strings_internal::MakeStringConstant(LongView{}));
+TEST_P(CordTest, AfterExit) {
+  TestAfterExit(absl::strings_internal::MakeStringConstant(ShortView{}));
+  TestAfterExit(absl::strings_internal::MakeStringConstant(LongView{}));
 }
 
 namespace {
diff --git a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
index 3e76137..17c3607 100644
--- a/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
+++ b/third_party/abseil-cpp/absl/strings/internal/str_format/convert_test.cc
@@ -785,8 +785,7 @@
 }
 
 template <typename Floating>
-void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats,
-                                   const std::set<Floating> &skip_verify) {
+void TestWithMultipleFormatsHelper(const std::vector<Floating> &floats) {
   const NativePrintfTraits &native_traits = VerifyNativeImplementation();
   // Reserve the space to ensure we don't allocate memory in the output itself.
   std::string str_format_result;
@@ -834,6 +833,9 @@
           AppendPack(&str_format_result, format, absl::MakeSpan(args));
         }
 
+        // For values that we know won't match the standard library
+        // implementation we skip verification, but still run the algorithm to
+        // catch asserts/sanitizer bugs.
 #ifdef _MSC_VER
         // MSVC has a different rounding policy than us so we can't test our
         // implementation against the native one there.
@@ -842,8 +844,7 @@
         // Apple formats NaN differently (+nan) vs. (nan)
         if (std::isnan(d)) continue;
 #endif
-        if (string_printf_result != str_format_result &&
-            skip_verify.find(d) == skip_verify.end()) {
+        if (string_printf_result != str_format_result) {
           // We use ASSERT_EQ here because failures are usually correlated and a
           // bug would print way too many failed expectations causing the test
           // to time out.
@@ -904,14 +905,10 @@
   });
   floats.erase(std::unique(floats.begin(), floats.end()), floats.end());
 
-  TestWithMultipleFormatsHelper(floats, {});
+  TestWithMultipleFormatsHelper(floats);
 }
 
 TEST_F(FormatConvertTest, Double) {
-  // For values that we know won't match the standard library implementation we
-  // skip verification, but still run the algorithm to catch asserts/sanitizer
-  // bugs.
-  std::set<double> skip_verify;
   std::vector<double> doubles = {0.0,
                                  -0.0,
                                  .99999999999999,
@@ -959,7 +956,7 @@
   });
   doubles.erase(std::unique(doubles.begin(), doubles.end()), doubles.end());
 
-  TestWithMultipleFormatsHelper(doubles, skip_verify);
+  TestWithMultipleFormatsHelper(doubles);
 }
 
 TEST_F(FormatConvertTest, DoubleRound) {
diff --git a/third_party/abseil-cpp/absl/synchronization/mutex.h b/third_party/abseil-cpp/absl/synchronization/mutex.h
index 9505225..be3f1f5 100644
--- a/third_party/abseil-cpp/absl/synchronization/mutex.h
+++ b/third_party/abseil-cpp/absl/synchronization/mutex.h
@@ -190,7 +190,7 @@
   // If the mutex can be acquired without blocking, does so exclusively and
   // returns `true`. Otherwise, returns `false`. Returns `true` with high
   // probability if the `Mutex` was free.
-  bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
+  ABSL_MUST_USE_RESULT bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
 
   // Mutex::AssertHeld()
   //
@@ -255,7 +255,7 @@
   // If the mutex can be acquired without blocking, acquires this mutex for
   // shared access and returns `true`. Otherwise, returns `false`. Returns
   // `true` with high probability if the `Mutex` was free or shared.
-  bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
+  ABSL_MUST_USE_RESULT bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
 
   // Mutex::AssertReaderHeld()
   //
@@ -281,7 +281,8 @@
 
   void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
 
-  bool WriterTryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
+  ABSL_MUST_USE_RESULT bool WriterTryLock()
+      ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
     return this->TryLock();
   }
 
diff --git a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
index d014612..b509402 100644
--- a/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/third_party/abseil-cpp/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -12,7 +12,7 @@
 //   See the License for the specific language governing permissions and
 //   limitations under the License.
 
-#if defined(_WIN32) || defined(_WIN64)
+#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_WIN32)
 #define _CRT_SECURE_NO_WARNINGS 1
 #endif