diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index c49d621..9145d8b 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -448,7 +448,12 @@
   "debugging/leak_check.cc"
 )
 
-if(NOT MSVC)
+if(MSVC)
+  list(APPEND ABSL_INTERNAL_DLL_FILES
+    "time/internal/cctz/src/time_zone_name_win.cc"
+    "time/internal/cctz/src/time_zone_name_win.h"
+  )
+else()
   list(APPEND ABSL_INTERNAL_DLL_FILES
     "flags/commandlineflag.cc"
     "flags/commandlineflag.h"
diff --git a/absl/base/attributes.h b/absl/base/attributes.h
index 33b2c28..77482e5 100644
--- a/absl/base/attributes.h
+++ b/absl/base/attributes.h
@@ -580,7 +580,11 @@
 // Instructs the compiler not to use natural alignment for a tagged data
 // structure, but instead to reduce its alignment to 1.
 //
-// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
+// Use of this attribute is HIGHLY DISCOURAGED. Taking the address of or
+// binding a reference to any unaligned member is UB, and it is very easy to
+// do so unintentionally when passing such members as function arguments.
+//
+// DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
 // so can cause atomic variables to be mis-aligned and silently violate
 // atomicity on x86.
 //
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 68a9008..ab6533f 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -429,6 +429,7 @@
     deps = [
         ":container_memory",
         ":test_instance_tracker",
+        "//absl/base:config",
         "//absl/base:no_destructor",
         "//absl/meta:type_traits",
         "//absl/strings",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 6adba18..adce9a9 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -484,6 +484,7 @@
   COPTS
     ${ABSL_TEST_COPTS}
   DEPS
+    absl::config
     absl::container_memory
     absl::no_destructor
     absl::strings
diff --git a/absl/container/internal/container_memory.h b/absl/container/internal/container_memory.h
index 8c97469..608a865 100644
--- a/absl/container/internal/container_memory.h
+++ b/absl/container/internal/container_memory.h
@@ -44,7 +44,12 @@
 namespace container_internal {
 
 template <size_t Alignment>
-struct alignas(Alignment) AlignedType {};
+struct alignas(Alignment) AlignedType {
+  // When alignment is sufficient for the allocated memory to store pointers,
+  // include a pointer member so that swisstable backing arrays end up in the
+  // pointer-containing partition for heap partitioning.
+  std::conditional_t<(Alignment < alignof(void*)), char, void*> pointer;
+};
 
 // Allocates at least n bytes aligned to the specified alignment.
 // Alignment must be a power of 2. It must be positive.
diff --git a/absl/container/internal/container_memory_test.cc b/absl/container/internal/container_memory_test.cc
index 97b09f7..946d1d3 100644
--- a/absl/container/internal/container_memory_test.cc
+++ b/absl/container/internal/container_memory_test.cc
@@ -25,6 +25,7 @@
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/base/config.h"
 #include "absl/base/no_destructor.h"
 #include "absl/container/internal/test_instance_tracker.h"
 #include "absl/meta/type_traits.h"
@@ -42,6 +43,16 @@
 using ::testing::Gt;
 using ::testing::Pair;
 
+#if ABSL_HAVE_BUILTIN(__builtin_infer_alloc_token)
+TEST(Memory, AlignedTypeAllocToken) {
+#if defined(__wasm__)
+  GTEST_SKIP() << "Fails on wasm due to lack of heap partitioning support.";
+#endif
+  EXPECT_GT(__builtin_infer_alloc_token(sizeof(AlignedType<alignof(void*)>)),
+            __builtin_infer_alloc_token(sizeof(int)));
+}
+#endif
+
 TEST(Memory, AlignmentLargerThanBase) {
   std::allocator<int8_t> alloc;
   void* mem = Allocate<2>(&alloc, 3);
diff --git a/absl/container/internal/hashtablez_sampler.cc b/absl/container/internal/hashtablez_sampler.cc
index 4adf591..4f6e946 100644
--- a/absl/container/internal/hashtablez_sampler.cc
+++ b/absl/container/internal/hashtablez_sampler.cc
@@ -87,7 +87,6 @@
   total_probe_length.store(0, std::memory_order_relaxed);
   hashes_bitwise_or.store(0, std::memory_order_relaxed);
   hashes_bitwise_and.store(~size_t{}, std::memory_order_relaxed);
-  hashes_bitwise_xor.store(0, std::memory_order_relaxed);
   max_reserve.store(0, std::memory_order_relaxed);
 
   create_time = absl::Now();
@@ -244,7 +243,6 @@
 
   info->hashes_bitwise_and.fetch_and(hash, std::memory_order_relaxed);
   info->hashes_bitwise_or.fetch_or(hash, std::memory_order_relaxed);
-  info->hashes_bitwise_xor.fetch_xor(hash, std::memory_order_relaxed);
   info->max_probe_length.store(
       std::max(info->max_probe_length.load(std::memory_order_relaxed),
                probe_length),
diff --git a/absl/container/internal/hashtablez_sampler.h b/absl/container/internal/hashtablez_sampler.h
index 163b18a..6c20dc3 100644
--- a/absl/container/internal/hashtablez_sampler.h
+++ b/absl/container/internal/hashtablez_sampler.h
@@ -88,7 +88,6 @@
   std::atomic<size_t> total_probe_length;
   std::atomic<size_t> hashes_bitwise_or;
   std::atomic<size_t> hashes_bitwise_and;
-  std::atomic<size_t> hashes_bitwise_xor;
   std::atomic<size_t> max_reserve;
 
   // All of the fields below are set by `PrepareForSampling`, they must not be
diff --git a/absl/container/internal/hashtablez_sampler_test.cc b/absl/container/internal/hashtablez_sampler_test.cc
index cbd8edc..9391e94 100644
--- a/absl/container/internal/hashtablez_sampler_test.cc
+++ b/absl/container/internal/hashtablez_sampler_test.cc
@@ -105,7 +105,6 @@
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_GE(info.create_time, test_start);
   EXPECT_EQ(info.weight, test_stride);
@@ -122,7 +121,6 @@
   info.total_probe_length.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_or.store(1, std::memory_order_relaxed);
   info.hashes_bitwise_and.store(1, std::memory_order_relaxed);
-  info.hashes_bitwise_xor.store(1, std::memory_order_relaxed);
   info.max_reserve.store(1, std::memory_order_relaxed);
   info.create_time = test_start - absl::Hours(20);
 
@@ -139,7 +137,6 @@
   EXPECT_EQ(info.total_probe_length.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0);
   EXPECT_EQ(info.hashes_bitwise_and.load(), ~size_t{});
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0);
   EXPECT_EQ(info.max_reserve.load(), 0);
   EXPECT_EQ(info.weight, 2 * test_stride);
   EXPECT_EQ(info.inline_element_size, test_element_size);
@@ -186,17 +183,14 @@
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000FF00);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x0000FF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x0000FF00);
   RecordInsertMissSlow(&info, 0x000FF000, 4 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 6);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x0000F000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x000FFF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x000F0F00);
   RecordInsertMissSlow(&info, 0x00FF0000, 12 * kProbeLength);
   EXPECT_EQ(info.max_probe_length.load(), 12);
   EXPECT_EQ(info.hashes_bitwise_and.load(), 0x00000000);
   EXPECT_EQ(info.hashes_bitwise_or.load(), 0x00FFFF00);
-  EXPECT_EQ(info.hashes_bitwise_xor.load(), 0x00F00F00);
 }
 
 TEST(HashtablezInfoTest, RecordErase) {
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc
index 0ef10ef..9955029 100644
--- a/absl/container/internal/raw_hash_set.cc
+++ b/absl/container/internal/raw_hash_set.cc
@@ -19,6 +19,7 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <memory>
 #include <tuple>
 #include <utility>
 
@@ -763,7 +764,16 @@
                                    void* alloc) {
   RawHashSetLayout layout(new_capacity, policy.slot_size, policy.slot_align,
                           has_infoz);
-  char* mem = static_cast<char*>(policy.alloc(alloc, layout.alloc_size()));
+  // Perform a direct call in the common case to allow for profile-guided
+  // heap optimization (PGHO) to understand which allocation function is used.
+  constexpr size_t kDefaultAlignment = BackingArrayAlignment(alignof(size_t));
+  char* mem = static_cast<char*>(
+      ABSL_PREDICT_TRUE(
+          policy.alloc ==
+          (&AllocateBackingArray<kDefaultAlignment, std::allocator<char>>))
+          ? AllocateBackingArray<kDefaultAlignment, std::allocator<char>>(
+                alloc, layout.alloc_size())
+          : policy.alloc(alloc, layout.alloc_size()));
   const GenerationType old_generation = common.generation();
   common.set_generation_ptr(
       reinterpret_cast<GenerationType*>(mem + layout.generation_offset()));
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h
index 31b117e..1d209e0 100644
--- a/absl/container/internal/raw_hash_set.h
+++ b/absl/container/internal/raw_hash_set.h
@@ -1492,10 +1492,12 @@
 
 // Allocates `n` bytes for a backing array.
 template <size_t AlignOfBackingArray, typename Alloc>
-ABSL_ATTRIBUTE_NOINLINE void* AllocateBackingArray(void* alloc, size_t n) {
+void* AllocateBackingArray(void* alloc, size_t n) {
   return Allocate<AlignOfBackingArray>(static_cast<Alloc*>(alloc), n);
 }
 
+// Note: we mark this function as ABSL_ATTRIBUTE_NOINLINE because we don't want
+// it to be inlined into e.g. the destructor to save code size.
 template <size_t AlignOfBackingArray, typename Alloc>
 ABSL_ATTRIBUTE_NOINLINE void DeallocateBackingArray(
     void* alloc, size_t capacity, ctrl_t* ctrl, size_t slot_size,
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc
index 8c80463..e8de41a 100644
--- a/absl/container/internal/raw_hash_set_test.cc
+++ b/absl/container/internal/raw_hash_set_test.cc
@@ -2830,8 +2830,6 @@
   end_size += sampler.Iterate([&](const HashtablezInfo& info) {
     ++end_size;
     if (preexisting_info.contains(&info)) return;
-    observed_checksums[info.hashes_bitwise_xor.load(
-        std::memory_order_relaxed)]++;
     reservations[info.max_reserve.load(std::memory_order_relaxed)]++;
     hit_misses[std::make_pair(
         info.num_insert_hits.load(std::memory_order_relaxed),
@@ -2851,10 +2849,6 @@
   // Expect that we sampled at the requested sampling rate of ~1%.
   EXPECT_NEAR((end_size - start_size) / static_cast<double>(tables.size()),
               0.01, 0.005);
-  ASSERT_EQ(observed_checksums.size(), 5);
-  for (const auto& [_, count] : observed_checksums) {
-    EXPECT_NEAR((100 * count) / static_cast<double>(tables.size()), 0.2, 0.05);
-  }
 
   ASSERT_EQ(reservations.size(), 10);
   for (const auto& [reservation, count] : reservations) {
diff --git a/absl/hash/internal/hash.cc b/absl/hash/internal/hash.cc
index 9e43e94..35ab0a2 100644
--- a/absl/hash/internal/hash.cc
+++ b/absl/hash/internal/hash.cc
@@ -26,6 +26,20 @@
 #include "absl/base/prefetch.h"
 #include "absl/hash/internal/city.h"
 
+
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#error ABSL_AES_INTERNAL_HAVE_X86_SIMD cannot be directly set
+#elif defined(__SSE4_2__) && defined(__AES__)
+#define ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#endif
+
+
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+#include <smmintrin.h>
+#include <wmmintrin.h>
+#include <xmmintrin.h>
+#endif  // ABSL_AES_INTERNAL_HAVE_X86_SIMD
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace hash_internal {
@@ -43,47 +57,86 @@
   return cs0 ^ cs1;
 }
 
-[[maybe_unused]] uint64_t LowLevelHashLenGt32(const void* data, size_t len,
-                                              uint64_t seed) {
+#ifdef ABSL_AES_INTERNAL_HAVE_X86_SIMD
+uint64_t LowLevelHash33To64(const uint8_t* ptr, size_t len, uint64_t seed) {
   assert(len > 32);
+  assert(len <= 64);
+  __m128i state =
+      _mm_set_epi64x(static_cast<int64_t>(seed), static_cast<int64_t>(len));
+  auto a = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr));
+  auto b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(ptr + 16));
+  auto* last32_ptr = ptr + len - 32;
+  auto c = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr));
+  auto d = _mm_loadu_si128(reinterpret_cast<const __m128i*>(last32_ptr + 16));
+
+  // Bits of the second argument to _mm_aesdec_si128/_mm_aesenc_si128 are
+  // XORed with the state argument after encryption.
+  // We use each value as the first argument to shuffle all the bits around.
+  // We do not add any salt to the state or loaded data, instead we vary
+  // instructions used to mix bits _mm_aesdec_si128/_mm_aesenc_si128 and
+  // _mm_add_epi64/_mm_sub_epi64.
+  // _mm_add_epi64/_mm_sub_epi64 are combined to one instruction with data
+  // loading like `vpaddq  xmm1, xmm0, xmmword ptr [rdi]`.
+  auto na = _mm_aesdec_si128(_mm_add_epi64(state, a), state);
+  auto nb = _mm_aesdec_si128(_mm_sub_epi64(state, b), state);
+  auto nc = _mm_aesenc_si128(_mm_add_epi64(state, c), state);
+  auto nd = _mm_aesenc_si128(_mm_sub_epi64(state, d), state);
+
+  // We perform another round of encryption to mix bits between two halves of
+  // the input.
+  auto res128 = _mm_add_epi64(_mm_aesenc_si128(_mm_add_epi64(na, nc), nd),
+                              _mm_aesdec_si128(_mm_sub_epi64(nb, nd), na));
+  auto x64 = static_cast<uint64_t>(_mm_cvtsi128_si64(res128));
+  auto y64 = static_cast<uint64_t>(_mm_extract_epi64(res128, 1));
+  return x64 ^ y64;
+}
+#else
+uint64_t LowLevelHash33To64(const uint8_t* ptr, size_t len, uint64_t seed) {
+  assert(len > 32);
+  assert(len <= 64);
+  uint64_t current_state = seed ^ kStaticRandomData[0] ^ len;
+  const uint8_t* last_32_ptr = ptr + len - 32;
+  return Mix32Bytes(last_32_ptr, Mix32Bytes(ptr, current_state));
+}
+#endif  // ABSL_AES_INTERNAL_HAVE_X86_SIMD
+
+[[maybe_unused]] ABSL_ATTRIBUTE_NOINLINE uint64_t
+LowLevelHashLenGt64(const void* data, size_t len, uint64_t seed) {
+  assert(len > 64);
   const uint8_t* ptr = static_cast<const uint8_t*>(data);
   uint64_t current_state = seed ^ kStaticRandomData[0] ^ len;
   const uint8_t* last_32_ptr = ptr + len - 32;
+  // If we have more than 64 bytes, we're going to handle chunks of 64
+  // bytes at a time. We're going to build up four separate hash states
+  // which we will then hash together. This avoids short dependency chains.
+  uint64_t duplicated_state0 = current_state;
+  uint64_t duplicated_state1 = current_state;
+  uint64_t duplicated_state2 = current_state;
 
-  if (len > 64) {
-    // If we have more than 64 bytes, we're going to handle chunks of 64
-    // bytes at a time. We're going to build up four separate hash states
-    // which we will then hash together. This avoids short dependency chains.
-    uint64_t duplicated_state0 = current_state;
-    uint64_t duplicated_state1 = current_state;
-    uint64_t duplicated_state2 = current_state;
+  do {
+    PrefetchToLocalCache(ptr + 5 * ABSL_CACHELINE_SIZE);
 
-    do {
-      PrefetchToLocalCache(ptr + 5 * ABSL_CACHELINE_SIZE);
+    uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
+    uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
+    uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
+    uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
+    uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
+    uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
+    uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
+    uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
 
-      uint64_t a = absl::base_internal::UnalignedLoad64(ptr);
-      uint64_t b = absl::base_internal::UnalignedLoad64(ptr + 8);
-      uint64_t c = absl::base_internal::UnalignedLoad64(ptr + 16);
-      uint64_t d = absl::base_internal::UnalignedLoad64(ptr + 24);
-      uint64_t e = absl::base_internal::UnalignedLoad64(ptr + 32);
-      uint64_t f = absl::base_internal::UnalignedLoad64(ptr + 40);
-      uint64_t g = absl::base_internal::UnalignedLoad64(ptr + 48);
-      uint64_t h = absl::base_internal::UnalignedLoad64(ptr + 56);
+    current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state);
+    duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0);
 
-      current_state = Mix(a ^ kStaticRandomData[1], b ^ current_state);
-      duplicated_state0 = Mix(c ^ kStaticRandomData[2], d ^ duplicated_state0);
+    duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1);
+    duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2);
 
-      duplicated_state1 = Mix(e ^ kStaticRandomData[3], f ^ duplicated_state1);
-      duplicated_state2 = Mix(g ^ kStaticRandomData[4], h ^ duplicated_state2);
+    ptr += 64;
+    len -= 64;
+  } while (len > 64);
 
-      ptr += 64;
-      len -= 64;
-    } while (len > 64);
-
-    current_state = (current_state ^ duplicated_state0) ^
-                    (duplicated_state1 + duplicated_state2);
-  }
-
+  current_state = (current_state ^ duplicated_state0) ^
+                  (duplicated_state1 + duplicated_state2);
   // We now have a data `ptr` with at most 64 bytes and the current state
   // of the hashing state machine stored in current_state.
   if (len > 32) {
@@ -96,6 +149,15 @@
   return Mix32Bytes(last_32_ptr, current_state);
 }
 
+[[maybe_unused]] uint64_t LowLevelHashLenGt32(const void* data, size_t len,
+                                              uint64_t seed) {
+  assert(len > 32);
+  if (ABSL_PREDICT_FALSE(len > 64)) {
+    return LowLevelHashLenGt64(data, len, seed);
+  }
+  return LowLevelHash33To64(static_cast<const uint8_t*>(data), len, seed);
+}
+
 ABSL_ATTRIBUTE_ALWAYS_INLINE inline uint64_t HashBlockOn32Bit(
     const unsigned char* data, size_t len, uint64_t state) {
   // TODO(b/417141985): expose and use CityHash32WithSeed.
diff --git a/absl/hash/internal/low_level_hash_test.cc b/absl/hash/internal/low_level_hash_test.cc
index 9b7868c..c8573b1 100644
--- a/absl/hash/internal/low_level_hash_test.cc
+++ b/absl/hash/internal/low_level_hash_test.cc
@@ -364,6 +364,41 @@
   GTEST_SKIP()
       << "We only maintain golden data for little endian 64 bit systems with "
          "128 bit intristics.";
+#elif defined(__SSE4_2__) && defined(__AES__)
+  constexpr uint64_t kGolden[kNumGoldenOutputs] = {
+      0xd6bdb2c9ba5e55f2, 0xffd3e23d4115a8ae, 0x2c3218ef486127de,
+      0x554fa7f3a262b886, 0x06304cbf82e312d3, 0x490b3fb5af80622c,
+      0x7398a90b8cc59c5d, 0x65fb3168b98030ab, 0xd4564363c53617bb,
+      0x0545c26351925fe7, 0xc30700723b634bf4, 0xfb23a140a76dbe94,
+      0x2fa1467fe218a47c, 0x92e05ec3a7b966eb, 0x6112b56e5624dd50,
+      0x8760801365f9d722, 0x41f7187b61db0e5e, 0x7fe9188a1f5f50ad,
+      0x25800bd4c2002ef1, 0x91fecd33a78ef0aa, 0x93986ad71e983613,
+      0xe4c78173c7ea537b, 0x0bbdc2bcabdb50b1, 0xd9aa134df2d87623,
+      0x6c4907c9477a9409, 0xc3e418a5dbda52e5, 0x4d24f3e9d0dda93a,
+      0xcdb565a363dbe45f, 0xa95f228c8ee57478, 0x6b8f00bab5130227,
+      0x2d05a0f44818b67a, 0xa64b55b071afbbea, 0xa205bfe6c724ce4d,
+      0x69dd26ca8ac21744, 0xef80e2ff2f6a9bc0, 0xde266c0baa202c20,
+      0xfa3463080ac74c50, 0x379d968a40125c2b, 0x4cbbd0a7b3c7d648,
+      0xc92afd93f4c665d2, 0x6e28f5adb7ae38dc, 0x7c689c9c237be35e,
+      0xaea41b29bd9d0f73, 0x832cef631d77e59f, 0x70cac8e87bc37dd3,
+      0x8e8c98bbde68e764, 0xd6117aeb3ddedded, 0xd796ab808e766240,
+      0x8953d0ea1a7d9814, 0xa212eba4281b391c, 0x21a555a8939ce597,
+      0x809d31660f6d81a8, 0x2356524b20ab400f, 0x5bc611e1e49d0478,
+      0xba9c065e2f385ce2, 0xb0a0fd12f4e83899, 0x14d076a35b1ff2ca,
+      0x8acd0bb8cf9a93c0, 0xe62e8ec094039ee4, 0x38a536a7072bdc61,
+      0xca256297602524f8, 0xfc62ebfb3530caeb, 0x8d8b0c05520569f6,
+      0xbbaca65cf154c59d, 0x3739b5ada7e338d3, 0xdb9ea31f47365340,
+      0x410b5c9c1da56755, 0x7e0abc03dbd10283, 0x136f87be70ed442e,
+      0x6b727d4feddbe1e9, 0x074ebb21183b01df, 0x3fe92185b1985484,
+      0xc5d8efd3c68305ca, 0xd9bada21b17e272e, 0x64d73133e1360f83,
+      0xeb8563aa993e21f9, 0xe5e8da50cceab28f, 0x7a6f92eb3223d2f3,
+      0xbdaf98370ea9b31b, 0x1682a84457f077bc, 0x4abd2d33b6e3be37,
+      0xb35bc81a7c9d4c04, 0x3e5bde3fb7cfe63d, 0xff3abe6e2ffec974,
+      0xb8116dd26cf6feec, 0x7a77a6e4ed0cf081, 0xb71eec2d5a184316,
+      0x6fa932f77b4da817, 0x795f79b33909b2c4, 0x1b8755ef6b5eb34e,
+      0x2255b72d7d6b2d79, 0xf2bdafafa90bd50a, 0x442a578f02cb1fc8,
+      0xc25aefe55ecf83db, 0x3114c056f9c5a676,
+  };
 #else
   constexpr uint64_t kGolden[kNumGoldenOutputs] = {
       0x669da02f8d009e0f, 0xceb19bf2255445cd, 0x0e746992d6d43a7c,
diff --git a/absl/profiling/hashtable.cc b/absl/profiling/hashtable.cc
index 17148d1..7c1a839 100644
--- a/absl/profiling/hashtable.cc
+++ b/absl/profiling/hashtable.cc
@@ -70,7 +70,6 @@
   const auto key_size_id = builder.InternString("key_size");
   const auto value_size_id = builder.InternString("value_size");
   const auto soo_capacity_id = builder.InternString("soo_capacity");
-  const auto checksum_id = builder.InternString("checksum");
   const auto table_age_id = builder.InternString("table_age");
   const auto max_reserve_id = builder.InternString("max_reserve");
 
@@ -106,8 +105,6 @@
         add_label(key_size_id, info.key_size);
         add_label(value_size_id, info.value_size);
         add_label(soo_capacity_id, info.soo_capacity);
-        add_label(checksum_id,
-                  info.hashes_bitwise_xor.load(std::memory_order_relaxed));
         add_label(
             table_age_id,
             static_cast<uint64_t>(ToInt64Microseconds(now - info.create_time)));
diff --git a/absl/strings/string_view.h b/absl/strings/string_view.h
index 49df37c..3176657 100644
--- a/absl/strings/string_view.h
+++ b/absl/strings/string_view.h
@@ -246,6 +246,9 @@
   }
 #endif  // ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
 
+  // Deleted constructor from std::nullptr_t from C++23.
+  string_view(std::nullptr_t) = delete;
+
   constexpr string_view(const string_view&) noexcept = default;
   string_view& operator=(const string_view&) noexcept = default;
 
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index ea91ba3..34a5ad4 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -77,6 +77,8 @@
     "internal/cctz/src/time_zone_posix.h"
     "internal/cctz/src/tzfile.h"
     "internal/cctz/src/zone_info_source.cc"
+    $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.cc>
+    $<$<PLATFORM_ID:Windows>:internal/cctz/src/time_zone_name_win.h>
   COPTS
     ${ABSL_DEFAULT_COPTS}
   DEPS
diff --git a/absl/time/internal/cctz/BUILD.bazel b/absl/time/internal/cctz/BUILD.bazel
index 6e17874..e7e2ee0 100644
--- a/absl/time/internal/cctz/BUILD.bazel
+++ b/absl/time/internal/cctz/BUILD.bazel
@@ -59,7 +59,13 @@
         "src/time_zone_posix.h",
         "src/tzfile.h",
         "src/zone_info_source.cc",
-    ],
+    ] + select({
+        "@platforms//os:windows": [
+            "src/time_zone_name_win.cc",
+            "src/time_zone_name_win.h",
+        ],
+        "//conditions:default": [],
+    }),
     hdrs = [
         "include/cctz/time_zone.h",
         "include/cctz/zone_info_source.h",
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index e8f1d93..d1078de 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -32,31 +32,6 @@
 #include <zircon/types.h>
 #endif
 
-#if defined(_WIN32)
-// Include only when <icu.h> is available.
-// https://learn.microsoft.com/en-us/windows/win32/intl/international-components-for-unicode--icu-
-// https://devblogs.microsoft.com/oldnewthing/20210527-00/?p=105255
-#if defined(__has_include)
-#if __has_include(<icu.h>)
-#define USE_WIN32_LOCAL_TIME_ZONE
-#include <windows.h>
-#pragma push_macro("_WIN32_WINNT")
-#pragma push_macro("NTDDI_VERSION")
-// Minimum _WIN32_WINNT and NTDDI_VERSION to use ucal_getTimeZoneIDForWindowsID
-#undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0A00  // == _WIN32_WINNT_WIN10
-#undef NTDDI_VERSION
-#define NTDDI_VERSION 0x0A000004  // == NTDDI_WIN10_RS3
-#include <icu.h>
-#pragma pop_macro("NTDDI_VERSION")
-#pragma pop_macro("_WIN32_WINNT")
-#include <timezoneapi.h>
-
-#include <atomic>
-#endif  // __has_include(<icu.h>)
-#endif  // __has_include
-#endif  // _WIN32
-
 #include <array>
 #include <cstdint>
 #include <cstdlib>
@@ -66,87 +41,15 @@
 #include "absl/time/internal/cctz/src/time_zone_fixed.h"
 #include "absl/time/internal/cctz/src/time_zone_impl.h"
 
+#if defined(_WIN32)
+#include "absl/time/internal/cctz/src/time_zone_name_win.h"
+#endif  // _WIN32
+
 namespace absl {
 ABSL_NAMESPACE_BEGIN
 namespace time_internal {
 namespace cctz {
 
-namespace {
-#if defined(USE_WIN32_LOCAL_TIME_ZONE)
-// True if we have already failed to load the API.
-static std::atomic_bool g_ucal_getTimeZoneIDForWindowsIDUnavailable;
-static std::atomic<decltype(ucal_getTimeZoneIDForWindowsID)*>
-    g_ucal_getTimeZoneIDForWindowsIDRef;
-
-std::string win32_local_time_zone() {
-  // If we have already failed to load the API, then just give up.
-  if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
-    return "";
-  }
-
-  auto ucal_getTimeZoneIDForWindowsIDFunc =
-      g_ucal_getTimeZoneIDForWindowsIDRef.load();
-  if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
-    // If we have already failed to load the API, then just give up.
-    if (g_ucal_getTimeZoneIDForWindowsIDUnavailable.load()) {
-      return "";
-    }
-
-    const HMODULE icudll =
-        ::LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
-
-    if (icudll == nullptr) {
-      g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
-      return "";
-    }
-
-    ucal_getTimeZoneIDForWindowsIDFunc =
-        reinterpret_cast<decltype(ucal_getTimeZoneIDForWindowsID)*>(
-            ::GetProcAddress(icudll, "ucal_getTimeZoneIDForWindowsID"));
-
-    if (ucal_getTimeZoneIDForWindowsIDFunc == nullptr) {
-      g_ucal_getTimeZoneIDForWindowsIDUnavailable.store(true);
-      return "";
-    }
-    // store-race is not a problem here, because ::GetProcAddress() returns the
-    // same address for the same function in the same DLL.
-    g_ucal_getTimeZoneIDForWindowsIDRef.store(
-        ucal_getTimeZoneIDForWindowsIDFunc);
-
-    // We intentionally do not call ::FreeLibrary() here to avoid frequent DLL
-    // loadings and unloading. As "icu.dll" is a system library, keeping it on
-    // memory is supposed to have no major drawback.
-  }
-
-  DYNAMIC_TIME_ZONE_INFORMATION info = {};
-  if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) {
-    return "";
-  }
-
-  std::array<UChar, 128> buffer;
-  UErrorCode status = U_ZERO_ERROR;
-  const auto num_chars_in_buffer = ucal_getTimeZoneIDForWindowsIDFunc(
-      reinterpret_cast<const UChar*>(info.TimeZoneKeyName), -1, nullptr,
-      buffer.data(), static_cast<int32_t>(buffer.size()), &status);
-  if (status != U_ZERO_ERROR || num_chars_in_buffer <= 0 ||
-      num_chars_in_buffer > static_cast<int32_t>(buffer.size())) {
-    return "";
-  }
-
-  const int num_bytes_in_utf8 = ::WideCharToMultiByte(
-      CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
-      static_cast<int>(num_chars_in_buffer), nullptr, 0, nullptr, nullptr);
-  std::string local_time_str;
-  local_time_str.resize(static_cast<size_t>(num_bytes_in_utf8));
-  ::WideCharToMultiByte(
-      CP_UTF8, 0, reinterpret_cast<const wchar_t*>(buffer.data()),
-      static_cast<int>(num_chars_in_buffer), &local_time_str[0],
-      num_bytes_in_utf8, nullptr, nullptr);
-  return local_time_str;
-}
-#endif  // USE_WIN32_LOCAL_TIME_ZONE
-}  // namespace
-
 std::string time_zone::name() const { return effective_impl().Name(); }
 
 time_zone::absolute_lookup time_zone::lookup(
@@ -261,8 +164,8 @@
     zone = primary_tz.c_str();
   }
 #endif
-#if defined(USE_WIN32_LOCAL_TIME_ZONE)
-  std::string win32_tz = win32_local_time_zone();
+#if defined(_WIN32)
+  std::string win32_tz = GetWindowsLocalTimeZone();
   if (!win32_tz.empty()) {
     zone = win32_tz.c_str();
   }
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.cc b/absl/time/internal/cctz/src/time_zone_name_win.cc
new file mode 100644
index 0000000..c3351cf
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_name_win.cc
@@ -0,0 +1,187 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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.
+
+#include "absl/time/internal/cctz/src/time_zone_name_win.h"
+
+#include "absl/base/config.h"
+
+#if !defined(NOMINMAX)
+#define NOMINMAX
+#endif  // !defined(NOMINMAX)
+#include <windows.h>
+
+#include <algorithm>
+#include <atomic>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <type_traits>
+#include <utility>
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+namespace {
+
+// Define UChar as wchar_t here because Win32 APIs receive UTF-16 strings as
+// wchar_t* instead of char16_t*. Using char16_t would require additional casts.
+using UChar = wchar_t;
+
+enum UErrorCode : std::int32_t {
+  U_ZERO_ERROR = 0,
+  U_BUFFER_OVERFLOW_ERROR = 15,
+};
+
+bool U_SUCCESS(UErrorCode error) { return error <= U_ZERO_ERROR; }
+
+using ucal_getTimeZoneIDForWindowsID_func = std::int32_t(__cdecl*)(
+    const UChar* winid, std::int32_t len, const char* region, UChar* id,
+    std::int32_t id_capacity, UErrorCode* status);
+
+std::atomic<bool> g_unavailable;
+std::atomic<ucal_getTimeZoneIDForWindowsID_func>
+    g_ucal_getTimeZoneIDForWindowsID;
+
+template <typename T>
+static T AsProcAddress(HMODULE module, const char* name) {
+  static_assert(
+      std::is_pointer<T>::value &&
+          std::is_function<typename std::remove_pointer<T>::type>::value,
+      "T must be a function pointer type");
+  const auto proc_address = ::GetProcAddress(module, name);
+  return reinterpret_cast<T>(reinterpret_cast<void*>(proc_address));
+}
+
+std::wstring GetSystem32Dir() {
+  std::wstring result;
+  std::uint32_t len = std::max<std::uint32_t>(
+      static_cast<std::uint32_t>(std::min<size_t>(
+          result.capacity(), std::numeric_limits<std::uint32_t>::max())),
+      1);
+  do {
+    result.resize(len);
+    len = ::GetSystemDirectoryW(&result[0], len);
+  } while (len > result.size());
+  result.resize(len);
+  return result;
+}
+
+ucal_getTimeZoneIDForWindowsID_func LoadIcuGetTimeZoneIDForWindowsID() {
+  // This function is intended to be lock free to avoid potential deadlocks
+  // with loader-lock taken inside LoadLibraryW. As LoadLibraryW and
+  // GetProcAddress are idempotent unless the DLL is unloaded, we just need to
+  // make sure global variables are read/written atomically, where
+  // memory_order_relaxed is also acceptable.
+
+  if (g_unavailable.load(std::memory_order_relaxed)) {
+    return nullptr;
+  }
+
+  {
+    const auto ucal_getTimeZoneIDForWindowsIDRef =
+        g_ucal_getTimeZoneIDForWindowsID.load(std::memory_order_relaxed);
+    if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) {
+      return ucal_getTimeZoneIDForWindowsIDRef;
+    }
+  }
+
+  const std::wstring system32_dir = GetSystem32Dir();
+  if (system32_dir.empty()) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  // Here LoadLibraryExW(L"icu.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32) does
+  // not work if "icu.dll" is already loaded from somewhere other than the
+  // system32 directory. Specifying the full path with LoadLibraryW is more
+  // reliable.
+  const std::wstring icu_dll_path = system32_dir + L"\\icu.dll";
+  const HMODULE icu_dll = ::LoadLibraryW(icu_dll_path.c_str());
+  if (icu_dll == nullptr) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  const auto ucal_getTimeZoneIDForWindowsIDRef =
+      AsProcAddress<ucal_getTimeZoneIDForWindowsID_func>(
+          icu_dll, "ucal_getTimeZoneIDForWindowsID");
+  if (ucal_getTimeZoneIDForWindowsIDRef != nullptr) {
+    g_unavailable.store(true, std::memory_order_relaxed);
+    return nullptr;
+  }
+
+  g_ucal_getTimeZoneIDForWindowsID.store(ucal_getTimeZoneIDForWindowsIDRef,
+                                         std::memory_order_relaxed);
+
+  return ucal_getTimeZoneIDForWindowsIDRef;
+}
+
+// Convert wchar_t array (UTF-16) to UTF-8 string
+std::string Utf16ToUtf8(const wchar_t* ptr, size_t size) {
+  if (size > std::numeric_limits<int>::max()) {
+    return std::string();
+  }
+  const int chars_len = static_cast<int>(size);
+  std::string result;
+  std::int32_t len = std::max<std::int32_t>(
+      static_cast<std::int32_t>(std::min<size_t>(
+          result.capacity(), std::numeric_limits<std::int32_t>::max())),
+      1);
+  do {
+    result.resize(len);
+    // TODO: Switch to std::string::data() when we require C++17 or higher.
+    len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, ptr, chars_len,
+                                &result[0], len, nullptr, nullptr);
+  } while (len > result.size());
+  result.resize(len);
+  return result;
+}
+
+}  // namespace
+
+std::string GetWindowsLocalTimeZone() {
+  const auto getTimeZoneIDForWindowsID = LoadIcuGetTimeZoneIDForWindowsID();
+  if (getTimeZoneIDForWindowsID == nullptr) {
+    return std::string();
+  }
+
+  DYNAMIC_TIME_ZONE_INFORMATION info = {};
+  if (::GetDynamicTimeZoneInformation(&info) == TIME_ZONE_ID_INVALID) {
+    return std::string();
+  }
+
+  std::wstring result;
+  std::int32_t len = std::max<std::int32_t>(
+      static_cast<std::int32_t>(std::min<size_t>(
+          result.capacity(), std::numeric_limits<std::int32_t>::max())),
+      1);
+  for (;;) {
+    UErrorCode status = U_ZERO_ERROR;
+    result.resize(len);
+    len = getTimeZoneIDForWindowsID(info.TimeZoneKeyName, -1, nullptr,
+                                    &result[0], len, &status);
+    if (U_SUCCESS(status)) {
+      return Utf16ToUtf8(result.data(), len);
+    }
+    if (status != U_BUFFER_OVERFLOW_ERROR) {
+      return std::string();
+    }
+  }
+}
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
diff --git a/absl/time/internal/cctz/src/time_zone_name_win.h b/absl/time/internal/cctz/src/time_zone_name_win.h
new file mode 100644
index 0000000..f53b5a9
--- /dev/null
+++ b/absl/time/internal/cctz/src/time_zone_name_win.h
@@ -0,0 +1,37 @@
+// Copyright 2025 Google Inc. All Rights Reserved.
+//
+// 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_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
+#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
+
+#include <string>
+
+#include "absl/base/config.h"
+
+namespace absl {
+ABSL_NAMESPACE_BEGIN
+namespace time_internal {
+namespace cctz {
+
+// Returns the local time zone ID in IANA format (e.g. "America/Los_Angeles"),
+// or the empty string on failure. Not supported on Windows 10 1809 and earlier,
+// where "icu.dll" is not available in the System32 directory.
+std::string GetWindowsLocalTimeZone();
+
+}  // namespace cctz
+}  // namespace time_internal
+ABSL_NAMESPACE_END
+}  // namespace absl
+
+#endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_NAME_WIN_H_
diff --git a/absl/types/span.h b/absl/types/span.h
index d2cf627..556c846 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -47,6 +47,9 @@
 //    * `absl::Span` has no static extent template parameter, nor constructors
 //      which exist only because of the static extent parameter.
 //    * `absl::Span` has an explicit mutable-reference constructor
+//    * `absl::Span::subspan(pos, len)` always truncates `len` to
+//      `size() - pos`, whereas `std::span::subspan()` only truncates when the
+//      `len` parameter is defaulted.
 //
 // For more information, see the class comments below.
 #ifndef ABSL_TYPES_SPAN_H_
@@ -449,6 +452,11 @@
   // will be trimmed to at most size() - `pos`. A default `len` value of `npos`
   // ensures the returned subspan continues until the end of the span.
   //
+  // Note that trimming behavior differs from `std::span::subspan()`.
+  // `std::span::subspan()` requires `len == npos || pos + len <= size()`.
+  // In other words, `std::span::subspan()` only trims `len` when its value is
+  // defaulted.
+  //
   // Examples:
   //
   //   std::vector<int> vec = {10, 11, 12, 13};
diff --git a/ci/cmake_common.sh b/ci/cmake_common.sh
index 484230c..53d3a37 100644
--- a/ci/cmake_common.sh
+++ b/ci/cmake_common.sh
@@ -16,4 +16,4 @@
 # Keep this in sync with the commit in the MODULE.bazel file.
 readonly ABSL_GOOGLETEST_VERSION="1.17.0"
 
-readonly ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+ABSL_GOOGLETEST_DOWNLOAD_URL="https://github.com/google/googletest/releases/download/v${ABSL_GOOGLETEST_VERSION}/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
diff --git a/ci/cmake_install_test.sh b/ci/cmake_install_test.sh
index 871490f..5e3e07b 100755
--- a/ci/cmake_install_test.sh
+++ b/ci/cmake_install_test.sh
@@ -26,6 +26,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
 readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
 
diff --git a/ci/linux_clang-latest_libcxx_asan_bazel.sh b/ci/linux_clang-latest_libcxx_asan_bazel.sh
index cfc5510..cea10ff 100755
--- a/ci/linux_clang-latest_libcxx_asan_bazel.sh
+++ b/ci/linux_clang-latest_libcxx_asan_bazel.sh
@@ -81,6 +81,7 @@
           --action_env=\"CPLUS_INCLUDE_PATH=/opt/llvm/libcxx/include/c++/v1\" \
           --compilation_mode=\"${compilation_mode}\" \
           --copt=\"${exceptions_mode}\" \
+          --copt=\"-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG\" \
           --copt=\"-DGTEST_REMOVE_LEGACY_TEST_CASEAPI_=1\" \
           --copt=\"-fsanitize=address\" \
           --copt=\"-fsanitize=${UBSAN_CHECKS}\" \
diff --git a/ci/linux_gcc-latest_libstdcxx_cmake.sh b/ci/linux_gcc-latest_libstdcxx_cmake.sh
index d75209b..2f69bba 100755
--- a/ci/linux_gcc-latest_libstdcxx_cmake.sh
+++ b/ci/linux_gcc-latest_libstdcxx_cmake.sh
@@ -22,6 +22,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="17 20"
 fi
diff --git a/ci/linux_gcc_alpine_cmake.sh b/ci/linux_gcc_alpine_cmake.sh
index 7cf25f7..1d64a95 100755
--- a/ci/linux_gcc_alpine_cmake.sh
+++ b/ci/linux_gcc_alpine_cmake.sh
@@ -22,6 +22,12 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="file:///distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+  DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
+fi
+
 if [[ -z ${ABSL_CMAKE_CXX_STANDARDS:-} ]]; then
   ABSL_CMAKE_CXX_STANDARDS="17"
 fi
diff --git a/ci/macos_xcode_cmake.sh b/ci/macos_xcode_cmake.sh
index 5b11b89..37be939 100755
--- a/ci/macos_xcode_cmake.sh
+++ b/ci/macos_xcode_cmake.sh
@@ -31,6 +31,11 @@
 
 source "${ABSEIL_ROOT}/ci/cmake_common.sh"
 
+# Avoid depending on GitHub by looking for a cached copy of GoogleTest.
+if [[ -r "${KOKORO_GFILE_DIR:-}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz" ]]; then
+  ABSL_GOOGLETEST_DOWNLOAD_URL="${KOKORO_GFILE_DIR}/distdir/googletest-${ABSL_GOOGLETEST_VERSION}.tar.gz"
+fi
+
 if [[ -z ${ABSL_CMAKE_BUILD_TYPES:-} ]]; then
   ABSL_CMAKE_BUILD_TYPES="Debug"
 fi
diff --git a/ci/windows_msvc_cmake.bat b/ci/windows_msvc_cmake.bat
index 62cdb70..c0083a1 100755
--- a/ci/windows_msvc_cmake.bat
+++ b/ci/windows_msvc_cmake.bat
@@ -17,7 +17,12 @@
 :: The version of GoogleTest to be used in the CMake tests in this directory.
 :: Keep this in sync with the version in the WORKSPACE file.
 SET ABSL_GOOGLETEST_VERSION=1.17.0
-SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+
+IF EXIST %KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz (
+  SET ABSL_GOOGLETEST_DOWNLOAD_URL=file://%KOKORO_GFILE_DIR%\distdir\googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+) ELSE (
+  SET ABSL_GOOGLETEST_DOWNLOAD_URL=https://github.com/google/googletest/releases/download/v%ABSL_GOOGLETEST_VERSION%/googletest-%ABSL_GOOGLETEST_VERSION%.tar.gz
+)
 
 :: Replace '\' with '/' in Windows paths for CMake.
 :: Note that this cannot go inside the IF block above, because BAT files are weird.