diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp
index a66fbf645f5..375570cf196 100644
--- a/src/hotspot/share/classfile/verifier.cpp
+++ b/src/hotspot/share/classfile/verifier.cpp
@@ -32,6 +32,7 @@
 #include "classfile/stackMapTableFormat.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
+#include "classfile/systemDictionaryShared.hpp"
 #include "classfile/verifier.hpp"
 #include "classfile/vmClasses.hpp"
 #include "classfile/vmSymbols.hpp"
@@ -212,6 +213,11 @@ bool Verifier::verify(InstanceKlass* klass, bool should_verify_class, TRAPS) {
          exception_name == vmSymbols::java_lang_ClassFormatError())) {
       log_info(verification)("Fail over class verification to old verifier for: %s", klass->external_name());
       log_info(class, init)("Fail over class verification to old verifier for: %s", klass->external_name());
+      // Exclude any classes that fail over during dynamic dumping
+      if (CDSConfig::is_dumping_dynamic_archive()) {
+        SystemDictionaryShared::warn_excluded(klass, "Failed over class verification while dynamic dumping");
+        SystemDictionaryShared::set_excluded(klass);
+      }
       message_buffer = NEW_RESOURCE_ARRAY(char, message_buffer_len);
       exception_message = message_buffer;
       exception_name = inference_verify(
diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp
index 6cb50b3dee2..c0e929ca1f4 100644
--- a/src/hotspot/share/opto/loopnode.cpp
+++ b/src/hotspot/share/opto/loopnode.cpp
@@ -2601,7 +2601,7 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) {
 
   const TypeInt* init_t  = phase->type(in(Init) )->is_int();
   const TypeInt* limit_t = phase->type(in(Limit))->is_int();
-  int stride_p;
+  jlong stride_p;
   jlong lim, ini;
   julong max;
   if (stride_con > 0) {
@@ -2610,10 +2610,10 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) {
     ini = init_t->_lo;
     max = (julong)max_jint;
   } else {
-    stride_p = -stride_con;
+    stride_p = -(jlong)stride_con;
     lim = init_t->_hi;
     ini = limit_t->_lo;
-    max = (julong)min_jint;
+    max = (julong)(juint)min_jint; // double cast to get 0x0000000080000000, not 0xffffffff80000000
   }
   julong range = lim - ini + stride_p;
   if (range <= max) {
diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp
index 8d2d3868fe6..fc4eaccff5c 100644
--- a/src/hotspot/share/opto/vectorization.cpp
+++ b/src/hotspot/share/opto/vectorization.cpp
@@ -416,6 +416,10 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop,
 #ifdef ASSERT
   _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr),
 #endif
+  _has_int_index_after_convI2L(false),
+  _int_index_after_convI2L_offset(0),
+  _int_index_after_convI2L_invar(nullptr),
+  _int_index_after_convI2L_scale(0),
   _nstack(nstack), _analyze_only(analyze_only), _stack_idx(0)
 #ifndef PRODUCT
   , _tracer(vloop.is_trace_pointer_analysis())
@@ -495,6 +499,11 @@ VPointer::VPointer(MemNode* const mem, const VLoop& vloop,
     return;
   }
 
+  if (!is_safe_to_use_as_simple_form(base, adr)) {
+    assert(!valid(), "does not have simple form");
+    return;
+  }
+
   _base = base;
   _adr  = adr;
   assert(valid(), "Usable");
@@ -508,6 +517,10 @@ VPointer::VPointer(VPointer* p) :
 #ifdef ASSERT
   _debug_invar(nullptr), _debug_negate_invar(false), _debug_invar_scale(nullptr),
 #endif
+  _has_int_index_after_convI2L(false),
+  _int_index_after_convI2L_offset(0),
+  _int_index_after_convI2L_invar(nullptr),
+  _int_index_after_convI2L_scale(0),
   _nstack(p->_nstack), _analyze_only(p->_analyze_only), _stack_idx(p->_stack_idx)
 #ifndef PRODUCT
   , _tracer(p->_tracer._is_trace_alignment)
@@ -530,6 +543,354 @@ int VPointer::invar_factor() const {
   return 1;
 }
 
+// We would like to make decisions about aliasing (i.e. removing memory edges) and adjacency
+// (i.e. which loads/stores can be packed) based on the simple form:
+//
+//   s_pointer = adr + offset + invar + scale * ConvI2L(iv)
+//
+// However, we parse the compound-long-int form:
+//
+//   c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index)
+//   int_index =       int_offset  + int_invar  + int_scale  * iv
+//
+// In general, the simple and the compound-long-int form do not always compute the same pointer
+// at runtime. For example, the simple form would give a different result due to an overflow
+// in the int_index.
+//
+// Example:
+//   For both forms, we have:
+//     iv = 0
+//     scale = 1
+//
+//   We now account the offset and invar once to the long part and once to the int part:
+//     Pointer 1 (long offset and long invar):
+//       long_offset = min_int
+//       long_invar  = min_int
+//       int_offset  = 0
+//       int_invar   = 0
+//
+//     Pointer 2 (int offset and int invar):
+//       long_offset = 0
+//       long_invar  = 0
+//       int_offset  = min_int
+//       int_invar   = min_int
+//
+//   This gives us the following pointers:
+//     Compound-long-int form pointers:
+//       Form:
+//         c_pointer   = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + int_invar + int_scale * iv)
+//
+//       Pointers:
+//         c_pointer1  = adr + min_int     + min_int    + 1          * ConvI2L(0          + 0         + 1         * 0)
+//                     = adr + min_int + min_int
+//                     = adr - 2^32
+//
+//         c_pointer2  = adr + 0           + 0          + 1          * ConvI2L(min_int    + min_int   + 1         * 0)
+//                     = adr + ConvI2L(min_int + min_int)
+//                     = adr + 0
+//                     = adr
+//
+//     Simple form pointers:
+//       Form:
+//         s_pointer  = adr + offset                     + invar                     + scale                    * ConvI2L(iv)
+//         s_pointer  = adr + (long_offset + int_offset) + (long_invar  + int_invar) + (long_scale * int_scale) * ConvI2L(iv)
+//
+//       Pointers:
+//         s_pointer1 = adr + (min_int     + 0         ) + (min_int     + 0        ) + 1                        * 0
+//                    = adr + min_int + min_int
+//                    = adr - 2^32
+//         s_pointer2 = adr + (0           + min_int   ) + (0           + min_int  ) + 1                        * 0
+//                    = adr + min_int + min_int
+//                    = adr - 2^32
+//
+//   We see that the two addresses are actually 2^32 bytes apart (derived from the c_pointers), but their simple form look identical.
+//
+// Hence, we need to determine in which cases it is safe to make decisions based on the simple
+// form, rather than the compound-long-int form. If we cannot prove that using the simple form
+// is safe (i.e. equivalent to the compound-long-int form), then we do not get a valid VPointer,
+// and the associated memop cannot be vectorized.
+bool VPointer::is_safe_to_use_as_simple_form(Node* base, Node* adr) const {
+#ifndef _LP64
+  // On 32-bit platforms, there is never an explicit int_index with ConvI2L for the iv. Thus, the
+  // parsed pointer form is always the simple form, with int operations:
+  //
+  //   pointer = adr + offset + invar + scale * iv
+  //
+  assert(!_has_int_index_after_convI2L, "32-bit never has an int_index with ConvI2L for the iv");
+  return true;
+#else
+
+  // Array accesses that are not Unsafe always have a RangeCheck which ensures that there is no
+  // int_index overflow. This implies that the conversion to long can be done separately:
+  //
+  //   ConvI2L(int_index) = ConvI2L(int_offset) + ConvI2L(int_invar) + ConvI2L(scale) * ConvI2L(iv)
+  //
+  // And hence, the simple form is guaranteed to be identical to the compound-long-int form at
+  // runtime and the VPointer is safe/valid to be used.
+  const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr();
+  if (ary_ptr_t != nullptr) {
+    if (!_mem->is_unsafe_access()) {
+      return true;
+    }
+  }
+
+  // We did not find the int_index. Just to be safe, reject this VPointer.
+  if (!_has_int_index_after_convI2L) {
+    return false;
+  }
+
+  int int_offset  = _int_index_after_convI2L_offset;
+  Node* int_invar = _int_index_after_convI2L_invar;
+  int int_scale   = _int_index_after_convI2L_scale;
+  int long_scale  = _scale / int_scale;
+
+  // If "int_index = iv", then the simple form is identical to the compound-long-int form.
+  //
+  //   int_index = int_offset + int_invar + int_scale * iv
+  //             = 0            0           1         * iv
+  //             =                                      iv
+  if (int_offset == 0 && int_invar == nullptr && int_scale == 1) {
+    return true;
+  }
+
+  // Intuition: What happens if the int_index overflows? Let us look at two pointers on the "overflow edge":
+  //
+  //              pointer1 = adr + ConvI2L(int_index1)
+  //              pointer2 = adr + ConvI2L(int_index2)
+  //
+  //              int_index1 = max_int + 0 = max_int  -> very close to but before the overflow
+  //              int_index2 = max_int + 1 = min_int  -> just enough to get the overflow
+  //
+  //            When looking at the difference of pointer1 and pointer2, we notice that it is very large
+  //            (almost 2^32). Since arrays have at most 2^31 elements, chances are high that pointer2 is
+  //            an actual out-of-bounds access at runtime. These would normally be prevented by range checks
+  //            at runtime. However, if the access was done by using Unsafe, where range checks are omitted,
+  //            then an out-of-bounds access constitutes undefined behavior. This means that we are allowed to
+  //            do anything, including changing the behavior.
+  //
+  //            If we can set the right conditions, we have a guarantee that an overflow is either impossible
+  //            (no overflow or range checks preventing that) or undefined behavior. In both cases, we are
+  //            safe to do a vectorization.
+  //
+  // Approach:  We want to prove a lower bound for the distance between these two pointers, and an
+  //            upper bound for the size of a memory object. We can derive such an upper bound for
+  //            arrays. We know they have at most 2^31 elements. If we know the size of the elements
+  //            in bytes, we have:
+  //
+  //              array_element_size_in_bytes * 2^31 >= max_possible_array_size_in_bytes
+  //                                                 >= array_size_in_bytes                      (ARR)
+  //
+  //            If some small difference "delta" leads to an int_index overflow, we know that the
+  //            int_index1 before overflow must have been close to max_int, and the int_index2 after
+  //            the overflow must be close to min_int:
+  //
+  //              pointer1 =        adr + long_offset + long_invar + long_scale * ConvI2L(int_index1)
+  //                       =approx  adr + long_offset + long_invar + long_scale * max_int
+  //
+  //              pointer2 =        adr + long_offset + long_invar + long_scale * ConvI2L(int_index2)
+  //                       =approx  adr + long_offset + long_invar + long_scale * min_int
+  //
+  //            We realize that the pointer difference is very large:
+  //
+  //              difference =approx  long_scale * 2^32
+  //
+  //            Hence, if we set the right condition for long_scale and array_element_size_in_bytes,
+  //            we can prove that an overflow is impossible (or would imply undefined behaviour).
+  //
+  // We must now take this intuition, and develop a rigorous proof. We start by stating the problem
+  // more precisely, with the help of some definitions and the Statement we are going to prove.
+  //
+  // Definition:
+  //   Two VPointers are "comparable" (i.e. VPointer::comparable is true, set with VPointer::cmp()),
+  //   iff all of these conditions apply for the simple form:
+  //     1) Both VPointers are valid.
+  //     2) The adr are identical, or both are array bases of different arrays.
+  //     3) They have identical scale.
+  //     4) They have identical invar.
+  //     5) The difference in offsets is limited: abs(offset1 - offset2) < 2^31.                 (DIFF)
+  //
+  // For the Vectorization Optimization, we pair-wise compare VPointers and determine if they are:
+  //   1) "not comparable":
+  //        We do not optimize them (assume they alias, not assume adjacency).
+  //
+  //        Whenever we chose this option based on the simple form, it is also correct based on the
+  //        compound-long-int form, since we make no optimizations based on it.
+  //
+  //   2) "comparable" with different array bases at runtime:
+  //        We assume they do not alias (remove memory edges), but not assume adjacency.
+  //
+  //        Whenever we have two different array bases for the simple form, we also have different
+  //        array bases for the compound-long-form. Since VPointers provably point to different
+  //        memory objects, they can never alias.
+  //
+  //   3) "comparable" with the same base address:
+  //        We compute the relative pointer difference, and based on the load/store size we can
+  //        compute aliasing and adjacency.
+  //
+  //        We must find a condition under which the pointer difference of the simple form is
+  //        identical to the pointer difference of the compound-long-form. We do this with the
+  //        Statement below, which we then proceed to prove.
+  //
+  // Statement:
+  //   If two VPointers satisfy these 3 conditions:
+  //     1) They are "comparable".
+  //     2) They have the same base address.
+  //     3) Their long_scale is a multiple of the array element size in bytes:
+  //
+  //          abs(long_scale) % array_element_size_in_bytes = 0                                     (A)
+  //
+  //   Then their pointer difference of the simple form is identical to the pointer difference
+  //   of the compound-long-int form.
+  //
+  //   More precisely:
+  //     Such two VPointers by definition have identical adr, invar, and scale.
+  //     Their simple form is:
+  //
+  //       s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv)                                 (B1)
+  //       s_pointer2 = adr + offset2 + invar + scale * ConvI2L(iv)                                 (B2)
+  //
+  //     Thus, the pointer difference of the simple forms collapses to the difference in offsets:
+  //
+  //       s_difference = s_pointer1 - s_pointer2 = offset1 - offset2                               (C)
+  //
+  //     Their compound-long-int form for these VPointer is:
+  //
+  //       c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1)        (D1)
+  //       int_index1 = int_offset1 + int_invar1 + int_scale1 * iv                                  (D2)
+  //
+  //       c_pointer2 = adr + long_offset2 + long_invar2 + long_scale2 * ConvI2L(int_index2)        (D3)
+  //       int_index2 = int_offset2 + int_invar2 + int_scale2 * iv                                  (D4)
+  //
+  //     And these are the offset1, offset2, invar and scale from the simple form (B1) and (B2):
+  //
+  //       offset1 = long_offset1 + long_scale1 * ConvI2L(int_offset1)                              (D5)
+  //       offset2 = long_offset2 + long_scale2 * ConvI2L(int_offset2)                              (D6)
+  //
+  //       invar   = long_invar1 + long_scale1 * ConvI2L(int_invar1)
+  //               = long_invar2 + long_scale2 * ConvI2L(int_invar2)                                (D7)
+  //
+  //       scale   = long_scale1 * ConvI2L(int_scale1)
+  //               = long_scale2 * ConvI2L(int_scale2)                                              (D8)
+  //
+  //     The pointer difference of the compound-long-int form is defined as:
+  //
+  //       c_difference = c_pointer1 - c_pointer2
+  //
+  //   Thus, the statement claims that for the two VPointer we have:
+  //
+  //     s_difference = c_difference                                                                (Statement)
+  //
+  // We prove the Statement with the help of a Lemma:
+  //
+  // Lemma:
+  //   There is some integer x, such that:
+  //
+  //     c_difference = s_difference + array_element_size_in_bytes * x * 2^32                       (Lemma)
+  //
+  // From condition (DIFF), we can derive:
+  //
+  //   abs(s_difference) < 2^31                                                                     (E)
+  //
+  // Assuming the Lemma, we prove the Statement:
+  //   If "x = 0" (intuitively: the int_index does not overflow), then:
+  //     c_difference = s_difference
+  //     and hence the simple form computes the same pointer difference as the compound-long-int form.
+  //   If "x != 0" (intuitively: the int_index overflows), then:
+  //     abs(c_difference) >= abs(s_difference + array_element_size_in_bytes * x * 2^32)
+  //                       >= array_element_size_in_bytes * 2^32 - abs(s_difference)
+  //                                                               --  apply (E)  --
+  //                       >  array_element_size_in_bytes * 2^32 - 2^31
+  //                       >= array_element_size_in_bytes * 2^31
+  //                              --  apply (ARR)  --
+  //                       >= max_possible_array_size_in_bytes
+  //                       >= array_size_in_bytes
+  //
+  //     This shows that c_pointer1 and c_pointer2 have a distance that exceeds the maximum array size.
+  //     Thus, at least one of the two pointers must be outside of the array bounds. But we can assume
+  //     that out-of-bounds accesses do not happen. If they still do, it is undefined behavior. Hence,
+  //     we are allowed to do anything. We can also "safely" use the simple form in this case even though
+  //     it might not match the compound-long-int form at runtime.
+  // QED Statement.
+  //
+  // We must now prove the Lemma.
+  //
+  // ConvI2L always truncates by some power of 2^32, i.e. there is some integer y such that:
+  //
+  //   ConvI2L(y1 + y2) = ConvI2L(y1) + ConvI2L(y2) + 2^32 * y                                  (F)
+  //
+  // It follows, that there is an integer y1 such that:
+  //
+  //   ConvI2L(int_index1) =  ConvI2L(int_offset1 + int_invar1 + int_scale1 * iv)
+  //                          -- apply (F) --
+  //                       =  ConvI2L(int_offset1)
+  //                        + ConvI2L(int_invar1)
+  //                        + ConvI2L(int_scale1) * ConvI2L(iv)
+  //                        + y1 * 2^32                                                         (G)
+  //
+  // Thus, we can write the compound-long-int form (D1) as:
+  //
+  //   c_pointer1 =   adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1)
+  //                  -- apply (G) --
+  //              =   adr
+  //                + long_offset1
+  //                + long_invar1
+  //                + long_scale1 * ConvI2L(int_offset1)
+  //                + long_scale1 * ConvI2L(int_invar1)
+  //                + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv)
+  //                + long_scale1 * y1 * 2^32                                                    (H)
+  //
+  // And we can write the simple form as:
+  //
+  //   s_pointer1 =   adr + offset1 + invar + scale * ConvI2L(iv)
+  //                  -- apply (D5, D7, D8) --
+  //              =   adr
+  //                + long_offset1
+  //                + long_scale1 * ConvI2L(int_offset1)
+  //                + long_invar1
+  //                + long_scale1 * ConvI2L(int_invar1)
+  //                + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv)                            (K)
+  //
+  // We now compute the pointer difference between the simple (K) and compound-long-int form (H).
+  // Most terms cancel out immediately:
+  //
+  //   sc_difference1 = c_pointer1 - s_pointer1 = long_scale1 * y1 * 2^32                        (L)
+  //
+  // Rearranging the equation (L), we get:
+  //
+  //   c_pointer1 = s_pointer1 + long_scale1 * y1 * 2^32                                         (M)
+  //
+  // And since long_scale1 is a multiple of array_element_size_in_bytes, there is some integer
+  // x1, such that (M) implies:
+  //
+  //   c_pointer1 = s_pointer1 + array_element_size_in_bytes * x1 * 2^32                         (N)
+  //
+  // With an analogue equation for c_pointer2, we can now compute the pointer difference for
+  // the compound-long-int form:
+  //
+  //   c_difference =  c_pointer1 - c_pointer2
+  //                   -- apply (N) --
+  //                =  s_pointer1 + array_element_size_in_bytes * x1 * 2^32
+  //                 -(s_pointer2 + array_element_size_in_bytes * x2 * 2^32)
+  //                   -- where "x = x1 - x2" --
+  //                =  s_pointer1 - s_pointer2 + array_element_size_in_bytes * x * 2^32
+  //                   -- apply (C) --
+  //                =  s_difference            + array_element_size_in_bytes * x * 2^32
+  // QED Lemma.
+  if (ary_ptr_t != nullptr) {
+    BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type();
+    if (is_java_primitive(array_element_bt)) {
+      int array_element_size_in_bytes = type2aelembytes(array_element_bt);
+      if (abs(long_scale) % array_element_size_in_bytes == 0) {
+        return true;
+      }
+    }
+  }
+
+  // General case: we do not know if it is safe to use the simple form.
+  return false;
+#endif
+}
+
 bool VPointer::is_loop_member(Node* n) const {
   Node* n_c = phase()->get_ctrl(n);
   return lpt()->is_member(phase()->get_loop(n_c));
@@ -582,11 +943,40 @@ bool VPointer::scaled_iv_plus_offset(Node* n) {
     }
   } else if (opc == Op_SubI || opc == Op_SubL) {
     if (offset_plus_k(n->in(2), true) && scaled_iv_plus_offset(n->in(1))) {
+      // (offset1 + invar1 + scale * iv) - (offset2 + invar2)
+      // Subtraction handled via "negate" flag of "offset_plus_k".
       NOT_PRODUCT(_tracer.scaled_iv_plus_offset_6(n);)
       return true;
     }
-    if (offset_plus_k(n->in(1)) && scaled_iv_plus_offset(n->in(2))) {
-      _scale *= -1;
+    VPointer tmp(this);
+    if (offset_plus_k(n->in(1)) && tmp.scaled_iv_plus_offset(n->in(2))) {
+      // (offset1 + invar1) - (offset2 + invar2 + scale * iv)
+      // Subtraction handled explicitly below.
+      assert(_scale == 0, "shouldn't be set yet");
+      // _scale = -tmp._scale
+      if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) {
+        return false; // mul overflow.
+      }
+      // _offset -= tmp._offset
+      if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) {
+        return false; // sub overflow.
+      }
+      // _invar -= tmp._invar
+      if (tmp._invar != nullptr) {
+        maybe_add_to_invar(tmp._invar, true);
+#ifdef ASSERT
+        _debug_invar_scale = tmp._debug_invar_scale;
+        _debug_negate_invar = !tmp._debug_negate_invar;
+#endif
+      }
+
+      // Forward info about the int_index:
+      assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
+      _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L;
+      _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset;
+      _int_index_after_convI2L_invar  = tmp._int_index_after_convI2L_invar;
+      _int_index_after_convI2L_scale  = tmp._int_index_after_convI2L_scale;
+
       NOT_PRODUCT(_tracer.scaled_iv_plus_offset_7(n);)
       return true;
     }
@@ -628,10 +1018,52 @@ bool VPointer::scaled_iv(Node* n) {
     }
   } else if (opc == Op_LShiftI) {
     if (n->in(1) == iv() && n->in(2)->is_Con()) {
-      _scale = 1 << n->in(2)->get_int();
+      if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) {
+        return false; // shift overflow.
+      }
       NOT_PRODUCT(_tracer.scaled_iv_6(n, _scale);)
       return true;
     }
+  } else if (opc == Op_ConvI2L && !has_iv()) {
+    // So far we have not found the iv yet, and are about to enter a ConvI2L subgraph,
+    // which may be the int index (that might overflow) for the memory access, of the form:
+    //
+    //   int_index = int_offset + int_invar + int_scale * iv
+    //
+    // If we simply continue parsing with the current VPointer, then the int_offset and
+    // int_invar simply get added to the long offset and invar. But for the checks in
+    // VPointer::is_safe_to_use_as_simple_form() we need to have explicit access to the
+    // int_index. Thus, we must parse it explicitly here. For this, we use a temporary
+    // VPointer, to pattern match the int_index sub-expression of the address.
+
+    NOT_PRODUCT(Tracer::Depth dddd;)
+    VPointer tmp(this);
+    NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);)
+
+    if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) {
+      // We successfully matched an integer index, of the form:
+      //   int_index = int_offset + int_invar + int_scale * iv
+      // Forward scale.
+      assert(_scale == 0 && tmp._scale != 0, "iv only found just now");
+      _scale = tmp._scale;
+      // Accumulate offset.
+      if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) {
+        return false; // add overflow.
+      }
+      // Accumulate invar.
+      if (tmp._invar != nullptr) {
+        maybe_add_to_invar(tmp._invar, false);
+      }
+      // Set info about the int_index:
+      assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
+      _has_int_index_after_convI2L = true;
+      _int_index_after_convI2L_offset = tmp._offset;
+      _int_index_after_convI2L_invar  = tmp._invar;
+      _int_index_after_convI2L_scale  = tmp._scale;
+
+      NOT_PRODUCT(_tracer.scaled_iv_7(n);)
+      return true;
+    }
   } else if (opc == Op_ConvI2L || opc == Op_CastII) {
     if (scaled_iv_plus_offset(n->in(1))) {
       NOT_PRODUCT(_tracer.scaled_iv_7(n);)
@@ -647,9 +1079,20 @@ bool VPointer::scaled_iv(Node* n) {
       NOT_PRODUCT(_tracer.scaled_iv_8(n, &tmp);)
 
       if (tmp.scaled_iv_plus_offset(n->in(1))) {
-        int scale = n->in(2)->get_int();
-        _scale   = tmp._scale  << scale;
-        _offset += tmp._offset << scale;
+        int shift = n->in(2)->get_int();
+        // Accumulate scale.
+        if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) {
+          return false; // shift overflow.
+        }
+        // Accumulate offset.
+        int shifted_offset = 0;
+        if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) {
+          return false; // shift overflow.
+        }
+        if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) {
+          return false; // add overflow.
+        }
+        // Accumulate invar.
         if (tmp._invar != nullptr) {
           BasicType bt = tmp._invar->bottom_type()->basic_type();
           assert(bt == T_INT || bt == T_LONG, "");
@@ -658,6 +1101,14 @@ bool VPointer::scaled_iv(Node* n) {
           _debug_invar_scale = n->in(2);
 #endif
         }
+
+        // Forward info about the int_index:
+        assert(!_has_int_index_after_convI2L, "no previous int_index discovered");
+        _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L;
+        _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset;
+        _int_index_after_convI2L_invar  = tmp._int_index_after_convI2L_invar;
+        _int_index_after_convI2L_scale  = tmp._int_index_after_convI2L_scale;
+
         NOT_PRODUCT(_tracer.scaled_iv_9(n, _scale, _offset, _invar);)
         return true;
       }
@@ -675,7 +1126,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) {
 
   int opc = n->Opcode();
   if (opc == Op_ConI) {
-    _offset += negate ? -(n->get_int()) : n->get_int();
+    if (!try_AddSubI_no_overflow(_offset, n->get_int(), negate, _offset)) {
+      return false; // add/sub overflow.
+    }
     NOT_PRODUCT(_tracer.offset_plus_k_2(n, _offset);)
     return true;
   } else if (opc == Op_ConL) {
@@ -684,7 +1137,9 @@ bool VPointer::offset_plus_k(Node* n, bool negate) {
     if (t->higher_equal(TypeLong::INT)) {
       jlong loff = n->get_long();
       jint  off  = (jint)loff;
-      _offset += negate ? -off : loff;
+      if (!try_AddSubI_no_overflow(_offset, off, negate, _offset)) {
+        return false; // add/sub overflow.
+      }
       NOT_PRODUCT(_tracer.offset_plus_k_3(n, _offset);)
       return true;
     }
@@ -699,11 +1154,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) {
   if (opc == Op_AddI) {
     if (n->in(2)->is_Con() && invariant(n->in(1))) {
       maybe_add_to_invar(n->in(1), negate);
-      _offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int();
+      if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), negate, _offset)) {
+        return false; // add/sub overflow.
+      }
       NOT_PRODUCT(_tracer.offset_plus_k_6(n, _invar, negate, _offset);)
       return true;
     } else if (n->in(1)->is_Con() && invariant(n->in(2))) {
-      _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int();
+      if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) {
+        return false; // add/sub overflow.
+      }
       maybe_add_to_invar(n->in(2), negate);
       NOT_PRODUCT(_tracer.offset_plus_k_7(n, _invar, negate, _offset);)
       return true;
@@ -712,11 +1171,15 @@ bool VPointer::offset_plus_k(Node* n, bool negate) {
   if (opc == Op_SubI) {
     if (n->in(2)->is_Con() && invariant(n->in(1))) {
       maybe_add_to_invar(n->in(1), negate);
-      _offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int();
+      if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), !negate, _offset)) {
+        return false; // add/sub overflow.
+      }
       NOT_PRODUCT(_tracer.offset_plus_k_8(n, _invar, negate, _offset);)
       return true;
     } else if (n->in(1)->is_Con() && invariant(n->in(2))) {
-      _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int();
+      if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) {
+        return false; // add/sub overflow.
+      }
       maybe_add_to_invar(n->in(2), !negate);
       NOT_PRODUCT(_tracer.offset_plus_k_9(n, _invar, !negate, _offset);)
       return true;
@@ -806,6 +1269,57 @@ void VPointer::maybe_add_to_invar(Node* new_invar, bool negate) {
   _invar = register_if_new(add);
 }
 
+bool VPointer::try_AddI_no_overflow(int offset1, int offset2, int& result) {
+  jlong long_offset = java_add((jlong)(offset1), (jlong)(offset2));
+  jint  int_offset  = java_add(        offset1,          offset2);
+  if (long_offset != int_offset) {
+    return false;
+  }
+  result = int_offset;
+  return true;
+}
+
+bool VPointer::try_SubI_no_overflow(int offset1, int offset2, int& result) {
+  jlong long_offset = java_subtract((jlong)(offset1), (jlong)(offset2));
+  jint  int_offset  = java_subtract(        offset1,          offset2);
+  if (long_offset != int_offset) {
+    return false;
+  }
+  result = int_offset;
+  return true;
+}
+
+bool VPointer::try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result) {
+  if (is_sub) {
+    return try_SubI_no_overflow(offset1, offset2, result);
+  } else {
+    return try_AddI_no_overflow(offset1, offset2, result);
+  }
+}
+
+bool VPointer::try_LShiftI_no_overflow(int offset, int shift, int& result) {
+  if (shift < 0 || shift > 31) {
+    return false;
+  }
+  jlong long_offset = java_shift_left((jlong)(offset), shift);
+  jint  int_offset  = java_shift_left(        offset,  shift);
+  if (long_offset != int_offset) {
+    return false;
+  }
+  result = int_offset;
+  return true;
+}
+
+bool VPointer::try_MulI_no_overflow(int offset1, int offset2, int& result) {
+  jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2));
+  jint  int_offset  = java_multiply(        offset1,          offset2);
+  if (long_offset != int_offset) {
+    return false;
+  }
+  result = int_offset;
+  return true;
+}
+
 // We use two comparisons, because a subtraction could underflow.
 #define RETURN_CMP_VALUE_IF_NOT_EQUAL(a, b) \
   if (a < b) { return -1; }                 \
diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp
index 3984407c565..b084edd44b3 100644
--- a/src/hotspot/share/opto/vectorization.hpp
+++ b/src/hotspot/share/opto/vectorization.hpp
@@ -670,13 +670,51 @@ private:
 // A vectorization pointer (VPointer) has information about an address for
 // dependence checking and vector alignment. It's usually bound to a memory
 // operation in a counted loop for vectorizable analysis.
+//
+// We parse and represent pointers of the simple form:
+//
+//   pointer   = adr + offset + invar + scale * ConvI2L(iv)
+//
+// Where:
+//
+//   adr: the base address of an array (base = adr)
+//        OR
+//        some address to off-heap memory (base = TOP)
+//
+//   offset: a constant offset
+//   invar:  a runtime variable, which is invariant during the loop
+//   scale:  scaling factor
+//   iv:     loop induction variable
+//
+// But more precisely, we parse the composite-long-int form:
+//
+//   pointer   = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + inv_invar + int_scale * iv)
+//
+//   pointer   = adr + long_offset + long_invar + long_scale * ConvI2L(int_index)
+//   int_index =       int_offset  + int_invar  + int_scale  * iv
+//
+// However, for aliasing and adjacency checks (e.g. VPointer::cmp()) we always use the simple form to make
+// decisions. Hence, we must make sure to only create a "valid" VPointer if the optimisations based on the
+// simple form produce the same result as the compound-long-int form would. Intuitively, this depends on
+// if the int_index overflows, but the precise conditions are given in VPointer::is_safe_to_use_as_simple_form().
+//
+//   ConvI2L(int_index) = ConvI2L(int_offset  + int_invar  + int_scale  * iv)
+//                      = Convi2L(int_offset) + ConvI2L(int_invar) + ConvI2L(int_scale) * ConvI2L(iv)
+//
+//   scale  = long_scale * ConvI2L(int_scale)
+//   offset = long_offset + long_scale * ConvI2L(int_offset)
+//   invar  = long_invar  + long_scale * ConvI2L(int_invar)
+//
+//   pointer   = adr + offset + invar + scale * ConvI2L(iv)
+//
 class VPointer : public ArenaObj {
  protected:
   MemNode* const  _mem;      // My memory reference node
   const VLoop&    _vloop;
 
-  Node* _base;               // null if unsafe nonheap reference
-  Node* _adr;                // address pointer
+  // Components of the simple form:
+  Node* _base;               // Base address of an array OR null if some off-heap memory.
+  Node* _adr;                // Same as _base if an array pointer OR some off-heap memory pointer.
   int   _scale;              // multiplier for iv (in bytes), 0 if no loop iv
   int   _offset;             // constant offset (in bytes)
 
@@ -687,6 +725,13 @@ class VPointer : public ArenaObj {
   Node* _debug_invar_scale;  // multiplier for invariant
 #endif
 
+  // The int_index components of the compound-long-int form. Used to decide if it is safe to use the
+  // simple form rather than the compound-long-int form that was parsed.
+  bool  _has_int_index_after_convI2L;
+  int   _int_index_after_convI2L_offset;
+  Node* _int_index_after_convI2L_invar;
+  int   _int_index_after_convI2L_scale;
+
   Node_Stack* _nstack;       // stack used to record a vpointer trace of variants
   bool        _analyze_only; // Used in loop unrolling only for vpointer trace
   uint        _stack_idx;    // Used in loop unrolling only for vpointer trace
@@ -726,6 +771,8 @@ class VPointer : public ArenaObj {
   VPointer(VPointer* p);
   NONCOPYABLE(VPointer);
 
+  bool is_safe_to_use_as_simple_form(Node* base, Node* adr) const;
+
  public:
   bool valid()             const { return _adr != nullptr; }
   bool has_iv()            const { return _scale != 0; }
@@ -751,10 +798,43 @@ class VPointer : public ArenaObj {
     return _invar == q._invar;
   }
 
+  // We compute if and how two VPointers can alias at runtime, i.e. if the two addressed regions of memory can
+  // ever overlap. There are essentially 3 relevant return states:
+  //  - NotComparable:  Synonymous to "unknown aliasing".
+  //                    We have no information about how the two VPointers can alias. They could overlap, refer
+  //                    to another location in the same memory object, or point to a completely different object.
+  //                    -> Memory edge required. Aliasing unlikely but possible.
+  //
+  //  - Less / Greater: Synonymous to "never aliasing".
+  //                    The two VPointers may point into the same memory object, but be non-aliasing (i.e. we
+  //                    know both address regions inside the same memory object, but these regions are non-
+  //                    overlapping), or the VPointers point to entirely different objects.
+  //                    -> No memory edge required. Aliasing impossible.
+  //
+  //  - Equal:          Synonymous to "overlap, or point to different memory objects".
+  //                    The two VPointers either overlap on the same memory object, or point to two different
+  //                    memory objects.
+  //                    -> Memory edge required. Aliasing likely.
+  //
+  // In a future refactoring, we can simplify to two states:
+  //  - NeverAlias:     instead of Less / Greater
+  //  - MayAlias:       instead of Equal / NotComparable
+  //
+  // Two VPointer are "comparable" (Less / Greater / Equal), iff all of these conditions apply:
+  //   1) Both are valid, i.e. expressible in the compound-long-int or simple form.
+  //   2) The adr are identical, or both are array bases of different arrays.
+  //   3) They have identical scale.
+  //   4) They have identical invar.
+  //   5) The difference in offsets is limited: abs(offset0 - offset1) < 2^31.
   int cmp(const VPointer& q) const {
     if (valid() && q.valid() &&
         (_adr == q._adr || (_base == _adr && q._base == q._adr)) &&
         _scale == q._scale   && invar_equals(q)) {
+      jlong difference = abs(java_subtract((jlong)_offset, (jlong)q._offset));
+      jlong max_diff = (jlong)1 << 31;
+      if (difference >= max_diff) {
+        return NotComparable;
+      }
       bool overlap = q._offset <   _offset +   memory_size() &&
                        _offset < q._offset + q.memory_size();
       return overlap ? Equal : (_offset < q._offset ? Less : Greater);
@@ -859,6 +939,12 @@ class VPointer : public ArenaObj {
 
   void maybe_add_to_invar(Node* new_invar, bool negate);
 
+  static bool try_AddI_no_overflow(int offset1, int offset2, int& result);
+  static bool try_SubI_no_overflow(int offset1, int offset2, int& result);
+  static bool try_AddSubI_no_overflow(int offset1, int offset2, bool is_sub, int& result);
+  static bool try_LShiftI_no_overflow(int offset1, int offset2, int& result);
+  static bool try_MulI_no_overflow(int offset1, int offset2, int& result);
+
   Node* register_if_new(Node* n) const;
 };
 
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
index 0d5363e866a..fcdc3fbea49 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPrivateKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -56,6 +56,7 @@ final class DHPrivateKey implements PrivateKey,
     private final BigInteger x;
 
     // the key bytes, without the algorithm information
+    // cannot be final as it's re-assigned for deserialization
     private byte[] key;
 
     // the encoded key
@@ -70,6 +71,131 @@ final class DHPrivateKey implements PrivateKey,
     // the private-value length (optional)
     private final int l;
 
+    private static class DHComponents {
+        final BigInteger x;
+        final BigInteger p;
+        final BigInteger g;
+        final int l;
+        final byte[] key;
+
+        DHComponents(BigInteger x, BigInteger p, BigInteger g, int l,
+                byte[] key) {
+            this.x = x;
+            this.p = p;
+            this.g = g;
+            this.l = l;
+            this.key = key;
+        }
+    }
+
+    // parses the specified encoding into a DHComponents object
+    private static DHComponents decode(byte[] encodedKey)
+            throws IOException {
+        DerValue val = null;
+
+        try {
+            val = new DerValue(encodedKey);
+            if (val.tag != DerValue.tag_Sequence) {
+                throw new IOException("Key not a SEQUENCE");
+            }
+
+            // version
+            BigInteger parsedVersion = val.data.getBigInteger();
+            if (!parsedVersion.equals(PKCS8_VERSION)) {
+                throw new IOException("version mismatch: (supported: " +
+                        PKCS8_VERSION + ", parsed: " + parsedVersion);
+            }
+
+            // privateKeyAlgorithm
+            DerValue algid = val.data.getDerValue();
+            if (algid.tag != DerValue.tag_Sequence) {
+                throw new IOException("AlgId is not a SEQUENCE");
+            }
+            DerInputStream derInStream = algid.toDerInputStream();
+            ObjectIdentifier oid = derInStream.getOID();
+            if (oid == null) {
+                throw new IOException("Null OID");
+            }
+            if (derInStream.available() == 0) {
+                throw new IOException("Parameters missing");
+            }
+            // parse the parameters
+            DerValue params = derInStream.getDerValue();
+            if (params.tag == DerValue.tag_Null) {
+                throw new IOException("Null parameters");
+            }
+            if (params.tag != DerValue.tag_Sequence) {
+                throw new IOException("Parameters not a SEQUENCE");
+            }
+            params.data.reset();
+            BigInteger p = params.data.getBigInteger();
+            BigInteger g = params.data.getBigInteger();
+            // Private-value length is OPTIONAL
+            int l = (params.data.available() != 0 ?
+                    params.data.getInteger() : 0);
+            // should have no trailing data
+            if (params.data.available() != 0) {
+                throw new IOException("Extra parameter data");
+            }
+
+            // privateKey
+            byte[] key = val.data.getOctetString();
+            DerInputStream in = new DerInputStream(key);
+            BigInteger x = in.getBigInteger();
+
+            // should have no trailing data
+            if (val.data.available() != 0) {
+                throw new IOException("Excess trailing data");
+            }
+            return new DHComponents(x, p, g, l, key);
+        } catch (NumberFormatException e) {
+            throw new IOException("Error parsing key encoding", e);
+        } finally {
+            if (val != null) {
+                val.clear();
+            }
+        }
+    }
+
+    // Generates the ASN.1 encoding
+    private static byte[] encode(BigInteger p, BigInteger g, int l,
+            byte[] key) {
+        DerOutputStream tmp = new DerOutputStream();
+
+        // version
+        tmp.putInteger(PKCS8_VERSION);
+
+        // privateKeyAlgorithm
+        DerOutputStream algid = new DerOutputStream();
+
+        // store OID
+        algid.putOID(DHPublicKey.DH_OID);
+        // encode parameters
+        DerOutputStream params = new DerOutputStream();
+        params.putInteger(p);
+        params.putInteger(g);
+        if (l != 0) {
+            params.putInteger(l);
+        }
+        // wrap parameters into SEQUENCE
+        DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
+                params.toByteArray());
+        // store parameter SEQUENCE in algid
+        algid.putDerValue(paramSequence);
+        // wrap algid into SEQUENCE
+        tmp.write(DerValue.tag_Sequence, algid);
+
+        // privateKey
+        tmp.putOctetString(key);
+
+        // make it a SEQUENCE
+        DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
+        byte[] encoded = val.toByteArray();
+        val.clear();
+
+        return encoded;
+    }
+
     /**
      * Make a DH private key out of a private value <code>x</code>, a prime
      * modulus <code>p</code>, and a base generator <code>g</code>.
@@ -79,7 +205,7 @@ final class DHPrivateKey implements PrivateKey,
      * @param g the base generator
      */
     DHPrivateKey(BigInteger x, BigInteger p, BigInteger g)
-        throws InvalidKeyException {
+            throws InvalidKeyException {
         this(x, p, g, 0);
     }
 
@@ -98,12 +224,16 @@ final class DHPrivateKey implements PrivateKey,
         this.p = p;
         this.g = g;
         this.l = l;
+
         byte[] xbytes = x.toByteArray();
         DerValue val = new DerValue(DerValue.tag_Integer, xbytes);
-        this.key = val.toByteArray();
-        val.clear();
-        Arrays.fill(xbytes, (byte) 0);
-        encode();
+        try {
+            this.key = val.toByteArray();
+        } finally {
+            val.clear();
+            Arrays.fill(xbytes, (byte) 0);
+        }
+        this.encodedKey = encode(p, g, l, key);
     }
 
     /**
@@ -115,75 +245,18 @@ final class DHPrivateKey implements PrivateKey,
      * a Diffie-Hellman private key
      */
     DHPrivateKey(byte[] encodedKey) throws InvalidKeyException {
-        DerValue val = null;
+        this.encodedKey = encodedKey.clone();
+        DHComponents dc;
         try {
-            val = new DerValue(encodedKey);
-            if (val.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException ("Key not a SEQUENCE");
-            }
-
-            //
-            // version
-            //
-            BigInteger parsedVersion = val.data.getBigInteger();
-            if (!parsedVersion.equals(PKCS8_VERSION)) {
-                throw new IOException("version mismatch: (supported: " +
-                                      PKCS8_VERSION + ", parsed: " +
-                                      parsedVersion);
-            }
-
-            //
-            // privateKeyAlgorithm
-            //
-            DerValue algid = val.data.getDerValue();
-            if (algid.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException("AlgId is not a SEQUENCE");
-            }
-            DerInputStream derInStream = algid.toDerInputStream();
-            ObjectIdentifier oid = derInStream.getOID();
-            if (oid == null) {
-                throw new InvalidKeyException("Null OID");
-            }
-            if (derInStream.available() == 0) {
-                throw new InvalidKeyException("Parameters missing");
-            }
-            // parse the parameters
-            DerValue params = derInStream.getDerValue();
-            if (params.tag == DerValue.tag_Null) {
-                throw new InvalidKeyException("Null parameters");
-            }
-            if (params.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException("Parameters not a SEQUENCE");
-            }
-            params.data.reset();
-            this.p = params.data.getBigInteger();
-            this.g = params.data.getBigInteger();
-            // Private-value length is OPTIONAL
-            if (params.data.available() != 0) {
-                this.l = params.data.getInteger();
-            } else {
-                this.l = 0;
-            }
-            if (params.data.available() != 0) {
-                throw new InvalidKeyException("Extra parameter data");
-            }
-
-            //
-            // privateKey
-            //
-            this.key = val.data.getOctetString();
-
-            DerInputStream in = new DerInputStream(this.key);
-            this.x = in.getBigInteger();
-
-            this.encodedKey = encodedKey.clone();
-        } catch (IOException | NumberFormatException e) {
-            throw new InvalidKeyException("Error parsing key encoding", e);
-        } finally {
-            if (val != null) {
-                val.clear();
-            }
+            dc = decode(this.encodedKey);
+        } catch (IOException e) {
+            throw new InvalidKeyException("Invalid encoding", e);
         }
+        this.x = dc.x;
+        this.p = dc.p;
+        this.g = dc.g;
+        this.l = dc.l;
+        this.key = dc.key;
     }
 
     /**
@@ -204,55 +277,9 @@ final class DHPrivateKey implements PrivateKey,
      * Get the encoding of the key.
      */
     public synchronized byte[] getEncoded() {
-        encode();
         return encodedKey.clone();
     }
 
-    /**
-     * Generate the encodedKey field if it has not been calculated.
-     * Could generate null.
-     */
-    private void encode() {
-        if (this.encodedKey == null) {
-            DerOutputStream tmp = new DerOutputStream();
-
-            //
-            // version
-            //
-            tmp.putInteger(PKCS8_VERSION);
-
-            //
-            // privateKeyAlgorithm
-            //
-            DerOutputStream algid = new DerOutputStream();
-
-            // store OID
-            algid.putOID(DHPublicKey.DH_OID);
-            // encode parameters
-            DerOutputStream params = new DerOutputStream();
-            params.putInteger(this.p);
-            params.putInteger(this.g);
-            if (this.l != 0) {
-                params.putInteger(this.l);
-            }
-            // wrap parameters into SEQUENCE
-            DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
-                    params.toByteArray());
-            // store parameter SEQUENCE in algid
-            algid.putDerValue(paramSequence);
-            // wrap algid into SEQUENCE
-            tmp.write(DerValue.tag_Sequence, algid);
-
-            // privateKey
-            tmp.putOctetString(this.key);
-
-            // make it a SEQUENCE
-            DerValue val = DerValue.wrap(DerValue.tag_Sequence, tmp);
-            this.encodedKey = val.toByteArray();
-            val.clear();
-        }
-    }
-
     /**
      * Returns the private value, <code>x</code>.
      *
@@ -307,10 +334,7 @@ final class DHPrivateKey implements PrivateKey,
      */
     @java.io.Serial
     private Object writeReplace() throws java.io.ObjectStreamException {
-        encode();
-        return new KeyRep(KeyRep.Type.PRIVATE,
-                getAlgorithm(),
-                getFormat(),
+        return new KeyRep(KeyRep.Type.PRIVATE, getAlgorithm(), getFormat(),
                 encodedKey);
     }
 
@@ -330,11 +354,28 @@ final class DHPrivateKey implements PrivateKey,
         if ((key == null) || (key.length == 0)) {
             throw new InvalidObjectException("key not deserializable");
         }
-        this.key = key.clone();
         if ((encodedKey == null) || (encodedKey.length == 0)) {
             throw new InvalidObjectException(
                     "encoded key not deserializable");
         }
-        this.encodedKey = encodedKey.clone();
+        // check if the "encodedKey" value matches the deserialized fields
+        DHComponents c;
+        byte[] encodedKeyIntern = encodedKey.clone();
+        try {
+            c = decode(encodedKeyIntern);
+        } catch (IOException e) {
+            throw new InvalidObjectException("Invalid encoding", e);
+        }
+        if (!Arrays.equals(c.key, key) || !c.x.equals(x) || !c.p.equals(p)
+                || !c.g.equals(g) || c.l != l) {
+            throw new InvalidObjectException(
+                    "encoded key not matching internal fields");
+        }
+        // zero out external arrays
+        Arrays.fill(key, (byte)0x00);
+        Arrays.fill(encodedKey, (byte)0x00);
+        // use self-created internal copies
+        this.key = c.key;
+        this.encodedKey = encodedKeyIntern;
     }
 }
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
index 47727c432a6..c95b40482d5 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/DHPublicKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package com.sun.crypto.provider;
 
 import java.io.*;
+import java.util.Arrays;
 import java.util.Objects;
 import java.math.BigInteger;
 import java.security.KeyRep;
@@ -70,6 +71,116 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
     static final ObjectIdentifier DH_OID =
             ObjectIdentifier.of(KnownOIDs.DiffieHellman);
 
+    private static class DHComponents {
+        final BigInteger y;
+        final BigInteger p;
+        final BigInteger g;
+        final int l;
+        final byte[] key;
+
+        DHComponents(BigInteger y, BigInteger p, BigInteger g, int l,
+                byte[] key) {
+            this.y = y;
+            this.p = p;
+            this.g = g;
+            this.l = l;
+            this.key = key;
+        }
+    }
+
+    // parses the specified encoding into a DHComponents object
+    private static DHComponents decode(byte[] encodedKey)
+            throws IOException {
+        DerValue val = null;
+
+        try {
+            val = new DerValue(encodedKey);
+            if (val.tag != DerValue.tag_Sequence) {
+                throw new IOException("Invalid key format");
+            }
+
+            // algorithm identifier
+            DerValue algid = val.data.getDerValue();
+            if (algid.tag != DerValue.tag_Sequence) {
+                throw new IOException("AlgId is not a SEQUENCE");
+            }
+            DerInputStream derInStream = algid.toDerInputStream();
+            ObjectIdentifier oid = derInStream.getOID();
+            if (oid == null) {
+                throw new IOException("Null OID");
+            }
+            if (derInStream.available() == 0) {
+                throw new IOException("Parameters missing");
+            }
+
+            // parse the parameters
+            DerValue params = derInStream.getDerValue();
+            if (params.tag == DerValue.tag_Null) {
+                throw new IOException("Null parameters");
+            }
+            if (params.tag != DerValue.tag_Sequence) {
+                throw new IOException("Parameters not a SEQUENCE");
+            }
+            params.data.reset();
+
+            BigInteger p = params.data.getBigInteger();
+            BigInteger g = params.data.getBigInteger();
+            // Private-value length is OPTIONAL
+            int l = (params.data.available() != 0 ? params.data.getInteger() :
+                    0);
+            if (params.data.available() != 0) {
+                throw new IOException("Extra parameter data");
+            }
+
+            // publickey
+            byte[] key = val.data.getBitString();
+            DerInputStream in = new DerInputStream(key);
+            BigInteger y = in.getBigInteger();
+
+            if (val.data.available() != 0) {
+                throw new IOException("Excess key data");
+            }
+            return new DHComponents(y, p, g, l, key);
+        } catch (NumberFormatException e) {
+            throw new IOException("Error parsing key encoding", e);
+        }
+    }
+
+    // generates the ASN.1 encoding
+    private static byte[] encode(BigInteger p, BigInteger g, int l,
+            byte[] key) {
+        DerOutputStream algid = new DerOutputStream();
+
+        // store oid in algid
+        algid.putOID(DH_OID);
+
+        // encode parameters
+        DerOutputStream params = new DerOutputStream();
+        params.putInteger(p);
+        params.putInteger(g);
+        if (l != 0) {
+            params.putInteger(l);
+        }
+
+        // wrap parameters into SEQUENCE
+        DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
+                params.toByteArray());
+        // store parameter SEQUENCE in algid
+        algid.putDerValue(paramSequence);
+
+        // wrap algid into SEQUENCE, and store it in key encoding
+        DerOutputStream tmpDerKey = new DerOutputStream();
+        tmpDerKey.write(DerValue.tag_Sequence, algid);
+
+        // store key data
+        tmpDerKey.putBitString(key);
+
+        // wrap algid and key into SEQUENCE
+        DerOutputStream derKey = new DerOutputStream();
+        derKey.write(DerValue.tag_Sequence, tmpDerKey);
+        return derKey.toByteArray();
+    }
+
     /**
      * Make a DH public key out of a public value <code>y</code>, a prime
      * modulus <code>p</code>, and a base generator <code>g</code>.
@@ -102,7 +213,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
         this.l = l;
         this.key = new DerValue(DerValue.tag_Integer,
                 this.y.toByteArray()).toByteArray();
-        this.encodedKey = getEncoded();
+        this.encodedKey = encode(p, g, l, key);
     }
 
     /**
@@ -114,68 +225,19 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
      * a Diffie-Hellman public key
      */
     DHPublicKey(byte[] encodedKey) throws InvalidKeyException {
-        InputStream inStream = new ByteArrayInputStream(encodedKey);
+        this.encodedKey = encodedKey.clone();
+
+        DHComponents dc;
         try {
-            DerValue derKeyVal = new DerValue(inStream);
-            if (derKeyVal.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException ("Invalid key format");
-            }
-
-            /*
-             * Parse the algorithm identifier
-             */
-            DerValue algid = derKeyVal.data.getDerValue();
-            if (algid.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException("AlgId is not a SEQUENCE");
-            }
-            DerInputStream derInStream = algid.toDerInputStream();
-            ObjectIdentifier oid = derInStream.getOID();
-            if (oid == null) {
-                throw new InvalidKeyException("Null OID");
-            }
-            if (derInStream.available() == 0) {
-                throw new InvalidKeyException("Parameters missing");
-            }
-
-            /*
-             * Parse the parameters
-             */
-            DerValue params = derInStream.getDerValue();
-            if (params.tag == DerValue.tag_Null) {
-                throw new InvalidKeyException("Null parameters");
-            }
-            if (params.tag != DerValue.tag_Sequence) {
-                throw new InvalidKeyException("Parameters not a SEQUENCE");
-            }
-            params.data.reset();
-            this.p = params.data.getBigInteger();
-            this.g = params.data.getBigInteger();
-            // Private-value length is OPTIONAL
-            if (params.data.available() != 0) {
-                this.l = params.data.getInteger();
-            } else {
-                this.l = 0;
-            }
-            if (params.data.available() != 0) {
-                throw new InvalidKeyException("Extra parameter data");
-            }
-
-            /*
-             * Parse the key
-             */
-            this.key = derKeyVal.data.getBitString();
-
-            DerInputStream in = new DerInputStream(this.key);
-            this.y = in.getBigInteger();
-
-            if (derKeyVal.data.available() != 0) {
-                throw new InvalidKeyException("Excess key data");
-            }
-
-            this.encodedKey = encodedKey.clone();
-        } catch (IOException | NumberFormatException e) {
-            throw new InvalidKeyException("Error parsing key encoding", e);
+            dc = decode(this.encodedKey);
+        } catch (IOException e) {
+            throw new InvalidKeyException("Invalid encoding", e);
         }
+        this.y = dc.y;
+        this.p = dc.p;
+        this.g = dc.g;
+        this.l = dc.l;
+        this.key = dc.key;
     }
 
     /**
@@ -196,37 +258,6 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
      * Get the encoding of the key.
      */
     public synchronized byte[] getEncoded() {
-        if (this.encodedKey == null) {
-            DerOutputStream algid = new DerOutputStream();
-
-            // store oid in algid
-            algid.putOID(DH_OID);
-
-            // encode parameters
-            DerOutputStream params = new DerOutputStream();
-            params.putInteger(this.p);
-            params.putInteger(this.g);
-            if (this.l != 0) {
-                params.putInteger(this.l);
-            }
-            // wrap parameters into SEQUENCE
-            DerValue paramSequence = new DerValue(DerValue.tag_Sequence,
-                    params.toByteArray());
-            // store parameter SEQUENCE in algid
-            algid.putDerValue(paramSequence);
-
-            // wrap algid into SEQUENCE, and store it in key encoding
-            DerOutputStream tmpDerKey = new DerOutputStream();
-            tmpDerKey.write(DerValue.tag_Sequence, algid);
-
-            // store key data
-            tmpDerKey.putBitString(this.key);
-
-            // wrap algid and key into SEQUENCE
-            DerOutputStream derKey = new DerOutputStream();
-            derKey.write(DerValue.tag_Sequence, tmpDerKey);
-            this.encodedKey = derKey.toByteArray();
-        }
         return this.encodedKey.clone();
     }
 
@@ -263,8 +294,9 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
                                + Debug.toHexString(this.p)
                                + LINE_SEP + "g:" + LINE_SEP
                                + Debug.toHexString(this.g));
-        if (this.l != 0)
+        if (this.l != 0) {
             sb.append(LINE_SEP + "l:" + LINE_SEP + "    " + this.l);
+        }
         return sb.toString();
     }
 
@@ -304,7 +336,7 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
         return new KeyRep(KeyRep.Type.PUBLIC,
                         getAlgorithm(),
                         getFormat(),
-                        getEncoded());
+                        encodedKey);
     }
 
     /**
@@ -323,11 +355,28 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
         if ((key == null) || (key.length == 0)) {
             throw new InvalidObjectException("key not deserializable");
         }
-        this.key = key.clone();
         if ((encodedKey == null) || (encodedKey.length == 0)) {
             throw new InvalidObjectException(
                     "encoded key not deserializable");
         }
-        this.encodedKey = encodedKey.clone();
+        // check if the "encodedKey" value matches the deserialized fields
+        DHComponents c;
+        byte[] encodedKeyIntern = encodedKey.clone();
+        try {
+            c = decode(encodedKeyIntern);
+        } catch (IOException e) {
+            throw new InvalidObjectException("Invalid encoding", e);
+        }
+        if (!Arrays.equals(c.key, key) || !c.y.equals(y) || !c.p.equals(p)
+                || !c.g.equals(g) || c.l != l) {
+            throw new InvalidObjectException(
+                    "encoded key not matching internal fields");
+        }
+        // zero out external arrays
+        Arrays.fill(key, (byte)0x00);
+        Arrays.fill(encodedKey, (byte)0x00);
+        // use self-created internal copies
+        this.key = c.key;
+        this.encodedKey = encodedKeyIntern;
     }
 }
diff --git a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
index 14ada1699c1..2762fb3751c 100644
--- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
+++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -194,22 +194,24 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
             return key.clone();
         }
 
-       /**
-        * Restores the state of this object from the stream.
-        *
-        * @param  stream the {@code ObjectInputStream} from which data is read
-        * @throws IOException if an I/O error occurs
-        * @throws ClassNotFoundException if a serialized class cannot be loaded
-        */
-       @java.io.Serial
-       private void readObject(ObjectInputStream stream)
-               throws IOException, ClassNotFoundException {
-           stream.defaultReadObject();
-           if ((key == null) || (key.length == 0)) {
-               throw new InvalidObjectException("TlsMasterSecretKey is null");
-           }
-           key = key.clone();
-       }
-   }
+        /**
+         * Restores the state of this object from the stream.
+         *
+         * @param  stream the {@code ObjectInputStream} from which data is read
+         * @throws IOException if an I/O error occurs
+         * @throws ClassNotFoundException if a serialized class cannot be loaded
+         */
+        @java.io.Serial
+        private void readObject(ObjectInputStream stream)
+                throws IOException, ClassNotFoundException {
+            stream.defaultReadObject();
+            if (key == null || key.length == 0) {
+                throw new InvalidObjectException("TlsMasterSecretKey is null");
+            }
+            byte[] temp = key;
+            this.key = temp.clone();
+            Arrays.fill(temp, (byte)0);
+        }
+    }
 }
 
diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html
index a61844cca6e..a67df0c0d00 100644
--- a/src/java.base/share/classes/java/net/doc-files/net-properties.html
+++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html
@@ -253,6 +253,15 @@ to determine the proxy that should be used for connecting to a given URI.</P>
 	</OL>
 	<P>The channel binding tokens generated are of the type "tls-server-end-point" as defined in
            RFC 5929.</P>
+
+	<LI><P><B>{@systemProperty jdk.http.maxHeaderSize}</B> (default: 393216 or 384kB)<BR>
+	This is the maximum header field section size that a client is prepared to accept.
+	This is computed as the sum of the size of the uncompressed header name, plus
+	the size of the uncompressed header value, plus an overhead of 32 bytes for
+	each field section line. If a peer sends a field section that exceeds this
+	size a {@link java.net.ProtocolException ProtocolException} will be raised.
+	This applies to all versions of the HTTP protocol. A value of zero or a negative
+	value means no limit. If left unspecified, the default value is 393216 bytes.
 </UL>
 <P>All these properties are checked only once at startup.</P>
 <a id="AddressCache"></a>
diff --git a/src/java.base/share/classes/java/security/Permissions.java b/src/java.base/share/classes/java/security/Permissions.java
index 42c1adc9002..3bdeac6f929 100644
--- a/src/java.base/share/classes/java/security/Permissions.java
+++ b/src/java.base/share/classes/java/security/Permissions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -407,6 +407,11 @@ implements Serializable
         @SuppressWarnings("unchecked")
         Hashtable<Class<?>, PermissionCollection> perms =
             (Hashtable<Class<?>, PermissionCollection>)gfields.get("perms", null);
+
+        if (perms == null) {
+            throw new InvalidObjectException("perms can't be null");
+        }
+
         permsMap = new ConcurrentHashMap<>(perms.size()*2);
         permsMap.putAll(perms);
 
diff --git a/src/java.base/share/classes/java/security/SignedObject.java b/src/java.base/share/classes/java/security/SignedObject.java
index e2f9c764ec2..f65300fc808 100644
--- a/src/java.base/share/classes/java/security/SignedObject.java
+++ b/src/java.base/share/classes/java/security/SignedObject.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -152,20 +152,20 @@ public final class SignedObject implements Serializable {
      */
     public SignedObject(Serializable object, PrivateKey signingKey,
                         Signature signingEngine)
-        throws IOException, InvalidKeyException, SignatureException {
-            // creating a stream pipe-line, from a to b
-            ByteArrayOutputStream b = new ByteArrayOutputStream();
-            ObjectOutput a = new ObjectOutputStream(b);
+            throws IOException, InvalidKeyException, SignatureException {
+        // creating a stream pipe-line, from a to b
+        ByteArrayOutputStream b = new ByteArrayOutputStream();
+        ObjectOutput a = new ObjectOutputStream(b);
 
-            // write and flush the object content to byte array
-            a.writeObject(object);
-            a.flush();
-            a.close();
-            this.content = b.toByteArray();
-            b.close();
+        // write and flush the object content to byte array
+        a.writeObject(object);
+        a.flush();
+        a.close();
+        this.content = b.toByteArray();
+        b.close();
 
-            // now sign the encapsulated object
-            this.sign(signingKey, signingEngine);
+        // now sign the encapsulated object
+        this.sign(signingKey, signingEngine);
     }
 
     /**
@@ -245,12 +245,12 @@ public final class SignedObject implements Serializable {
      * @throws    SignatureException if signing fails.
      */
     private void sign(PrivateKey signingKey, Signature signingEngine)
-        throws InvalidKeyException, SignatureException {
-            // initialize the signing engine
-            signingEngine.initSign(signingKey);
-            signingEngine.update(this.content.clone());
-            this.signature = signingEngine.sign().clone();
-            this.thealgorithm = signingEngine.getAlgorithm();
+            throws InvalidKeyException, SignatureException {
+        // initialize the signing engine
+        signingEngine.initSign(signingKey);
+        signingEngine.update(this.content.clone());
+        this.signature = signingEngine.sign();
+        this.thealgorithm = signingEngine.getAlgorithm();
     }
 
     /**
@@ -263,10 +263,16 @@ public final class SignedObject implements Serializable {
      */
     @Serial
     private void readObject(ObjectInputStream s)
-        throws IOException, ClassNotFoundException {
-            ObjectInputStream.GetField fields = s.readFields();
-            content = ((byte[])fields.get("content", null)).clone();
-            signature = ((byte[])fields.get("signature", null)).clone();
-            thealgorithm = (String)fields.get("thealgorithm", null);
+            throws IOException, ClassNotFoundException {
+       ObjectInputStream.GetField fields = s.readFields();
+       byte[] c = (byte[]) fields.get("content", null);
+       byte[] sig = (byte[]) fields.get("signature", null);
+       String a = (String) fields.get("thealgorithm", null);
+       if (c == null || sig == null || a == null) {
+           throw new InvalidObjectException("One or more null fields");
+       }
+       content = c.clone();
+       signature = sig.clone();
+       thealgorithm = a;
     }
 }
diff --git a/src/java.base/share/classes/java/security/Timestamp.java b/src/java.base/share/classes/java/security/Timestamp.java
index 10a93a9b180..96df37a8c1f 100644
--- a/src/java.base/share/classes/java/security/Timestamp.java
+++ b/src/java.base/share/classes/java/security/Timestamp.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@ package java.security;
 
 import java.io.IOException;
 import java.io.ObjectInputStream;
+import java.io.InvalidObjectException;
 import java.io.Serializable;
 import java.security.cert.CertPath;
 import java.security.cert.Certificate;
@@ -78,7 +79,7 @@ public final class Timestamp implements Serializable {
      * {@code null}.
      */
     public Timestamp(Date timestamp, CertPath signerCertPath) {
-        if (timestamp == null || signerCertPath == null) {
+        if (isNull(timestamp, signerCertPath)) {
             throw new NullPointerException();
         }
         this.timestamp = new Date(timestamp.getTime()); // clone
@@ -166,9 +167,16 @@ public final class Timestamp implements Serializable {
      */
     @java.io.Serial
     private void readObject(ObjectInputStream ois)
-        throws IOException, ClassNotFoundException {
+            throws IOException, ClassNotFoundException {
         ois.defaultReadObject();
+        if (isNull(timestamp, signerCertPath)) {
+            throw new InvalidObjectException("Invalid null field(s)");
+        }
         myhash = -1;
         timestamp = new Date(timestamp.getTime());
     }
+
+    private static boolean isNull(Date d, CertPath c) {
+        return (d == null || c == null);
+    }
 }
diff --git a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
index a5f4de22d89..c0bdf5fc2a1 100644
--- a/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
+++ b/src/java.base/share/classes/java/security/UnresolvedPermissionCollection.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.ObjectStreamField;
+import java.io.InvalidObjectException;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
@@ -196,23 +197,32 @@ implements java.io.Serializable
         ObjectInputStream.GetField gfields = in.readFields();
 
         // Get permissions
-        @SuppressWarnings("unchecked")
         // writeObject writes a Hashtable<String, Vector<UnresolvedPermission>>
         // for the permissions key, so this cast is safe, unless the data is corrupt.
-        Hashtable<String, Vector<UnresolvedPermission>> permissions =
-                (Hashtable<String, Vector<UnresolvedPermission>>)
-                gfields.get("permissions", null);
-        perms = new ConcurrentHashMap<>(permissions.size()*2);
+        try {
+            @SuppressWarnings("unchecked")
+            Hashtable<String, Vector<UnresolvedPermission>> permissions =
+                    (Hashtable<String, Vector<UnresolvedPermission>>)
+                    gfields.get("permissions", null);
 
-        // Convert each entry (Vector) into a List
-        Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
-        for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
-            // Convert Vector into ArrayList
-            Vector<UnresolvedPermission> vec = e.getValue();
-            List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
+            if (permissions == null) {
+                throw new InvalidObjectException("Invalid null permissions");
+            }
 
-            // Add to Hashtable being serialized
-            perms.put(e.getKey(), list);
+            perms = new ConcurrentHashMap<>(permissions.size()*2);
+
+            // Convert each entry (Vector) into a List
+            Set<Map.Entry<String, Vector<UnresolvedPermission>>> set = permissions.entrySet();
+            for (Map.Entry<String, Vector<UnresolvedPermission>> e : set) {
+                // Convert Vector into ArrayList
+                Vector<UnresolvedPermission> vec = e.getValue();
+                List<UnresolvedPermission> list = new CopyOnWriteArrayList<>(vec);
+
+                // Add to Hashtable being serialized
+                perms.put(e.getKey(), list);
+            }
+        } catch (ClassCastException cce) {
+            throw new InvalidObjectException("Invalid type for permissions");
         }
     }
 }
diff --git a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
index 70083033fc6..6649dcda6cc 100644
--- a/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
+++ b/src/java.base/share/classes/java/security/cert/CertificateRevokedException.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@ package java.security.cert;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
@@ -70,6 +71,13 @@ public class CertificateRevokedException extends CertificateException {
 
     private transient Map<String, Extension> extensions;
 
+    private static boolean isNull(Date revocationDate,
+            CRLReason reason, X500Principal authority,
+            Map<String, Extension> extensions) {
+        return (revocationDate == null || reason == null || authority == null
+                || extensions == null);
+    }
+
     /**
      * Constructs a {@code CertificateRevokedException} with
      * the specified revocation date, reason code, authority name, and map
@@ -92,8 +100,7 @@ public class CertificateRevokedException extends CertificateException {
      */
     public CertificateRevokedException(Date revocationDate, CRLReason reason,
         X500Principal authority, Map<String, Extension> extensions) {
-        if (revocationDate == null || reason == null || authority == null ||
-            extensions == null) {
+        if (isNull(revocationDate, reason, authority, extensions)) {
             throw new NullPointerException();
         }
         this.revocationDate = new Date(revocationDate.getTime());
@@ -234,9 +241,6 @@ public class CertificateRevokedException extends CertificateException {
         // (revocationDate, reason, authority)
         ois.defaultReadObject();
 
-        // Defensively copy the revocation date
-        revocationDate = new Date(revocationDate.getTime());
-
         // Read in the size (number of mappings) of the extensions map
         // and create the extensions map
         int size = ois.readInt();
@@ -247,6 +251,13 @@ public class CertificateRevokedException extends CertificateException {
         } else {
             extensions = HashMap.newHashMap(Math.min(size, 20));
         }
+        // make sure all fields are set before checking
+        if (isNull(revocationDate, reason, authority, extensions)) {
+            throw new InvalidObjectException("Invalid null field(s)");
+        }
+
+        // Defensively copy the revocation date
+        revocationDate = new Date(revocationDate.getTime());
 
         // Read in the extensions and put the mappings in the extensions map
         for (int i = 0; i < size; i++) {
diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java
index 58872834567..83cc3ec4647 100644
--- a/src/java.base/share/classes/java/text/MessageFormat.java
+++ b/src/java.base/share/classes/java/text/MessageFormat.java
@@ -41,6 +41,7 @@ package java.text;
 import java.io.IOException;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
+import java.io.ObjectStreamException;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1181,6 +1182,8 @@ public class MessageFormat extends Format {
                 maximumArgumentNumber = argumentNumbers[i];
             }
         }
+
+        // Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX
         Object[] resultArray = new Object[maximumArgumentNumber + 1];
 
         int patternOffset = 0;
@@ -1459,6 +1462,9 @@ public class MessageFormat extends Format {
      * @serial
      */
     private int[] argumentNumbers = new int[INITIAL_FORMATS];
+    // Implementation limit for ArgumentIndex pattern element. Valid indices must
+    // be less than this value
+    private static final int MAX_ARGUMENT_INDEX = 10000;
 
     /**
      * One less than the number of entries in {@code offsets}.  Can also be thought of
@@ -1639,6 +1645,11 @@ public class MessageFormat extends Format {
                                                + argumentNumber);
         }
 
+        if (argumentNumber >= MAX_ARGUMENT_INDEX) {
+            throw new IllegalArgumentException(
+                    argumentNumber + " exceeds the ArgumentIndex implementation limit");
+        }
+
         // resize format information arrays if necessary
         if (offsetNumber >= formats.length) {
             int newLength = formats.length * 2;
@@ -2006,24 +2017,53 @@ public class MessageFormat extends Format {
      */
     @java.io.Serial
     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
-        in.defaultReadObject();
-        boolean isValid = maxOffset >= -1
-                && formats.length > maxOffset
-                && offsets.length > maxOffset
-                && argumentNumbers.length > maxOffset;
+        ObjectInputStream.GetField fields = in.readFields();
+        if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets")
+                || fields.defaulted("formats") || fields.defaulted("locale")
+                || fields.defaulted("pattern") || fields.defaulted("maxOffset")){
+            throw new InvalidObjectException("Stream has missing data");
+        }
+
+        locale = (Locale) fields.get("locale", null);
+        String patt = (String) fields.get("pattern", null);
+        int maxOff = fields.get("maxOffset", -2);
+        int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone();
+        int[] offs = ((int[]) fields.get("offsets", null)).clone();
+        Format[] fmts = ((Format[]) fields.get("formats", null)).clone();
+
+        // Check arrays/maxOffset have correct value/length
+        boolean isValid = maxOff >= -1 && argNums.length > maxOff
+                && offs.length > maxOff && fmts.length > maxOff;
+
+        // Check the correctness of arguments and offsets
         if (isValid) {
-            int lastOffset = pattern.length() + 1;
-            for (int i = maxOffset; i >= 0; --i) {
-                if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
+            int lastOffset = patt.length() + 1;
+            for (int i = maxOff; i >= 0; --i) {
+                if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX
+                        || offs[i] < 0 || offs[i] > lastOffset) {
                     isValid = false;
                     break;
                 } else {
-                    lastOffset = offsets[i];
+                    lastOffset = offs[i];
                 }
             }
         }
+
         if (!isValid) {
-            throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
+            throw new InvalidObjectException("Stream has invalid data");
         }
+        maxOffset = maxOff;
+        pattern = patt;
+        offsets = offs;
+        formats = fmts;
+        argumentNumbers = argNums;
+    }
+
+    /**
+     * Serialization without data not supported for this class.
+     */
+    @java.io.Serial
+    private void readObjectNoData() throws ObjectStreamException {
+        throw new InvalidObjectException("Deserialized MessageFormat objects need data");
     }
 }
diff --git a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
index e76a51e5d68..2ad9a7748f2 100644
--- a/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
+++ b/src/java.base/share/classes/javax/crypto/spec/SecretKeySpec.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -100,11 +100,9 @@ public class SecretKeySpec implements KeySpec, SecretKey {
      * is null or <code>key</code> is null or empty.
      */
     public SecretKeySpec(byte[] key, String algorithm) {
-        if (key == null || algorithm == null) {
-            throw new IllegalArgumentException("Missing argument");
-        }
-        if (key.length == 0) {
-            throw new IllegalArgumentException("Empty key");
+        String errMsg = doSanityCheck(key, algorithm);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
         }
         this.key = key.clone();
         this.algorithm = algorithm;
@@ -266,14 +264,22 @@ public class SecretKeySpec implements KeySpec, SecretKey {
     private void readObject(ObjectInputStream stream)
             throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
+        String errMsg = doSanityCheck(key, algorithm);
+        if (errMsg != null) {
+            throw new InvalidObjectException(errMsg);
+        }
+        byte[] temp = key;
+        this.key = temp.clone();
+        Arrays.fill(temp, (byte) 0);
+    }
 
+    private static String doSanityCheck(byte[] key, String algorithm) {
+        String errMsg = null;
         if (key == null || algorithm == null) {
-            throw new InvalidObjectException("Missing argument");
-        }
-
-        this.key = key.clone();
-        if (key.length == 0) {
-            throw new InvalidObjectException("Invalid key length");
+            errMsg = "Missing argument";
+        } else if (key.length == 0) {
+            errMsg = "Empty key";
         }
+        return errMsg;
     }
 }
diff --git a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
index c005b4ea02b..1c35491e4e2 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/ChoiceCallback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -102,20 +102,18 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
     public ChoiceCallback(String prompt, String[] choices,
                 int defaultChoice, boolean multipleSelectionsAllowed) {
 
-        if (prompt == null || prompt.isEmpty() ||
-            choices == null || choices.length == 0 ||
-            defaultChoice < 0 || defaultChoice >= choices.length)
-            throw new IllegalArgumentException();
-
+        choices = (choices == null || choices.length == 0 ? choices :
+                choices.clone());
+        String errMsg = doSanityCheck(prompt, choices, defaultChoice,
+                multipleSelectionsAllowed);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
+        }
         this.prompt = prompt;
         this.defaultChoice = defaultChoice;
         this.multipleSelectionsAllowed = multipleSelectionsAllowed;
 
-        this.choices = choices.clone();
-        for (int i = 0; i < choices.length; i++) {
-            if (choices[i] == null || choices[i].isEmpty())
-                throw new IllegalArgumentException();
-        }
+        this.choices = choices;
     }
 
     /**
@@ -183,9 +181,11 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
      * @see #getSelectedIndexes
      */
     public void setSelectedIndexes(int[] selections) {
-        if (!multipleSelectionsAllowed)
+        if (!multipleSelectionsAllowed) {
             throw new UnsupportedOperationException();
-        this.selections = selections == null ? null : selections.clone();
+        }
+        this.selections = ((selections == null || selections.length == 0) ?
+                selections : selections.clone());
     }
 
     /**
@@ -211,26 +211,35 @@ public class ChoiceCallback implements Callback, java.io.Serializable {
     private void readObject(ObjectInputStream stream)
             throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
+        choices = (choices == null || choices.length == 0 ?
+                choices :  choices.clone());
+        String errMsg = doSanityCheck(prompt, choices, defaultChoice,
+                multipleSelectionsAllowed);
+        if (errMsg != null) {
+            throw new InvalidObjectException(errMsg);
+        }
 
+        selections = (selections == null || selections.length == 0 ?
+                selections :  selections.clone());
+        if (selections != null && selections.length > 1 &&
+                !multipleSelectionsAllowed) {
+            throw new InvalidObjectException("Multiple selections not allowed");
+        }
+    }
+
+    private static String doSanityCheck(String prompt, String[] choices,
+            int defaultChoice, boolean allowMultiple) {
         if ((prompt == null) || prompt.isEmpty() ||
                 (choices == null) || (choices.length == 0) ||
                 (defaultChoice < 0) || (defaultChoice >= choices.length)) {
-            throw new InvalidObjectException(
-                    "Missing/invalid prompt/choices");
+            return "Missing/invalid prompt/choices";
         }
 
-        choices = choices.clone();
         for (int i = 0; i < choices.length; i++) {
-            if ((choices[i] == null) || choices[i].isEmpty())
-                throw new InvalidObjectException("Null/empty choices");
-        }
-
-        if (selections != null) {
-            selections = selections.clone();
-            if (!multipleSelectionsAllowed && (selections.length != 1)) {
-                throw new InvalidObjectException(
-                        "Multiple selections not allowed");
+            if ((choices[i] == null) || choices[i].isEmpty()) {
+                return "Null/empty choices value";
             }
         }
+        return null;
     }
 }
diff --git a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
index 437ce7041a7..a00fc7013ec 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/ConfirmationCallback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package javax.security.auth.callback;
 
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 
 /**
@@ -189,25 +190,10 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
      */
     public ConfirmationCallback(int messageType,
                 int optionType, int defaultOption) {
-
-        if (messageType < INFORMATION || messageType > ERROR ||
-            optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
-            throw new IllegalArgumentException();
-
-        switch (optionType) {
-        case YES_NO_OPTION:
-            if (defaultOption != YES && defaultOption != NO)
-                throw new IllegalArgumentException();
-            break;
-        case YES_NO_CANCEL_OPTION:
-            if (defaultOption != YES && defaultOption != NO &&
-                defaultOption != CANCEL)
-                throw new IllegalArgumentException();
-            break;
-        case OK_CANCEL_OPTION:
-            if (defaultOption != OK && defaultOption != CANCEL)
-                throw new IllegalArgumentException();
-            break;
+        String errMsg = doSanityCheck(messageType, optionType, false, null,
+                defaultOption, null, false);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
         }
 
         this.prompt = null;
@@ -250,21 +236,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
     public ConfirmationCallback(int messageType,
                 String[] options, int defaultOption) {
 
-        if (messageType < INFORMATION || messageType > ERROR ||
-            options == null || options.length == 0 ||
-            defaultOption < 0 || defaultOption >= options.length)
-            throw new IllegalArgumentException();
+        if (options != null) {
+            options = options.clone();
+        }
+        String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
+                options, defaultOption, null, false);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
+        }
 
         this.prompt = null;
         this.messageType = messageType;
         this.optionType = UNSPECIFIED_OPTION;
         this.defaultOption = defaultOption;
-
-        this.options = options.clone();
-        for (int i = 0; i < options.length; i++) {
-            if (options[i] == null || options[i].isEmpty())
-                throw new IllegalArgumentException();
-        }
+        this.options = options;
     }
 
     /**
@@ -304,27 +289,11 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
     public ConfirmationCallback(String prompt, int messageType,
                 int optionType, int defaultOption) {
 
-        if (prompt == null || prompt.isEmpty() ||
-            messageType < INFORMATION || messageType > ERROR ||
-            optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION)
-            throw new IllegalArgumentException();
-
-        switch (optionType) {
-        case YES_NO_OPTION:
-            if (defaultOption != YES && defaultOption != NO)
-                throw new IllegalArgumentException();
-            break;
-        case YES_NO_CANCEL_OPTION:
-            if (defaultOption != YES && defaultOption != NO &&
-                defaultOption != CANCEL)
-                throw new IllegalArgumentException();
-            break;
-        case OK_CANCEL_OPTION:
-            if (defaultOption != OK && defaultOption != CANCEL)
-                throw new IllegalArgumentException();
-            break;
+        String errMsg = doSanityCheck(messageType, optionType, false, null,
+                defaultOption, prompt, true);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
         }
-
         this.prompt = prompt;
         this.messageType = messageType;
         this.optionType = optionType;
@@ -369,22 +338,20 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
     public ConfirmationCallback(String prompt, int messageType,
                 String[] options, int defaultOption) {
 
-        if (prompt == null || prompt.isEmpty() ||
-            messageType < INFORMATION || messageType > ERROR ||
-            options == null || options.length == 0 ||
-            defaultOption < 0 || defaultOption >= options.length)
-            throw new IllegalArgumentException();
+        if (options != null) {
+            options = options.clone();
+        }
+        String errMsg = doSanityCheck(messageType, UNSPECIFIED_OPTION, true,
+                options, defaultOption, prompt, true);
+        if (errMsg != null) {
+            throw new IllegalArgumentException(errMsg);
+        }
 
         this.prompt = prompt;
         this.messageType = messageType;
         this.optionType = UNSPECIFIED_OPTION;
         this.defaultOption = defaultOption;
-
-        this.options = options.clone();
-        for (int i = 0; i < options.length; i++) {
-            if (options[i] == null || options[i].isEmpty())
-                throw new IllegalArgumentException();
-        }
+        this.options = options;
     }
 
     /**
@@ -491,6 +458,49 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
         return selection;
     }
 
+    private static String doSanityCheck(int msgType, int optionType,
+            boolean isUnspecifiedOption, String[] options, int defOption,
+            String prompt, boolean checkPrompt) {
+        // validate msgType
+        if (msgType < INFORMATION || msgType > ERROR) {
+            return "Invalid msgType";
+        }
+        // validate prompt if checkPrompt == true
+        if (checkPrompt && (prompt == null || prompt.isEmpty())) {
+            return "Invalid prompt";
+        }
+        // validate optionType
+        if (isUnspecifiedOption) {
+            if (optionType != UNSPECIFIED_OPTION) {
+                return "Invalid optionType";
+            }
+            // check options
+            if (options == null || options.length == 0 ||
+                    defOption < 0 || defOption >= options.length) {
+                return "Invalid options and/or default option";
+            }
+            for (String ov : options) {
+                if (ov == null || ov.isEmpty()) {
+                    return "Invalid option value";
+                }
+            }
+        } else {
+            if (optionType < YES_NO_OPTION || optionType > OK_CANCEL_OPTION) {
+                return "Invalid optionType";
+            }
+            // validate defOption based on optionType
+            if ((optionType == YES_NO_OPTION && (defOption != YES &&
+                    defOption != NO)) ||
+                    (optionType == YES_NO_CANCEL_OPTION && (defOption != YES &&
+                    defOption != NO && defOption != CANCEL)) ||
+                    (optionType == OK_CANCEL_OPTION && (defOption != OK &&
+                    defOption != CANCEL))) {
+                return "Invalid default option";
+            }
+        }
+        return null;
+    }
+
     /**
      * Restores the state of this object from the stream.
      *
@@ -502,8 +512,15 @@ public class ConfirmationCallback implements Callback, java.io.Serializable {
     private void readObject(ObjectInputStream stream)
             throws IOException, ClassNotFoundException {
         stream.defaultReadObject();
+
         if (options != null) {
             options = options.clone();
         }
+        String errMsg = doSanityCheck(messageType, optionType,
+                (optionType == UNSPECIFIED_OPTION), options, defaultOption,
+                prompt, false);
+        if (errMsg != null) {
+            throw new InvalidObjectException(errMsg);
+        }
     }
 }
diff --git a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
index bbe7ab882a6..2bee38ceaaa 100644
--- a/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
+++ b/src/java.base/share/classes/javax/security/auth/callback/PasswordCallback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -178,7 +178,9 @@ public class PasswordCallback implements Callback, java.io.Serializable {
         }
 
         if (inputPassword != null) {
-            inputPassword = inputPassword.clone();
+            char[] temp = inputPassword;
+            inputPassword = temp.clone();
+            Arrays.fill(temp, '0');
             cleanable = CleanerFactory.cleaner().register(
                     this, cleanerFor(inputPassword));
         }
diff --git a/src/java.base/share/classes/sun/net/www/MessageHeader.java b/src/java.base/share/classes/sun/net/www/MessageHeader.java
index 6af23e43ad2..5095507d968 100644
--- a/src/java.base/share/classes/sun/net/www/MessageHeader.java
+++ b/src/java.base/share/classes/sun/net/www/MessageHeader.java
@@ -30,6 +30,8 @@
 package sun.net.www;
 
 import java.io.*;
+import java.lang.reflect.Array;
+import java.net.ProtocolException;
 import java.util.Collections;
 import java.util.*;
 
@@ -45,11 +47,32 @@ public final class MessageHeader {
     private String[] values;
     private int nkeys;
 
+    // max number of bytes for headers, <=0 means unlimited;
+    // this corresponds to the length of the names, plus the length
+    // of the values, plus an overhead of 32 bytes per name: value
+    // pair.
+    // Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE
+    // see RFC 9113, section 6.5.2.
+    // https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE
+    private final int maxHeaderSize;
+
+    // Aggregate size of the field lines (name + value + 32) x N
+    // that have been parsed and accepted so far.
+    // This is defined as a long to force promotion to long
+    // and avoid overflows; see checkNewSize;
+    private long size;
+
     public MessageHeader () {
+       this(0);
+    }
+
+    public MessageHeader (int maxHeaderSize) {
+        this.maxHeaderSize = maxHeaderSize;
         grow();
     }
 
     public MessageHeader (InputStream is) throws java.io.IOException {
+        maxHeaderSize = 0;
         parseHeader(is);
     }
 
@@ -476,10 +499,28 @@ public final class MessageHeader {
     public void parseHeader(InputStream is) throws java.io.IOException {
         synchronized (this) {
             nkeys = 0;
+            size = 0;
         }
         mergeHeader(is);
     }
 
+    private void checkMaxHeaderSize(int sz) throws ProtocolException {
+        if (maxHeaderSize > 0) checkNewSize(size, sz, 0);
+    }
+
+    private long checkNewSize(long size, int name, int value) throws ProtocolException {
+        // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
+        long newSize = size + name + value + 32;
+        if (maxHeaderSize > 0 && newSize > maxHeaderSize) {
+            Arrays.fill(keys, 0, nkeys, null);
+            Arrays.fill(values,0, nkeys, null);
+            nkeys = 0;
+            throw new ProtocolException(String.format("Header size too big: %s > %s",
+                    newSize, maxHeaderSize));
+        }
+        return newSize;
+    }
+
     /** Parse and merge a MIME header from an input stream. */
     @SuppressWarnings("fallthrough")
     public void mergeHeader(InputStream is) throws java.io.IOException {
@@ -493,7 +534,15 @@ public final class MessageHeader {
             int c;
             boolean inKey = firstc > ' ';
             s[len++] = (char) firstc;
+            checkMaxHeaderSize(len);
     parseloop:{
+                // We start parsing for a new name value pair here.
+                // The max header size includes an overhead of 32 bytes per
+                // name value pair.
+                // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
+                long maxRemaining = maxHeaderSize > 0
+                        ? maxHeaderSize - size - 32
+                        : Long.MAX_VALUE;
                 while ((c = is.read()) >= 0) {
                     switch (c) {
                       case ':':
@@ -527,6 +576,9 @@ public final class MessageHeader {
                         s = ns;
                     }
                     s[len++] = (char) c;
+                    if (maxHeaderSize > 0 && len > maxRemaining) {
+                        checkMaxHeaderSize(len);
+                    }
                 }
                 firstc = -1;
             }
@@ -548,6 +600,9 @@ public final class MessageHeader {
                 v = new String();
             else
                 v = String.copyValueOf(s, keyend, len - keyend);
+            int klen = k == null ? 0 : k.length();
+
+            size = checkNewSize(size, klen, v.length());
             add(k, v);
         }
     }
diff --git a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index f47261f4491..83511853502 100644
--- a/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -172,6 +172,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
      */
     private static final int bufSize4ES;
 
+    private static final int maxHeaderSize;
+
     /*
      * Restrict setting of request headers through the public api
      * consistent with JavaScript XMLHttpRequest2 with a few
@@ -288,6 +290,19 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
         } else {
             restrictedHeaderSet = null;
         }
+
+        int defMaxHeaderSize = 384 * 1024;
+        String maxHeaderSizeStr = getNetProperty("jdk.http.maxHeaderSize");
+        int maxHeaderSizeVal = defMaxHeaderSize;
+        if (maxHeaderSizeStr != null) {
+            try {
+                maxHeaderSizeVal = Integer.parseInt(maxHeaderSizeStr);
+            } catch (NumberFormatException n) {
+                maxHeaderSizeVal = defMaxHeaderSize;
+            }
+        }
+        if (maxHeaderSizeVal < 0) maxHeaderSizeVal = 0;
+        maxHeaderSize = maxHeaderSizeVal;
     }
 
     static final String httpVersion = "HTTP/1.1";
@@ -754,7 +769,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
                 }
                 ps = (PrintStream) http.getOutputStream();
                 connected=true;
-                responses = new MessageHeader();
+                responses = new MessageHeader(maxHeaderSize);
                 setRequests=false;
                 writeRequests();
             }
@@ -912,7 +927,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
             throws IOException {
         super(checkURL(u));
         requests = new MessageHeader();
-        responses = new MessageHeader();
+        responses = new MessageHeader(maxHeaderSize);
         userHeaders = new MessageHeader();
         this.handler = handler;
         instProxy = p;
@@ -2810,7 +2825,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
         }
 
         // clear out old response headers!!!!
-        responses = new MessageHeader();
+        responses = new MessageHeader(maxHeaderSize);
         if (stat == HTTP_USE_PROXY) {
             /* This means we must re-request the resource through the
              * proxy denoted in the "Location:" field of the response.
@@ -3000,7 +3015,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
             } catch (IOException e) { }
         }
         responseCode = -1;
-        responses = new MessageHeader();
+        responses = new MessageHeader(maxHeaderSize);
         connected = false;
     }
 
diff --git a/src/java.base/share/classes/sun/security/provider/DRBG.java b/src/java.base/share/classes/sun/security/provider/DRBG.java
index 923c8c3aa54..01958285e43 100644
--- a/src/java.base/share/classes/sun/security/provider/DRBG.java
+++ b/src/java.base/share/classes/sun/security/provider/DRBG.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,6 +26,7 @@
 package sun.security.provider;
 
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.security.AccessController;
 import java.security.DrbgParameters;
 import java.security.PrivilegedAction;
@@ -272,11 +273,18 @@ public final class DRBG extends SecureRandomSpi {
         }
     }
 
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  s the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
     @java.io.Serial
     private void readObject(java.io.ObjectInputStream s)
             throws IOException, ClassNotFoundException {
         s.defaultReadObject();
-        if (mdp.mech == null) {
+        if (mdp == null || mdp.mech == null) {
             throw new IllegalArgumentException("Input data is corrupted");
         }
         createImpl();
diff --git a/src/java.base/share/classes/sun/security/ssl/ClientHello.java b/src/java.base/share/classes/sun/security/ssl/ClientHello.java
index babf2bb452d..e75076b11d6 100644
--- a/src/java.base/share/classes/sun/security/ssl/ClientHello.java
+++ b/src/java.base/share/classes/sun/security/ssl/ClientHello.java
@@ -213,8 +213,6 @@ final class ClientHello {
                 // ignore cookie
                 hos.putBytes16(getEncodedCipherSuites());
                 hos.putBytes8(compressionMethod);
-                extensions.send(hos);       // In TLS 1.3, use of certain
-                                            // extensions is mandatory.
             } catch (IOException ioe) {
                 // unlikely
             }
@@ -1426,6 +1424,9 @@ final class ClientHello {
             shc.handshakeProducers.put(SSLHandshake.SERVER_HELLO.id,
                     SSLHandshake.SERVER_HELLO);
 
+            // Reset the ClientHello non-zero offset fragment allowance
+            shc.acceptCliHelloFragments = false;
+
             //
             // produce
             //
diff --git a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java
index 337cf76f2c2..e0196f3009c 100644
--- a/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,12 +40,23 @@ import sun.security.ssl.SSLCipher.SSLReadCipher;
 final class DTLSInputRecord extends InputRecord implements DTLSRecord {
     private DTLSReassembler reassembler = null;
     private int             readEpoch;
+    private SSLContextImpl  sslContext;
 
     DTLSInputRecord(HandshakeHash handshakeHash) {
         super(handshakeHash, SSLReadCipher.nullDTlsReadCipher());
         this.readEpoch = 0;
     }
 
+    // Method to set TransportContext
+    public void setTransportContext(TransportContext tc) {
+        this.tc = tc;
+    }
+
+    // Method to set SSLContext
+    public void setSSLContext(SSLContextImpl sslContext) {
+        this.sslContext = sslContext;
+    }
+
     @Override
     void changeReadCiphers(SSLReadCipher readCipher) {
         this.readCipher = readCipher;
@@ -537,6 +548,27 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
         }
     }
 
+    /**
+     * Turn a sufficiently-large initial ClientHello fragment into one that
+     * stops immediately after the compression methods.  This is only used
+     * for the initial CH message fragment at offset 0.
+     *
+     * @param srcFrag the fragment actually received by the DTLSReassembler
+     * @param limit the size of the new, cloned/truncated handshake fragment
+     *
+     * @return a truncated handshake fragment that is sized to look like a
+     * complete message, but actually contains only up to the compression
+     * methods (no extensions)
+     */
+    private static HandshakeFragment truncateChFragment(HandshakeFragment srcFrag,
+            int limit) {
+        return new HandshakeFragment(Arrays.copyOf(srcFrag.fragment, limit),
+                srcFrag.contentType, srcFrag.majorVersion,
+                srcFrag.minorVersion, srcFrag.recordEnS, srcFrag.recordEpoch,
+                srcFrag.recordSeq, srcFrag.handshakeType, limit,
+                srcFrag.messageSeq, srcFrag.fragmentOffset, limit);
+    }
+
     private static final class HoleDescriptor {
         int offset;             // fragment_offset
         int limit;              // fragment_offset + fragment_length
@@ -640,10 +672,17 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
         // Queue up a handshake message.
         void queueUpHandshake(HandshakeFragment hsf) throws SSLProtocolException {
             if (!isDesirable(hsf)) {
-                // Not a dedired record, discard it.
+                // Not a desired record, discard it.
                 return;
             }
 
+            if (hsf.handshakeType == SSLHandshake.CLIENT_HELLO.id) {
+                // validate the first or subsequent ClientHello message
+                if ((hsf = valHello(hsf, hsf.messageSeq == 0)) == null) {
+                    return;
+                }
+            }
+
             // Clean up the retransmission messages if necessary.
             cleanUpRetransmit(hsf);
 
@@ -769,6 +808,100 @@ final class DTLSInputRecord extends InputRecord implements DTLSRecord {
             }
         }
 
+        private HandshakeFragment valHello(HandshakeFragment hsf,
+                boolean firstHello) {
+            ServerHandshakeContext shc =
+                    (ServerHandshakeContext) tc.handshakeContext;
+            // Drop any fragment that is not a zero offset until we've received
+            // a second (or possibly later) CH message that passes the cookie
+            // check.
+            if (shc == null || !shc.acceptCliHelloFragments) {
+                if (hsf.fragmentOffset != 0) {
+                    return null;
+                }
+            } else {
+                // Let this fragment through to the DTLSReassembler as-is
+                return hsf;
+            }
+
+            try {
+                ByteBuffer fragmentData = ByteBuffer.wrap(hsf.fragment);
+
+                ProtocolVersion pv = ProtocolVersion.valueOf(
+                        Record.getInt16(fragmentData));
+                if (!pv.isDTLS) {
+                    return null;
+                }
+                // Read the random (32 bytes)
+                if (fragmentData.remaining() < 32) {
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine("Rejected client hello fragment (bad random len) " +
+                                "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
+                    }
+                    return null;
+                }
+                fragmentData.position(fragmentData.position() + 32);
+
+                // SessionID
+                byte[] sessId = Record.getBytes8(fragmentData);
+                if (sessId.length > 0  &&
+                        !SSLConfiguration.enableDtlsResumeCookie) {
+                    // If we are in a resumption it is possible that the cookie
+                    // exchange will be skipped.  This is a server-side setting
+                    // and it is NOT the default.  If enableDtlsResumeCookie is
+                    // false though, then we will buffer fragments since there
+                    // is no cookie exchange to execute prior to performing
+                    // reassembly.
+                    return hsf;
+                }
+
+                // Cookie
+                byte[] cookie = Record.getBytes8(fragmentData);
+                if (firstHello && cookie.length != 0) {
+                    if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                        SSLLogger.fine("Rejected initial client hello fragment (bad cookie len) " +
+                                "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
+                    }
+                    return null;
+                }
+                // CipherSuites
+                Record.getBytes16(fragmentData);
+                // Compression methods
+                Record.getBytes8(fragmentData);
+
+                // If it's the first fragment, we'll truncate it and push it
+                // through the reassembler.
+                if (firstHello) {
+                    return truncateChFragment(hsf, fragmentData.position());
+                } else {
+                    HelloCookieManager hcMgr = sslContext.
+                            getHelloCookieManager(ProtocolVersion.DTLS10);
+                    ByteBuffer msgFragBuf = ByteBuffer.wrap(hsf.fragment, 0,
+                            fragmentData.position());
+                    ClientHello.ClientHelloMessage chMsg =
+                            new ClientHello.ClientHelloMessage(shc, msgFragBuf, null);
+                    if (!hcMgr.isCookieValid(shc, chMsg, cookie)) {
+                        // Bad cookie check, truncate it and let the ClientHello
+                        // consumer recheck, fail and take the appropriate action.
+                        return truncateChFragment(hsf, fragmentData.position());
+                    } else {
+                        // It's a good cookie, return the original handshake
+                        // fragment and let it go into the DTLSReassembler like
+                        // any other fragment so we can wait for the rest of
+                        // the CH message.
+                        shc.acceptCliHelloFragments = true;
+                        return hsf;
+                    }
+                }
+            } catch (IOException ioe) {
+                if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+                    SSLLogger.fine("Rejected client hello fragment " +
+                            "fo=" + hsf.fragmentOffset + " fl=" + hsf.fragmentLength);
+                }
+                return null;
+            }
+        }
+
         // Queue up a ChangeCipherSpec message
         void queueUpChangeCipherSpec(RecordFragment rf)
                 throws SSLProtocolException {
diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java
index 829fa2af96c..11b625e5791 100644
--- a/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/ServerHandshakeContext.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -55,6 +55,7 @@ class ServerHandshakeContext extends HandshakeContext {
     CertificateMessage.CertificateEntry currentCertEntry;
     private static final long DEFAULT_STATUS_RESP_DELAY = 5000L;
     final long statusRespTimeout;
+    boolean acceptCliHelloFragments = false;
 
 
     ServerHandshakeContext(SSLContextImpl sslContext,
diff --git a/src/java.base/share/classes/sun/security/ssl/TransportContext.java b/src/java.base/share/classes/sun/security/ssl/TransportContext.java
index c235da3068c..f65a08dfcfe 100644
--- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -156,6 +156,11 @@ final class TransportContext implements ConnectionContext {
 
         this.acc = AccessController.getContext();
         this.consumers = new HashMap<>();
+
+        if (inputRecord instanceof DTLSInputRecord dtlsInputRecord) {
+            dtlsInputRecord.setTransportContext(this);
+            dtlsInputRecord.setSSLContext(this.sslContext);
+        }
     }
 
     // Dispatch plaintext to a specific consumer.
diff --git a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
index 6181bf223e9..306d34d7149 100644
--- a/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
+++ b/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -127,13 +127,24 @@ public final class ObjectIdentifier implements Serializable {
     // Is the component's field calculated?
     private transient boolean   componentsCalculated = false;
 
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  is the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
     @java.io.Serial
     private void readObject(ObjectInputStream is)
             throws IOException, ClassNotFoundException {
         is.defaultReadObject();
 
         if (encoding == null) {  // from an old version
-            int[] comp = (int[])components;
+            if (components == null) {
+                throw new InvalidObjectException("OID components is null");
+            }
+
+            int[] comp = ((int[]) components).clone();
             if (componentLen > comp.length) {
                 componentLen = comp.length;
             }
@@ -142,7 +153,9 @@ public final class ObjectIdentifier implements Serializable {
             // will be performed again in init().
             checkOidSize(componentLen);
             init(comp, componentLen);
+            components = comp;
         } else {
+            encoding = encoding.clone(); // defensive copying
             checkOidSize(encoding.length);
             check(encoding);
         }
@@ -261,6 +274,7 @@ public final class ObjectIdentifier implements Serializable {
         encoding = in.getDerValue().getOID().encoding;
     }
 
+    // set 'encoding' field based on the specified 'components' and 'length'
     private void init(int[] components, int length) throws IOException {
         int pos = 0;
         byte[] tmp = new byte[length * 5 + 1];  // +1 for empty input
diff --git a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
index 3a3d384a0e8..764d77e6da8 100644
--- a/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
+++ b/src/java.base/share/classes/sun/security/x509/AlgIdDSA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,11 +25,13 @@
 
 package sun.security.x509;
 
+import java.io.ObjectInputStream;
 import java.io.IOException;
+import java.io.InvalidObjectException;
 import java.math.BigInteger;
 import java.security.*;
 import java.security.interfaces.DSAParams;
-
+import java.util.Arrays;
 import sun.security.util.*;
 
 
@@ -72,33 +74,42 @@ import sun.security.util.*;
  *
  * @author David Brownell
  */
-public final
-class AlgIdDSA extends AlgorithmId implements DSAParams
-{
+public final class AlgIdDSA extends AlgorithmId implements DSAParams {
 
     @java.io.Serial
     private static final long serialVersionUID = 3437177836797504046L;
 
+    private static class DSAComponents {
+        private final BigInteger p;
+        private final BigInteger q;
+        private final BigInteger g;
+        DSAComponents(BigInteger p, BigInteger q, BigInteger g) {
+            this.p = p;
+            this.q = q;
+            this.g = g;
+        }
+    }
+
     /*
      * The three unsigned integer parameters.
      */
-    private BigInteger  p , q, g;
+    private BigInteger p, q, g;
 
     /** Returns the DSS/DSA parameter "P" */
-    public BigInteger   getP () { return p; }
+    public BigInteger   getP() { return p; }
 
     /** Returns the DSS/DSA parameter "Q" */
-    public BigInteger   getQ () { return q; }
+    public BigInteger   getQ() { return q; }
 
     /** Returns the DSS/DSA parameter "G" */
-    public BigInteger   getG () { return g; }
+    public BigInteger   getG() { return g; }
 
     /**
      * Default constructor.  The OID and parameters must be
      * deserialized before this algorithm ID is used.
      */
     @Deprecated
-    public AlgIdDSA () {}
+    public AlgIdDSA() {}
 
     /**
      * Constructs a DSS/DSA Algorithm ID from numeric parameters.
@@ -109,7 +120,7 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
      * @param q the DSS/DSA parameter "Q"
      * @param g the DSS/DSA parameter "G"
      */
-    public AlgIdDSA (BigInteger p, BigInteger q, BigInteger g) {
+    public AlgIdDSA(BigInteger p, BigInteger q, BigInteger g) {
         super (DSA_oid);
 
         if (p != null || q != null || g != null) {
@@ -120,8 +131,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
                 this.p = p;
                 this.q = q;
                 this.g = g;
-                initializeParams ();
-
+                // For algorithm IDs which haven't been created from a DER
+                // encoded value, need to create DER encoding and store it
+                // into "encodedParams"
+                encodedParams = encode(p, q, g);
             } catch (IOException e) {
                 /* this should not happen */
                 throw new ProviderException ("Construct DSS/DSA Algorithm ID");
@@ -133,50 +146,10 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
      * Returns "DSA", indicating the Digital Signature Algorithm (DSA) as
      * defined by the Digital Signature Standard (DSS), FIPS 186.
      */
-    public String getName ()
-        { return "DSA"; }
-
-
-    /*
-     * For algorithm IDs which haven't been created from a DER encoded
-     * value, "params" must be created.
-     */
-    private void initializeParams () throws IOException {
-        DerOutputStream out = new DerOutputStream();
-        out.putInteger(p);
-        out.putInteger(q);
-        out.putInteger(g);
-        DerOutputStream result = new DerOutputStream();
-        result.write(DerValue.tag_Sequence, out);
-        encodedParams = result.toByteArray();
+    public String getName() {
+        return "DSA";
     }
 
-    /**
-     * Parses algorithm parameters P, Q, and G.  They're found
-     * in the "params" member, which never needs to be changed.
-     */
-    protected void decodeParams () throws IOException {
-        if (encodedParams == null) {
-            throw new IOException("DSA alg params are null");
-        }
-
-        DerValue params = new DerValue(encodedParams);
-        if (params.tag != DerValue.tag_Sequence) {
-            throw new IOException("DSA alg parsing error");
-        }
-
-        params.data.reset ();
-
-        this.p = params.data.getBigInteger();
-        this.q = params.data.getBigInteger();
-        this.g = params.data.getBigInteger();
-
-        if (params.data.available () != 0)
-            throw new IOException ("AlgIdDSA params, extra="+
-                                   params.data.available ());
-    }
-
-
     /*
      * Returns a formatted string describing the parameters.
      */
@@ -197,4 +170,44 @@ class AlgIdDSA extends AlgorithmId implements DSAParams
                     "\n";
         }
     }
+
+    /**
+     * Restores the state of this object from the stream. Override to check
+     * on the 'p', 'q', 'g', and 'encodedParams'.
+     *
+     * @param  stream the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream) throws IOException {
+        try {
+            stream.defaultReadObject();
+            // if any of the 'p', 'q', 'g', 'encodedParams' is non-null,
+            // then they must be all non-null w/ matching encoding
+            if ((p != null || q != null || g != null || encodedParams != null)
+                    && !Arrays.equals(encodedParams, encode(p, q, g))) {
+                throw new InvalidObjectException("Invalid DSA alg params");
+            }
+        } catch (ClassNotFoundException e) {
+            throw new IOException(e);
+        }
+    }
+
+    /*
+     * Create the DER encoding w/ the specified 'p', 'q', 'g'
+     */
+    private static byte[] encode(BigInteger p, BigInteger q,
+            BigInteger g) throws IOException {
+        if (p == null || q == null || g == null) {
+            throw new InvalidObjectException("invalid null value");
+        }
+        DerOutputStream out = new DerOutputStream();
+        out.putInteger(p);
+        out.putInteger(q);
+        out.putInteger(g);
+        DerOutputStream result = new DerOutputStream();
+        result.write(DerValue.tag_Sequence, out);
+        return result.toByteArray();
+    }
 }
diff --git a/src/java.base/share/conf/net.properties b/src/java.base/share/conf/net.properties
index 67f294355a1..2aa9a9630be 100644
--- a/src/java.base/share/conf/net.properties
+++ b/src/java.base/share/conf/net.properties
@@ -130,3 +130,20 @@ jdk.http.auth.tunneling.disabledSchemes=Basic
 #jdk.http.ntlm.transparentAuth=trustedHosts
 #
 jdk.http.ntlm.transparentAuth=disabled
+
+#
+# Maximum HTTP field section size that a client is prepared to accept
+#
+# jdk.http.maxHeaderSize=393216
+#
+# This is the maximum header field section size that a client is prepared to accept.
+# This is computed as the sum of the size of the uncompressed header name, plus
+# the size of the uncompressed header value, plus an overhead of 32 bytes for
+# each field section line. If a peer sends a field section that exceeds this
+# size a {@link java.net.ProtocolException ProtocolException} will be raised.
+# This applies to all versions of the HTTP protocol. A value of zero or a negative
+# value means no limit. If left unspecified, the default value is 393216 bytes
+# or 384kB.
+#
+# Note: This property is currently used by the JDK Reference implementation. It
+# is not guaranteed to be examined and used by other implementations.
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java
index eb30dc85e9c..1ff1e5f4733 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Exchange.java
@@ -41,6 +41,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import java.net.http.HttpClient;
 import java.net.http.HttpHeaders;
@@ -69,6 +70,8 @@ import static jdk.internal.net.http.common.Utils.permissionForProxy;
  */
 final class Exchange<T> {
 
+    static final int MAX_NON_FINAL_RESPONSES =
+            Utils.getIntegerNetProperty("jdk.httpclient.maxNonFinalResponses", 8);
     final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG);
 
     final HttpRequestImpl request;
@@ -93,6 +96,8 @@ final class Exchange<T> {
     // exchange so that it can be aborted/timed out mid setup.
     final ConnectionAborter connectionAborter = new ConnectionAborter();
 
+    final AtomicInteger nonFinalResponses = new AtomicInteger();
+
     Exchange(HttpRequestImpl request, MultiExchange<T> multi) {
         this.request = request;
         this.upgrading = false;
@@ -359,7 +364,7 @@ final class Exchange<T> {
 
     public void h2Upgrade() {
         upgrading = true;
-        request.setH2Upgrade(client.client2());
+        request.setH2Upgrade(this);
     }
 
     synchronized IOException getCancelCause() {
@@ -482,9 +487,9 @@ final class Exchange<T> {
                     Log.logResponse(r1::toString);
                     int rcode = r1.statusCode();
                     if (rcode == 100) {
+                        nonFinalResponses.incrementAndGet();
                         Log.logTrace("Received 100-Continue: sending body");
-                        if (debug.on())
-                            debug.log("Received 100-Continue for %s", r1);
+                        if (debug.on()) debug.log("Received 100-Continue for %s", r1);
                         CompletableFuture<Response> cf =
                                 exchImpl.sendBodyAsync()
                                         .thenCompose(exIm -> exIm.getResponseAsync(parentExecutor));
@@ -492,9 +497,9 @@ final class Exchange<T> {
                         cf = wrapForLog(cf);
                         return cf;
                     } else {
-                        Log.logTrace("Expectation failed: Received {0}", rcode);
-                        if (debug.on())
-                            debug.log("Expect-Continue failed (%d) for: %s", rcode, r1);
+                        Log.logTrace("Expectation failed: Received {0}",
+                                rcode);
+                        if (debug.on()) debug.log("Expect-Continue failed (%d) for: %s", rcode, r1);
                         if (upgrading && rcode == 101) {
                             IOException failed = new IOException(
                                     "Unable to handle 101 while waiting for 100");
@@ -559,12 +564,20 @@ final class Exchange<T> {
                         + rsp.statusCode());
             }
             assert exchImpl != null : "Illegal state - current exchange isn't set";
-            // ignore this Response and wait again for the subsequent response headers
-            final CompletableFuture<Response> cf = exchImpl.getResponseAsync(parentExecutor);
-            // we recompose the CF again into the ignore1xxResponse check/function because
-            // the 1xx response is allowed to be sent multiple times for a request, before
-            // a final response arrives
-            return cf.thenCompose(this::ignore1xxResponse);
+            int count = nonFinalResponses.incrementAndGet();
+            if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) {
+                return MinimalFuture.failedFuture(
+                        new ProtocolException(String.format(
+                                "Too many interim responses received: %s > %s",
+                                count, MAX_NON_FINAL_RESPONSES)));
+            } else {
+                // ignore this Response and wait again for the subsequent response headers
+                final CompletableFuture<Response> cf = exchImpl.getResponseAsync(parentExecutor);
+                // we recompose the CF again into the ignore1xxResponse check/function because
+                // the 1xx response is allowed to be sent multiple times for a request, before
+                // a final response arrives
+                return cf.thenCompose(this::ignore1xxResponse);
+            }
         } else {
             // return the already completed future
             return MinimalFuture.completedFuture(rsp);
@@ -829,6 +842,14 @@ final class Exchange<T> {
         return multi.version();
     }
 
+    boolean pushEnabled() {
+        return pushGroup != null;
+    }
+
+    String h2cSettingsStrings() {
+        return client.client2().getSettingsString(pushEnabled());
+    }
+
     String dbgString() {
         return dbgTag;
     }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java
index 669c173e3f8..8c796193015 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http1HeaderParser.java
@@ -25,6 +25,7 @@
 
 package jdk.internal.net.http;
 
+import java.io.IOException;
 import java.net.ProtocolException;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
@@ -53,6 +54,12 @@ class Http1HeaderParser {
     private int responseCode;
     private HttpHeaders headers;
     private Map<String,List<String>> privateMap = new HashMap<>();
+    private long size;
+
+    private static final int K = 1024;
+    private static  final int MAX_HTTP_HEADER_SIZE = Utils.getIntegerNetProperty(
+            "jdk.http.maxHeaderSize",
+                Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K, true);
 
     enum State { INITIAL,
                  STATUS_LINE,
@@ -164,11 +171,16 @@ class Http1HeaderParser {
         return (char)(input.get() & 0xFF);
     }
 
-    private void readResumeStatusLine(ByteBuffer input) {
+    private void readResumeStatusLine(ByteBuffer input) throws ProtocolException {
+        final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length();
+        int count = 0;
         char c = 0;
         while (input.hasRemaining() && (c = get(input)) != CR) {
             if (c == LF) break;
             sb.append(c);
+            if (++count > max) {
+                checkMaxHeaderSize(sb.length());
+            }
         }
         if (c == CR) {
             state = State.STATUS_LINE_FOUND_CR;
@@ -185,6 +197,7 @@ class Http1HeaderParser {
         }
 
         statusLine = sb.toString();
+        size = size + 32 + statusLine.length();
         sb = new StringBuilder();
         if (!statusLine.startsWith("HTTP/1.")) {
             throw protocolException("Invalid status line: \"%s\"", statusLine);
@@ -205,7 +218,23 @@ class Http1HeaderParser {
         state = State.STATUS_LINE_END;
     }
 
-    private void maybeStartHeaders(ByteBuffer input) {
+    private void checkMaxHeaderSize(int sz) throws ProtocolException {
+        long s = size + sz + 32;
+        if (MAX_HTTP_HEADER_SIZE > 0 && s > MAX_HTTP_HEADER_SIZE) {
+            throw new ProtocolException(String.format("Header size too big: %s > %s",
+                    s, MAX_HTTP_HEADER_SIZE));
+        }
+    }
+    static private long newSize(long size, int name, int value) throws ProtocolException {
+        long newSize = size + name + value + 32;
+        if (MAX_HTTP_HEADER_SIZE > 0 && newSize > MAX_HTTP_HEADER_SIZE) {
+            throw new ProtocolException(String.format("Header size too big: %s > %s",
+                    newSize, MAX_HTTP_HEADER_SIZE));
+        }
+        return newSize;
+    }
+
+    private void maybeStartHeaders(ByteBuffer input) throws ProtocolException {
         assert state == State.STATUS_LINE_END;
         assert sb.length() == 0;
         char c = get(input);
@@ -215,6 +244,7 @@ class Http1HeaderParser {
             state = State.STATUS_LINE_END_LF;
         } else {
             sb.append(c);
+            checkMaxHeaderSize(sb.length());
             state = State.HEADER;
         }
     }
@@ -232,9 +262,11 @@ class Http1HeaderParser {
         }
     }
 
-    private void readResumeHeader(ByteBuffer input) {
+    private void readResumeHeader(ByteBuffer input) throws ProtocolException {
         assert state == State.HEADER;
         assert input.hasRemaining();
+        final long max = MAX_HTTP_HEADER_SIZE - size - 32 - sb.length();
+        int count = 0;
         while (input.hasRemaining()) {
             char c = get(input);
             if (c == CR) {
@@ -248,6 +280,9 @@ class Http1HeaderParser {
             if (c == HT)
                 c = SP;
             sb.append(c);
+            if (++count > max) {
+                checkMaxHeaderSize(sb.length());
+            }
         }
     }
 
@@ -268,12 +303,12 @@ class Http1HeaderParser {
         if (!Utils.isValidValue(value)) {
             throw protocolException("Invalid header value \"%s: %s\"", name, value);
         }
-
+        size = newSize(size, name.length(), value.length());
         privateMap.computeIfAbsent(name.toLowerCase(Locale.US),
                                    k -> new ArrayList<>()).add(value);
     }
 
-    private void resumeOrLF(ByteBuffer input) {
+    private void resumeOrLF(ByteBuffer input) throws ProtocolException {
         assert state == State.HEADER_FOUND_CR || state == State.HEADER_FOUND_LF;
         char c = state == State.HEADER_FOUND_LF ? LF : get(input);
         if (c == LF) {
@@ -283,10 +318,12 @@ class Http1HeaderParser {
             state = State.HEADER_FOUND_CR_LF;
         } else if (c == SP || c == HT) {
             sb.append(SP); // parity with MessageHeaders
+            checkMaxHeaderSize(sb.length());
             state = State.HEADER;
         } else {
             sb = new StringBuilder();
             sb.append(c);
+            checkMaxHeaderSize(1);
             state = State.HEADER;
         }
     }
@@ -312,6 +349,7 @@ class Http1HeaderParser {
         } else if (c == SP || c == HT) {
             assert sb.length() != 0;
             sb.append(SP); // continuation line
+            checkMaxHeaderSize(sb.length());
             state = State.HEADER;
         } else {
             if (sb.length() > 0) {
@@ -322,6 +360,7 @@ class Http1HeaderParser {
                 addHeaderFromString(headerString);
             }
             sb.append(c);
+            checkMaxHeaderSize(sb.length());
             state = State.HEADER;
         }
     }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java
index 50338f94c1d..022442b5371 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2ClientImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.locks.ReentrantLock;
 
-import jdk.internal.net.http.common.Log;
 import jdk.internal.net.http.common.Logger;
 import jdk.internal.net.http.common.MinimalFuture;
 import jdk.internal.net.http.common.Utils;
@@ -46,6 +45,7 @@ import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH;
 import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE;
 import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS;
 import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE;
+import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE;
 
 /**
  *  Http2 specific aspects of HttpClientImpl
@@ -98,16 +98,20 @@ class Http2ClientImpl {
     CompletableFuture<Http2Connection> getConnectionFor(HttpRequestImpl req,
                                                         Exchange<?> exchange) {
         String key = Http2Connection.keyFor(req);
+        boolean pushEnabled = exchange.pushEnabled();
 
         connectionPoolLock.lock();
         try {
             Http2Connection connection = connections.get(key);
             if (connection != null) {
                 try {
-                    if (!connection.tryReserveForPoolCheckout() || !connection.reserveStream(true)) {
+                    if (!connection.tryReserveForPoolCheckout()
+                            || !connection.reserveStream(true, pushEnabled)) {
                         if (debug.on())
                             debug.log("removing connection from pool since it couldn't be" +
-                                    " reserved for use: %s", connection);
+                                    " reserved for use%s: %s",
+                                    pushEnabled ? " with server push enabled" : "",
+                                    connection);
                         removeFromPool(connection);
                     } else {
                         // fast path if connection already exists
@@ -137,7 +141,7 @@ class Http2ClientImpl {
                     try {
                         if (conn != null) {
                             try {
-                                conn.reserveStream(true);
+                                conn.reserveStream(true, exchange.pushEnabled());
                             } catch (IOException e) {
                                 throw new UncheckedIOException(e); // shouldn't happen
                             }
@@ -183,10 +187,21 @@ class Http2ClientImpl {
             }
             Http2Connection c1 = connections.putIfAbsent(key, c);
             if (c1 != null) {
-                c.setFinalStream();
-                if (debug.on())
-                    debug.log("existing entry in connection pool for %s", key);
-                return false;
+                if (c.serverPushEnabled() && !c1.serverPushEnabled()) {
+                    c1.setFinalStream();
+                    connections.remove(key, c1);
+                    connections.put(key, c);
+                    if (debug.on()) {
+                        debug.log("Replacing %s with %s in connection pool", c1, c);
+                    }
+                    if (c1.shouldClose()) c1.close();
+                    return  true;
+                } else {
+                    c.setFinalStream();
+                    if (debug.on())
+                        debug.log("existing entry in connection pool for %s", key);
+                    return false;
+                }
             }
             if (debug.on())
                 debug.log("put in the connection pool: %s", c);
@@ -250,8 +265,8 @@ class Http2ClientImpl {
     }
 
     /** Returns the client settings as a base64 (url) encoded string */
-    String getSettingsString() {
-        SettingsFrame sf = getClientSettings();
+    String getSettingsString(boolean defaultServerPush) {
+        SettingsFrame sf = getClientSettings(defaultServerPush);
         byte[] settings = sf.toByteArray(); // without the header
         Base64.Encoder encoder = Base64.getUrlEncoder()
                                        .withoutPadding();
@@ -261,14 +276,7 @@ class Http2ClientImpl {
     private static final int K = 1024;
 
     private static int getParameter(String property, int min, int max, int defaultValue) {
-        int value =  Utils.getIntegerNetProperty(property, defaultValue);
-        // use default value if misconfigured
-        if (value < min || value > max) {
-            Log.logError("Property value for {0}={1} not in [{2}..{3}]: " +
-                    "using default={4}", property, value, min, max, defaultValue);
-            value = defaultValue;
-        }
-        return value;
+        return Utils.getIntegerNetProperty(property, min, max, defaultValue, true);
     }
 
     // used for the connection window, to have a connection window size
@@ -288,7 +296,18 @@ class Http2ClientImpl {
                 streamWindow, Integer.MAX_VALUE, defaultValue);
     }
 
-    SettingsFrame getClientSettings() {
+    /**
+     * This method is used to test whether pushes are globally
+     * disabled on all connections.
+     * @return true if pushes are globally disabled on all connections
+     */
+    boolean serverPushDisabled() {
+        return getParameter(
+                "jdk.httpclient.enablepush",
+                0, 1, 1) == 0;
+    }
+
+    SettingsFrame getClientSettings(boolean defaultServerPush) {
         SettingsFrame frame = new SettingsFrame();
         // default defined for HTTP/2 is 4 K, we use 16 K.
         frame.setParameter(HEADER_TABLE_SIZE, getParameter(
@@ -297,14 +316,15 @@ class Http2ClientImpl {
         // O: does not accept push streams. 1: accepts push streams.
         frame.setParameter(ENABLE_PUSH, getParameter(
                 "jdk.httpclient.enablepush",
-                0, 1, 1));
+                0, 1, defaultServerPush ? 1 : 0));
         // HTTP/2 recommends to set the number of concurrent streams
-        // no lower than 100. We use 100. 0 means no stream would be
-        // accepted. That would render the client to be non functional,
-        // so we won't let 0 be configured for our Http2ClientImpl.
+        // no lower than 100. We use 100, unless push promises are
+        // disabled.
+        int initialServerStreams = frame.getParameter(ENABLE_PUSH) == 0
+                ? 0 : 100;
         frame.setParameter(MAX_CONCURRENT_STREAMS, getParameter(
                 "jdk.httpclient.maxstreams",
-                1, Integer.MAX_VALUE, 100));
+                0, Integer.MAX_VALUE, initialServerStreams));
         // Maximum size is 2^31-1. Don't allow window size to be less
         // than the minimum frame size as this is likely to be a
         // configuration error. HTTP/2 specify a default of 64 * K -1,
@@ -317,6 +337,14 @@ class Http2ClientImpl {
         frame.setParameter(MAX_FRAME_SIZE, getParameter(
                 "jdk.httpclient.maxframesize",
                 16 * K, 16 * K * K -1, 16 * K));
+        // Maximum field section size we're prepared to accept
+        // This is the uncompressed name + value size + 32 per field line
+        int maxHeaderSize = getParameter(
+                "jdk.http.maxHeaderSize",
+                Integer.MIN_VALUE, Integer.MAX_VALUE, 384 * K);
+        // If the property is <= 0 the value is unlimited
+        if (maxHeaderSize <= 0) maxHeaderSize = -1;
+        frame.setParameter(MAX_HEADER_LIST_SIZE, maxHeaderSize);
         return frame;
     }
 
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java
index 9457ff69988..080905222c3 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Http2Connection.java
@@ -31,6 +31,7 @@ import java.io.UncheckedIOException;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.net.InetSocketAddress;
+import java.net.ProtocolException;
 import java.net.http.HttpClient;
 import java.net.http.HttpHeaders;
 import java.nio.ByteBuffer;
@@ -49,6 +50,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Flow;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.Function;
@@ -88,10 +90,12 @@ import jdk.internal.net.http.hpack.DecodingCallback;
 import jdk.internal.net.http.hpack.Encoder;
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_INITIAL_WINDOW_SIZE;
+import static jdk.internal.net.http.frame.SettingsFrame.ENABLE_PUSH;
 import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE;
 import static jdk.internal.net.http.frame.SettingsFrame.INITIAL_WINDOW_SIZE;
 import static jdk.internal.net.http.frame.SettingsFrame.MAX_CONCURRENT_STREAMS;
 import static jdk.internal.net.http.frame.SettingsFrame.MAX_FRAME_SIZE;
+import static jdk.internal.net.http.frame.SettingsFrame.MAX_HEADER_LIST_SIZE;
 
 /**
  * An Http2Connection. Encapsulates the socket(channel) and any SSLEngine used
@@ -327,6 +331,45 @@ class Http2Connection  {
         }
     }
 
+    private final class PushPromiseDecoder extends HeaderDecoder implements DecodingCallback {
+
+        final int parentStreamId;
+        final int pushPromiseStreamId;
+        final Stream<?> parent;
+        final AtomicReference<Throwable> errorRef = new AtomicReference<>();
+
+        PushPromiseDecoder(int parentStreamId, int pushPromiseStreamId, Stream<?> parent) {
+            this.parentStreamId = parentStreamId;
+            this.pushPromiseStreamId = pushPromiseStreamId;
+            this.parent = parent;
+        }
+
+        @Override
+        protected void addHeader(String name, String value) {
+            if (errorRef.get() == null) {
+                super.addHeader(name, value);
+            }
+        }
+
+        @Override
+        public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException {
+            try {
+                DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize);
+            } catch (ProtocolException pe) {
+                if (parent != null) {
+                    if (errorRef.compareAndSet(null, pe)) {
+                        // cancel the parent stream
+                        resetStream(pushPromiseStreamId, ResetFrame.REFUSED_STREAM);
+                        parent.onProtocolError(pe);
+                    }
+                } else {
+                    // interrupt decoding and closes the connection
+                    throw pe;
+                }
+            }
+        }
+    }
+
 
     private static final int HALF_CLOSED_LOCAL  = 1;
     private static final int HALF_CLOSED_REMOTE = 2;
@@ -355,7 +398,7 @@ class Http2Connection  {
     private final Decoder hpackIn;
     final SettingsFrame clientSettings;
     private volatile SettingsFrame serverSettings;
-    private record PushContinuationState(HeaderDecoder pushContDecoder, PushPromiseFrame pushContFrame) {}
+    private record PushContinuationState(PushPromiseDecoder pushContDecoder, PushPromiseFrame pushContFrame) {}
     private volatile PushContinuationState pushContinuationState;
     private final String key; // for HttpClientImpl.connections map
     private final FramesDecoder framesDecoder;
@@ -370,12 +413,24 @@ class Http2Connection  {
     private final FramesController framesController = new FramesController();
     private final Http2TubeSubscriber subscriber;
     final ConnectionWindowUpdateSender windowUpdater;
-    private volatile Throwable cause;
+    private final AtomicReference<Throwable> cause = new AtomicReference<>();
     private volatile Supplier<ByteBuffer> initial;
     private volatile Stream<?> initialStream;
 
-    static final int DEFAULT_FRAME_SIZE = 16 * 1024;
+    private ValidatingHeadersConsumer orphanedConsumer;
+    private final AtomicInteger orphanedHeaders = new AtomicInteger();
 
+    static final int DEFAULT_FRAME_SIZE = 16 * 1024;
+    static final int MAX_LITERAL_WITH_INDEXING =
+            Utils.getIntegerNetProperty("jdk.httpclient.maxLiteralWithIndexing",512);
+
+    // The maximum number of HEADER frames, CONTINUATION frames, or PUSH_PROMISE frames
+    // referring to an already closed or non-existent stream that a client will accept to
+    // process. Receiving frames referring to non-existent or closed streams doesn't necessarily
+    // constitute an HTTP/2 protocol error, but receiving too many may indicate a problem
+    // with the connection. If this limit is reached, a {@link java.net.ProtocolException
+    // ProtocolException} will be raised and the connection will be closed.
+    static final int MAX_ORPHANED_HEADERS = 1024;
 
     // TODO: need list of control frames from other threads
     // that need to be sent
@@ -383,19 +438,21 @@ class Http2Connection  {
     private Http2Connection(HttpConnection connection,
                             Http2ClientImpl client2,
                             int nextstreamid,
-                            String key) {
+                            String key,
+                            boolean defaultServerPush) {
         this.connection = connection;
         this.client2 = client2;
         this.subscriber = new Http2TubeSubscriber(client2.client());
         this.nextstreamid = nextstreamid;
         this.key = key;
-        this.clientSettings = this.client2.getClientSettings();
+        this.clientSettings = this.client2.getClientSettings(defaultServerPush);
         this.framesDecoder = new FramesDecoder(this::processFrame,
                 clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE));
         // serverSettings will be updated by server
         this.serverSettings = SettingsFrame.defaultRFCSettings();
         this.hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
-        this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
+        this.hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE),
+                clientSettings.getParameter(MAX_HEADER_LIST_SIZE), MAX_LITERAL_WITH_INDEXING);
         if (debugHpack.on()) {
             debugHpack.log("For the record:" + super.toString());
             debugHpack.log("Decoder created: %s", hpackIn);
@@ -414,14 +471,16 @@ class Http2Connection  {
     private Http2Connection(HttpConnection connection,
                     Http2ClientImpl client2,
                     Exchange<?> exchange,
-                    Supplier<ByteBuffer> initial)
+                    Supplier<ByteBuffer> initial,
+                    boolean defaultServerPush)
         throws IOException, InterruptedException
     {
         this(connection,
                 client2,
                 3, // stream 1 is registered during the upgrade
-                keyFor(connection));
-        reserveStream(true);
+                keyFor(connection),
+                defaultServerPush);
+        reserveStream(true, clientSettings.getFlag(ENABLE_PUSH));
         Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize());
 
         Stream<?> initialStream = createStream(exchange);
@@ -454,7 +513,8 @@ class Http2Connection  {
                                                           Exchange<?> exchange,
                                                           Supplier<ByteBuffer> initial)
     {
-        return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial));
+        return MinimalFuture.supply(() -> new Http2Connection(connection, client2, exchange, initial,
+                exchange.pushEnabled()));
     }
 
     // Requires TLS handshake. So, is really async
@@ -478,7 +538,8 @@ class Http2Connection  {
                   .thenCompose(notused-> {
                       CompletableFuture<Http2Connection> cf = new MinimalFuture<>();
                       try {
-                          Http2Connection hc = new Http2Connection(request, h2client, connection);
+                          Http2Connection hc = new Http2Connection(request, h2client,
+                                  connection, exchange.pushEnabled());
                           cf.complete(hc);
                       } catch (IOException e) {
                           cf.completeExceptionally(e);
@@ -493,13 +554,15 @@ class Http2Connection  {
      */
     private Http2Connection(HttpRequestImpl request,
                             Http2ClientImpl h2client,
-                            HttpConnection connection)
+                            HttpConnection connection,
+                            boolean defaultServerPush)
         throws IOException
     {
         this(connection,
              h2client,
              1,
-             keyFor(request));
+             keyFor(request),
+             defaultServerPush);
 
         Log.logTrace("Connection send window size {0} ", windowController.connectionWindowSize());
 
@@ -522,24 +585,30 @@ class Http2Connection  {
     // if false returned then a new Http2Connection is required
     // if true, the stream may be assigned to this connection
     // for server push, if false returned, then the stream should be cancelled
-    boolean reserveStream(boolean clientInitiated) throws IOException {
+    boolean reserveStream(boolean clientInitiated, boolean pushEnabled) throws IOException {
         stateLock.lock();
         try {
-            return reserveStream0(clientInitiated);
+            return reserveStream0(clientInitiated, pushEnabled);
         } finally {
             stateLock.unlock();
         }
     }
 
-    private boolean reserveStream0(boolean clientInitiated) throws IOException {
+    private boolean reserveStream0(boolean clientInitiated, boolean pushEnabled) throws IOException {
         if (finalStream()) {
             return false;
         }
-        if (clientInitiated && (lastReservedClientStreamid + 2) >= MAX_CLIENT_STREAM_ID) {
+        // If requesting to reserve a stream for an exchange for which push is enabled,
+        // we will reserve the stream in this connection only if this connection is also
+        // push enabled, unless pushes are globally disabled.
+        boolean pushCompatible = !clientInitiated || !pushEnabled
+                || this.serverPushEnabled()
+                || client2.serverPushDisabled();
+        if (clientInitiated && (lastReservedClientStreamid >= MAX_CLIENT_STREAM_ID -2  || !pushCompatible)) {
             setFinalStream();
             client2.removeFromPool(this);
             return false;
-        } else if (!clientInitiated && (lastReservedServerStreamid + 2) >= MAX_SERVER_STREAM_ID) {
+        } else if (!clientInitiated && (lastReservedServerStreamid >= MAX_SERVER_STREAM_ID - 2)) {
             setFinalStream();
             client2.removeFromPool(this);
             return false;
@@ -564,6 +633,15 @@ class Http2Connection  {
         return true;
     }
 
+    boolean shouldClose() {
+        stateLock.lock();
+        try {
+            return finalStream() && streams.isEmpty();
+        } finally {
+            stateLock.unlock();
+        }
+    }
+
     /**
      * Throws an IOException if h2 was not negotiated
      */
@@ -691,6 +769,10 @@ class Http2Connection  {
         return this.key;
     }
 
+    public boolean serverPushEnabled() {
+        return clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1;
+    }
+
     boolean offerConnection() {
         return client2.offerConnection(this);
     }
@@ -795,7 +877,7 @@ class Http2Connection  {
     }
 
     Throwable getRecordedCause() {
-        return cause;
+        return cause.get();
     }
 
     void shutdown(Throwable t) {
@@ -804,11 +886,11 @@ class Http2Connection  {
         stateLock.lock();
         try {
             if (!markShutdownRequested()) return;
-            Throwable initialCause = this.cause;
-            if (initialCause == null && t != null) this.cause = t;
+            cause.compareAndSet(null, t);
         } finally {
             stateLock.unlock();
         }
+
         if (Log.errors()) {
             if (t!= null && (!(t instanceof EOFException) || isActive())) {
                 Log.logError(t);
@@ -819,6 +901,7 @@ class Http2Connection  {
             }
         }
         client2.removeFromPool(this);
+        subscriber.stop(cause.get());
         for (Stream<?> s : streams.values()) {
             try {
                 s.connectionClosing(t);
@@ -872,17 +955,39 @@ class Http2Connection  {
                 return;
             }
 
+            if (frame instanceof PushPromiseFrame && !serverPushEnabled()) {
+                String protocolError = "received a PUSH_PROMISE when SETTINGS_ENABLE_PUSH is 0";
+                protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
+                return;
+            }
+
             Stream<?> stream = getStream(streamid);
+            var nextstreamid = this.nextstreamid;
+            if (stream == null && (streamid & 0x01) == 0x01 && streamid >= nextstreamid) {
+                String protocolError = String.format(
+                        "received a frame for a non existing streamid(%s) >= nextstreamid(%s)",
+                        streamid, nextstreamid);
+                protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
+                return;
+            }
             if (stream == null && pushContinuationState == null) {
                 // Should never receive a frame with unknown stream id
 
-                if (frame instanceof HeaderFrame) {
+                if (frame instanceof HeaderFrame hf) {
+                    String protocolError = checkMaxOrphanedHeadersExceeded(hf);
+                    if (protocolError != null) {
+                        protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
+                        return;
+                    }
                     // always decode the headers as they may affect
                     // connection-level HPACK decoding state
-                    DecodingCallback decoder = new ValidatingHeadersConsumer()::onDecoded;
+                    if (orphanedConsumer == null || frame.getClass() != ContinuationFrame.class) {
+                        orphanedConsumer = new ValidatingHeadersConsumer();
+                    }
+                    DecodingCallback decoder = orphanedConsumer::onDecoded;
                     try {
-                        decodeHeaders((HeaderFrame) frame, decoder);
-                    } catch (UncheckedIOException e) {
+                        decodeHeaders(hf, decoder);
+                    } catch (IOException | UncheckedIOException e) {
                         protocolError(ResetFrame.PROTOCOL_ERROR, e.getMessage());
                         return;
                     }
@@ -910,29 +1015,41 @@ class Http2Connection  {
 
             // While push frame is not null, the only acceptable frame on this
             // stream is a Continuation frame
-            if (pushContinuationState != null) {
+            PushContinuationState pcs = pushContinuationState;
+            if (pcs != null) {
                 if (frame instanceof ContinuationFrame cf) {
+                    if (stream == null) {
+                        String protocolError = checkMaxOrphanedHeadersExceeded(cf);
+                        if (protocolError != null) {
+                            protocolError(ResetFrame.PROTOCOL_ERROR, protocolError);
+                            return;
+                        }
+                    }
                     try {
-                        if (streamid == pushContinuationState.pushContFrame.streamid())
-                            handlePushContinuation(stream, cf);
-                        else
-                            protocolError(ErrorFrame.PROTOCOL_ERROR, "Received a Continuation Frame with an " +
-                                    "unexpected stream id");
-                    } catch (UncheckedIOException e) {
+                        if (streamid == pcs.pushContFrame.streamid())
+                            handlePushContinuation(pcs, stream, cf);
+                        else {
+                            String protocolError = "Received a CONTINUATION with " +
+                                    "unexpected stream id: " + streamid + " != "
+                                    + pcs.pushContFrame.streamid();
+                            protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError);
+                        }
+                    } catch (IOException | UncheckedIOException e) {
                         debug.log("Error handling Push Promise with Continuation: " + e.getMessage(), e);
                         protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
                         return;
                     }
                 } else {
                     pushContinuationState = null;
-                    protocolError(ErrorFrame.PROTOCOL_ERROR, "Expected a Continuation frame but received " + frame);
+                    String protocolError = "Expected a CONTINUATION frame but received " + frame;
+                    protocolError(ErrorFrame.PROTOCOL_ERROR, protocolError);
                     return;
                 }
             } else {
                 if (frame instanceof PushPromiseFrame pp) {
                     try {
                         handlePushPromise(stream, pp);
-                    } catch (UncheckedIOException e) {
+                    } catch (IOException | UncheckedIOException e) {
                         protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
                         return;
                     }
@@ -940,7 +1057,7 @@ class Http2Connection  {
                     // decode headers
                     try {
                         decodeHeaders(hf, stream.rspHeadersConsumer());
-                    } catch (UncheckedIOException e) {
+                    } catch (IOException | UncheckedIOException e) {
                         debug.log("Error decoding headers: " + e.getMessage(), e);
                         protocolError(ErrorFrame.PROTOCOL_ERROR, e.getMessage());
                         return;
@@ -953,6 +1070,16 @@ class Http2Connection  {
         }
     }
 
+    private String checkMaxOrphanedHeadersExceeded(HeaderFrame hf) {
+        if (MAX_ORPHANED_HEADERS > 0 ) {
+            int orphaned = orphanedHeaders.incrementAndGet();
+            if (orphaned < 0 || orphaned > MAX_ORPHANED_HEADERS) {
+               return "Too many orphaned header frames received on connection";
+            }
+        }
+        return null;
+    }
+
     final void dropDataFrame(DataFrame df) {
         if (isMarked(closedState, SHUTDOWN_REQUESTED)) return;
         if (debug.on()) {
@@ -977,38 +1104,65 @@ class Http2Connection  {
     private <T> void handlePushPromise(Stream<T> parent, PushPromiseFrame pp)
         throws IOException
     {
+        int promisedStreamid = pp.getPromisedStream();
+        if ((promisedStreamid & 0x01) != 0x00) {
+            throw new ProtocolException("Received PUSH_PROMISE for stream " + promisedStreamid);
+        }
+        int streamId = pp.streamid();
+        if ((streamId & 0x01) != 0x01) {
+            throw new ProtocolException("Received PUSH_PROMISE on stream " + streamId);
+        }
         // always decode the headers as they may affect connection-level HPACK
         // decoding state
         assert pushContinuationState == null;
-        HeaderDecoder decoder = new HeaderDecoder();
-        decodeHeaders(pp, decoder::onDecoded);
-        int promisedStreamid = pp.getPromisedStream();
+        PushPromiseDecoder decoder = new PushPromiseDecoder(streamId, promisedStreamid, parent);
+        decodeHeaders(pp, decoder);
         if (pp.endHeaders()) {
-            completePushPromise(promisedStreamid, parent, decoder.headers());
+            if (decoder.errorRef.get() == null) {
+                completePushPromise(promisedStreamid, parent, decoder.headers());
+            }
         } else {
             pushContinuationState = new PushContinuationState(decoder, pp);
         }
     }
 
-    private <T> void handlePushContinuation(Stream<T> parent, ContinuationFrame cf)
+    private <T> void handlePushContinuation(PushContinuationState pcs, Stream<T> parent, ContinuationFrame cf)
             throws IOException {
-        var pcs = pushContinuationState;
-        decodeHeaders(cf, pcs.pushContDecoder::onDecoded);
+        assert pcs.pushContFrame.streamid() == cf.streamid() : String.format(
+                    "Received CONTINUATION on a different stream %s != %s",
+                    cf.streamid(), pcs.pushContFrame.streamid());
+        decodeHeaders(cf, pcs.pushContDecoder);
         // if all continuations are sent, set pushWithContinuation to null
         if (cf.endHeaders()) {
-            completePushPromise(pcs.pushContFrame.getPromisedStream(), parent,
-                    pcs.pushContDecoder.headers());
+            if (pcs.pushContDecoder.errorRef.get() == null) {
+                completePushPromise(pcs.pushContFrame.getPromisedStream(), parent,
+                        pcs.pushContDecoder.headers());
+            }
             pushContinuationState = null;
         }
     }
 
     private <T> void completePushPromise(int promisedStreamid, Stream<T> parent, HttpHeaders headers)
             throws IOException {
+        if (parent == null) {
+            resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM);
+            return;
+        }
         HttpRequestImpl parentReq = parent.request;
+        if (promisedStreamid < nextPushStream) {
+            // From RFC 9113 section 5.1.1:
+            // The identifier of a newly established stream MUST be numerically
+            // greater than all streams that the initiating endpoint has
+            // opened or reserved.
+            protocolError(ResetFrame.PROTOCOL_ERROR, String.format(
+                    "Unexpected stream identifier: %s < %s", promisedStreamid, nextPushStream));
+            return;
+        }
         if (promisedStreamid != nextPushStream) {
+            // we don't support skipping stream ids;
             resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR);
             return;
-        } else if (!reserveStream(false)) {
+        } else if (!reserveStream(false, true)) {
             resetStream(promisedStreamid, ResetFrame.REFUSED_STREAM);
             return;
         } else {
@@ -1177,11 +1331,17 @@ class Http2Connection  {
     private void protocolError(int errorCode, String msg)
         throws IOException
     {
+        String protocolError = "protocol error" + (msg == null?"":(": " + msg));
+        ProtocolException protocolException =
+                new ProtocolException(protocolError);
         if (markHalfClosedLocal()) {
+            framesDecoder.close(protocolError);
+            subscriber.stop(protocolException);
+            if (debug.on()) debug.log("Sending GOAWAY due to " + protocolException);
             GoAwayFrame frame = new GoAwayFrame(0, errorCode);
             sendFrame(frame);
         }
-        shutdown(new IOException("protocol error" + (msg == null?"":(": " + msg))));
+        shutdown(protocolException);
     }
 
     private void handleSettings(SettingsFrame frame)
@@ -1356,7 +1516,7 @@ class Http2Connection  {
 
     <T> Stream.PushedStream<T> createPushStream(Stream<T> parent, Exchange<T> pushEx) {
         PushGroup<T> pg = parent.exchange.getPushGroup();
-        return new Stream.PushedStream<>(pg, this, pushEx);
+        return new Stream.PushedStream<>(parent, pg, this, pushEx);
     }
 
     /**
@@ -1466,16 +1626,18 @@ class Http2Connection  {
     private List<ByteBuffer> encodeHeadersImpl(int bufferSize, HttpHeaders... headers) {
         ByteBuffer buffer = getHeaderBuffer(bufferSize);
         List<ByteBuffer> buffers = new ArrayList<>();
-        for(HttpHeaders header : headers) {
+        for (HttpHeaders header : headers) {
             for (Map.Entry<String, List<String>> e : header.map().entrySet()) {
                 String lKey = e.getKey().toLowerCase(Locale.US);
                 List<String> values = e.getValue();
                 for (String value : values) {
                     hpackOut.header(lKey, value);
                     while (!hpackOut.encode(buffer)) {
-                        buffer.flip();
-                        buffers.add(buffer);
-                        buffer =  getHeaderBuffer(bufferSize);
+                        if (!buffer.hasRemaining()) {
+                            buffer.flip();
+                            buffers.add(buffer);
+                            buffer = getHeaderBuffer(bufferSize);
+                        }
                     }
                 }
             }
@@ -1514,7 +1676,7 @@ class Http2Connection  {
         Throwable cause = null;
         synchronized (this) {
             if (isMarked(closedState, SHUTDOWN_REQUESTED)) {
-                cause = this.cause;
+                cause = this.cause.get();
                 if (cause == null) {
                     cause = new IOException("Connection closed");
                 }
@@ -1553,6 +1715,8 @@ class Http2Connection  {
                     Stream<?> stream = registerNewStream(oh);
                     // provide protection from inserting unordered frames between Headers and Continuation
                     if (stream != null) {
+                        // we are creating a new stream: reset orphaned header count
+                        orphanedHeaders.set(0);
                         publisher.enqueue(encodeHeaders(oh, stream));
                     }
                 } else {
@@ -1621,7 +1785,7 @@ class Http2Connection  {
         private volatile Flow.Subscription subscription;
         private volatile boolean completed;
         private volatile boolean dropped;
-        private volatile Throwable error;
+        private final AtomicReference<Throwable> errorRef = new AtomicReference<>();
         private final ConcurrentLinkedQueue<ByteBuffer> queue
                 = new ConcurrentLinkedQueue<>();
         private final SequentialScheduler scheduler =
@@ -1642,10 +1806,9 @@ class Http2Connection  {
                     asyncReceive(buffer);
                 }
             } catch (Throwable t) {
-                Throwable x = error;
-                if (x == null) error = t;
+                errorRef.compareAndSet(null, t);
             } finally {
-                Throwable x = error;
+                Throwable x = errorRef.get();
                 if (x != null) {
                     if (debug.on()) debug.log("Stopping scheduler", x);
                     scheduler.stop();
@@ -1680,6 +1843,7 @@ class Http2Connection  {
 
         @Override
         public void onNext(List<ByteBuffer> item) {
+            if (completed) return;
             if (debug.on()) debug.log(() -> "onNext: got " + Utils.remaining(item)
                     + " bytes in " + item.size() + " buffers");
             queue.addAll(item);
@@ -1688,19 +1852,21 @@ class Http2Connection  {
 
         @Override
         public void onError(Throwable throwable) {
+            if (completed) return;
             if (debug.on()) debug.log(() -> "onError: " + throwable);
-            error = throwable;
+            errorRef.compareAndSet(null, throwable);
             completed = true;
             runOrSchedule();
         }
 
         @Override
         public void onComplete() {
+            if (completed) return;
             String msg = isActive()
                     ? "EOF reached while reading"
                     : "Idle connection closed by HTTP/2 peer";
             if (debug.on()) debug.log(msg);
-            error = new EOFException(msg);
+            errorRef.compareAndSet(null, new EOFException(msg));
             completed = true;
             runOrSchedule();
         }
@@ -1712,6 +1878,18 @@ class Http2Connection  {
             // then we might not need the 'dropped' boolean?
             dropped = true;
         }
+
+        void stop(Throwable error) {
+            if (errorRef.compareAndSet(null, error)) {
+                completed = true;
+                scheduler.stop();
+                queue.clear();
+                if (subscription != null) {
+                    subscription.cancel();
+                }
+                queue.clear();
+            }
+        }
     }
 
     boolean isActive() {
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
index 3fe8efdd7af..e1f4ec16dcd 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.java
@@ -964,7 +964,9 @@ final class HttpClientImpl extends HttpClient implements Trackable {
                 // SSLException
                 throw new SSLException(msg, throwable);
             } else if (throwable instanceof ProtocolException) {
-                throw new ProtocolException(msg);
+                ProtocolException pe = new ProtocolException(msg);
+                pe.initCause(throwable);
+                throw pe;
             } else if (throwable instanceof IOException) {
                 throw new IOException(msg, throwable);
             } else {
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java
index 68a27041d6b..f5b5ed54bf3 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java
@@ -287,10 +287,10 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
 
     InetSocketAddress authority() { return authority; }
 
-    void setH2Upgrade(Http2ClientImpl h2client) {
+    void setH2Upgrade(Exchange<?> exchange) {
         systemHeadersBuilder.setHeader("Connection", "Upgrade, HTTP2-Settings");
         systemHeadersBuilder.setHeader("Upgrade", Alpns.H2C);
-        systemHeadersBuilder.setHeader("HTTP2-Settings", h2client.getSettingsString());
+        systemHeadersBuilder.setHeader("HTTP2-Settings", exchange.h2cSettingsStrings());
     }
 
     @Override
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java
index 66d89ae1fc5..22e03238d21 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/ResponseBodyHandlers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@ import java.nio.file.Paths;
 import java.security.AccessControlContext;
 import java.security.AccessController;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.Function;
@@ -137,16 +138,21 @@ public final class ResponseBodyHandlers {
             if (!initiatingURI.getHost().equalsIgnoreCase(pushRequestURI.getHost()))
                 return;
 
+            String initiatingScheme = initiatingURI.getScheme();
+            String pushRequestScheme = pushRequestURI.getScheme();
+
+            if (!initiatingScheme.equalsIgnoreCase(pushRequestScheme)) return;
+
             int initiatingPort = initiatingURI.getPort();
             if (initiatingPort == -1 ) {
-                if ("https".equalsIgnoreCase(initiatingURI.getScheme()))
+                if ("https".equalsIgnoreCase(initiatingScheme))
                     initiatingPort = 443;
                 else
                     initiatingPort = 80;
             }
             int pushPort = pushRequestURI.getPort();
             if (pushPort == -1 ) {
-                if ("https".equalsIgnoreCase(pushRequestURI.getScheme()))
+                if ("https".equalsIgnoreCase(pushRequestScheme))
                     pushPort = 443;
                 else
                     pushPort = 80;
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
index 45633622923..84187678f94 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/Stream.java
@@ -30,6 +30,7 @@ import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
+import java.net.ProtocolException;
 import java.net.URI;
 import java.net.http.HttpResponse.BodyHandler;
 import java.net.http.HttpResponse.ResponseInfo;
@@ -43,6 +44,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Flow;
 import java.util.concurrent.Flow.Subscription;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -52,10 +54,13 @@ import java.net.http.HttpHeaders;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.net.http.HttpResponse.BodySubscriber;
+
 import jdk.internal.net.http.common.*;
 import jdk.internal.net.http.frame.*;
 import jdk.internal.net.http.hpack.DecodingCallback;
 
+import static jdk.internal.net.http.Exchange.MAX_NON_FINAL_RESPONSES;
+
 /**
  * Http/2 Stream handling.
  *
@@ -140,6 +145,9 @@ class Stream<T> extends ExchangeImpl<T> {
     private volatile boolean closed;
     private volatile boolean endStreamSent;
     private volatile boolean finalResponseCodeReceived;
+    private volatile boolean trailerReceived;
+    private AtomicInteger nonFinalResponseCount = new AtomicInteger();
+
     // Indicates the first reason that was invoked when sending a ResetFrame
     // to the server. A streamState of 0 indicates that no reset was sent.
     // (see markStream(int code)
@@ -520,16 +528,38 @@ class Stream<T> extends ExchangeImpl<T> {
     // The Hpack decoder decodes into one of these consumers of name,value pairs
 
     DecodingCallback rspHeadersConsumer() {
-        return rspHeadersConsumer::onDecoded;
+        return rspHeadersConsumer;
+    }
+
+    String checkInterimResponseCountExceeded() {
+        // this is also checked by Exchange - but tracking it here too provides
+        // a more informative message.
+        int count = nonFinalResponseCount.incrementAndGet();
+        if (MAX_NON_FINAL_RESPONSES > 0 && (count < 0 || count > MAX_NON_FINAL_RESPONSES)) {
+            return String.format(
+                    "Stream %s PROTOCOL_ERROR: too many interim responses received: %s > %s",
+                    streamid, count, MAX_NON_FINAL_RESPONSES);
+        }
+        return null;
     }
 
     protected void handleResponse(HeaderFrame hf) throws IOException {
         HttpHeaders responseHeaders = responseHeadersBuilder.build();
 
         if (!finalResponseCodeReceived) {
-            responseCode = (int) responseHeaders
-                    .firstValueAsLong(":status")
-                    .orElseThrow(() -> new IOException("no statuscode in response"));
+            try {
+                responseCode = (int) responseHeaders
+                        .firstValueAsLong(":status")
+                        .orElseThrow(() -> new ProtocolException(String.format(
+                                "Stream %s PROTOCOL_ERROR: no status code in response",
+                                streamid)));
+            } catch (ProtocolException cause) {
+                cancelImpl(cause, ResetFrame.PROTOCOL_ERROR);
+                rspHeadersConsumer.reset();
+                return;
+            }
+
+            String protocolErrorMsg = null;
             // If informational code, response is partially complete
             if (responseCode < 100 || responseCode > 199) {
                 this.finalResponseCodeReceived = true;
@@ -537,23 +567,31 @@ class Stream<T> extends ExchangeImpl<T> {
                 // see RFC 9113 section 8.1:
                 // A HEADERS frame with the END_STREAM flag set that carries an
                 // informational status code is malformed
-                String msg = ("Stream %s PROTOCOL_ERROR: " +
-                        "HEADERS frame with status %s has END_STREAM flag set")
-                        .formatted(streamid, responseCode);
+                protocolErrorMsg = String.format(
+                        "Stream %s PROTOCOL_ERROR: " +
+                        "HEADERS frame with status %s has END_STREAM flag set",
+                        streamid, responseCode);
+            } else {
+                protocolErrorMsg = checkInterimResponseCountExceeded();
+            }
+
+            if (protocolErrorMsg != null) {
                 if (debug.on()) {
-                    debug.log(msg);
+                    debug.log(protocolErrorMsg);
                 }
-                cancelImpl(new IOException(msg), ResetFrame.PROTOCOL_ERROR);
+                cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
+                rspHeadersConsumer.reset();
+                return;
             }
 
             response = new Response(
                     request, exchange, responseHeaders, connection(),
                     responseCode, HttpClient.Version.HTTP_2);
 
-        /* TODO: review if needs to be removed
-           the value is not used, but in case `content-length` doesn't parse as
-           long, there will be NumberFormatException. If left as is, make sure
-           code up the stack handles NFE correctly. */
+            /* TODO: review if needs to be removed
+               the value is not used, but in case `content-length` doesn't parse as
+               long, there will be NumberFormatException. If left as is, make sure
+               code up the stack handles NFE correctly. */
             responseHeaders.firstValueAsLong("content-length");
 
             if (Log.headers()) {
@@ -572,6 +610,15 @@ class Stream<T> extends ExchangeImpl<T> {
                 Log.dumpHeaders(sb, "    ", responseHeaders);
                 Log.logHeaders(sb.toString());
             }
+            if (trailerReceived) {
+                String protocolErrorMsg = String.format(
+                        "Stream %s PROTOCOL_ERROR: trailers already received", streamid);
+                if (debug.on()) {
+                    debug.log(protocolErrorMsg);
+                }
+                cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
+            }
+            trailerReceived = true;
             rspHeadersConsumer.reset();
         }
 
@@ -1182,7 +1229,7 @@ class Stream<T> extends ExchangeImpl<T> {
 
     /**
      * A List of responses relating to this stream. Normally there is only
-     * one response, but intermediate responses like 100 are allowed
+     * one response, but interim responses like 100 are allowed
      * and must be passed up to higher level before continuing. Deals with races
      * such as if responses are returned before the CFs get created by
      * getResponseAsync()
@@ -1401,7 +1448,7 @@ class Stream<T> extends ExchangeImpl<T> {
         cancelImpl(e, ResetFrame.CANCEL);
     }
 
-    private void cancelImpl(final Throwable e, final int resetFrameErrCode) {
+    void cancelImpl(final Throwable e, final int resetFrameErrCode) {
         errorRef.compareAndSet(null, e);
         if (debug.on()) {
             if (streamid == 0) debug.log("cancelling stream: %s", (Object)e);
@@ -1511,6 +1558,7 @@ class Stream<T> extends ExchangeImpl<T> {
     }
 
     static class PushedStream<T> extends Stream<T> {
+        final Stream<T> parent;
         final PushGroup<T> pushGroup;
         // push streams need the response CF allocated up front as it is
         // given directly to user via the multi handler callback function.
@@ -1520,16 +1568,17 @@ class Stream<T> extends ExchangeImpl<T> {
         volatile HttpResponse.BodyHandler<T> pushHandler;
         private volatile boolean finalPushResponseCodeReceived;
 
-        PushedStream(PushGroup<T> pushGroup,
+        PushedStream(Stream<T> parent,
+                     PushGroup<T> pushGroup,
                      Http2Connection connection,
                      Exchange<T> pushReq) {
             // ## no request body possible, null window controller
             super(connection, pushReq, null);
+            this.parent = parent;
             this.pushGroup = pushGroup;
             this.pushReq = pushReq.request();
             this.pushCF = new MinimalFuture<>();
             this.responseCF = new MinimalFuture<>();
-
         }
 
         CompletableFuture<HttpResponse<T>> responseCF() {
@@ -1617,7 +1666,16 @@ class Stream<T> extends ExchangeImpl<T> {
                     .orElse(-1);
 
                 if (responseCode == -1) {
-                    completeResponseExceptionally(new IOException("No status code"));
+                    cancelImpl(new ProtocolException("No status code"), ResetFrame.PROTOCOL_ERROR);
+                    rspHeadersConsumer.reset();
+                    return;
+                } else if (responseCode >= 100 && responseCode < 200) {
+                    String protocolErrorMsg = checkInterimResponseCountExceeded();
+                    if (protocolErrorMsg != null) {
+                        cancelImpl(new ProtocolException(protocolErrorMsg), ResetFrame.PROTOCOL_ERROR);
+                        rspHeadersConsumer.reset();
+                        return;
+                    }
                 }
 
                 this.finalPushResponseCodeReceived = true;
@@ -1727,7 +1785,9 @@ class Stream<T> extends ExchangeImpl<T> {
         }
     }
 
-    private class HeadersConsumer extends ValidatingHeadersConsumer {
+    private class HeadersConsumer extends ValidatingHeadersConsumer implements DecodingCallback {
+
+        boolean maxHeaderListSizeReached;
 
         @Override
         public void reset() {
@@ -1740,6 +1800,9 @@ class Stream<T> extends ExchangeImpl<T> {
         public void onDecoded(CharSequence name, CharSequence value)
             throws UncheckedIOException
         {
+            if (maxHeaderListSizeReached) {
+                return;
+            }
             try {
                 String n = name.toString();
                 String v = value.toString();
@@ -1762,6 +1825,23 @@ class Stream<T> extends ExchangeImpl<T> {
         protected String formatMessage(String message, String header) {
             return "malformed response: " + super.formatMessage(message, header);
         }
+
+        @Override
+        public void onMaxHeaderListSizeReached(long size, int maxHeaderListSize) throws ProtocolException {
+            if (maxHeaderListSizeReached) return;
+            try {
+                DecodingCallback.super.onMaxHeaderListSizeReached(size, maxHeaderListSize);
+            } catch (ProtocolException cause) {
+                maxHeaderListSizeReached = true;
+                // If this is a push stream: cancel the parent.
+                if (Stream.this instanceof Stream.PushedStream<?> ps) {
+                    ps.parent.onProtocolError(cause);
+                }
+                // cancel the stream, continue processing
+                onProtocolError(cause);
+                reset();
+            }
+        }
     }
 
     final class Http2StreamResponseSubscriber<U> extends HttpBodySubscriberWrapper<U> {
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java
index 62d03844d2e..d81f52e6630 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/HeaderDecoder.java
@@ -39,7 +39,11 @@ public class HeaderDecoder extends ValidatingHeadersConsumer {
         String n = name.toString();
         String v = value.toString();
         super.onDecoded(n, v);
-        headersBuilder.addHeader(n, v);
+        addHeader(n, v);
+    }
+
+    protected void addHeader(String name, String value) {
+        headersBuilder.addHeader(name, value);
     }
 
     public HttpHeaders headers() {
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
index b2eb570db0c..49e669e5add 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
@@ -616,6 +616,19 @@ public final class Utils {
                 Integer.parseInt(System.getProperty(name, String.valueOf(defaultValue))));
     }
 
+    public static int getIntegerNetProperty(String property, int min, int max, int defaultValue, boolean log) {
+        int value =  Utils.getIntegerNetProperty(property, defaultValue);
+        // use default value if misconfigured
+        if (value < min || value > max) {
+            if (log && Log.errors()) {
+                Log.logError("Property value for {0}={1} not in [{2}..{3}]: " +
+                        "using default={4}", property, value, min, max, defaultValue);
+            }
+            value = defaultValue;
+        }
+        return value;
+    }
+
     public static SSLParameters copySSLParameters(SSLParameters p) {
         SSLParameters p1 = new SSLParameters();
         p1.setAlgorithmConstraints(p.getAlgorithmConstraints());
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java
index 9d57a734ac3..881be12c67c 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Decoder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@ package jdk.internal.net.http.hpack;
 import jdk.internal.net.http.hpack.HPACK.Logger;
 
 import java.io.IOException;
+import java.net.ProtocolException;
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicLong;
@@ -107,12 +108,16 @@ public final class Decoder {
     private final StringReader stringReader;
     private final StringBuilder name;
     private final StringBuilder value;
+    private final int maxHeaderListSize;
+    private final int maxIndexed;
     private int intValue;
     private boolean firstValueRead;
     private boolean firstValueIndex;
     private boolean nameHuffmanEncoded;
     private boolean valueHuffmanEncoded;
     private int capacity;
+    private long size;
+    private int indexed;
 
     /**
      * Constructs a {@code Decoder} with the specified initial capacity of the
@@ -129,6 +134,31 @@ public final class Decoder {
      *         if capacity is negative
      */
     public Decoder(int capacity) {
+        this(capacity, 0, 0);
+    }
+
+    /**
+     * Constructs a {@code Decoder} with the specified initial capacity of the
+     * header table, a max header list size, and a maximum number of literals
+     * with indexing per header section.
+     *
+     * <p> The value of the capacity has to be agreed between decoder and encoder out-of-band,
+     * e.g. by a protocol that uses HPACK
+     * (see <a href="https://tools.ietf.org/html/rfc7541#section-4.2">4.2. Maximum Table Size</a>).
+     *
+     * @param capacity
+     *         a non-negative integer
+     * @param maxHeaderListSize
+     *         a maximum value for the header list size. This is the uncompressed
+     *         names size + uncompressed values size + 32 bytes per field line
+     * @param maxIndexed
+     *         the maximum number of literal with indexing we're prepared to handle
+     *         for a header field section
+     *
+     * @throws IllegalArgumentException
+     *         if capacity is negative
+     */
+    public Decoder(int capacity, int maxHeaderListSize, int maxIndexed) {
         id = DECODERS_IDS.incrementAndGet();
         logger = HPACK.getLogger().subLogger("Decoder#" + id);
         if (logger.isLoggable(NORMAL)) {
@@ -145,6 +175,8 @@ public final class Decoder {
                               toString(), hashCode);
             });
         }
+        this.maxHeaderListSize = maxHeaderListSize;
+        this.maxIndexed = maxIndexed;
         setMaxCapacity0(capacity);
         table = new SimpleHeaderTable(capacity, logger.subLogger("HeaderTable"));
         integerReader = new IntegerReader();
@@ -242,22 +274,25 @@ public final class Decoder {
         requireNonNull(consumer, "consumer");
         if (logger.isLoggable(NORMAL)) {
             logger.log(NORMAL, () -> format("reading %s, end of header block? %s",
-                                            headerBlock, endOfHeaderBlock));
+                    headerBlock, endOfHeaderBlock));
         }
         while (headerBlock.hasRemaining()) {
             proceed(headerBlock, consumer);
         }
         if (endOfHeaderBlock && state != State.READY) {
             logger.log(NORMAL, () -> format("unexpected end of %s representation",
-                                            state));
+                    state));
             throw new IOException("Unexpected end of header block");
         }
+        if (endOfHeaderBlock) {
+            size = indexed = 0;
+        }
     }
 
     private void proceed(ByteBuffer input, DecodingCallback action)
             throws IOException {
         switch (state) {
-            case READY                  ->  resumeReady(input);
+            case READY                  ->  resumeReady(input, action);
             case INDEXED                ->  resumeIndexed(input, action);
             case LITERAL                ->  resumeLiteral(input, action);
             case LITERAL_WITH_INDEXING  ->  resumeLiteralWithIndexing(input, action);
@@ -268,7 +303,7 @@ public final class Decoder {
         }
     }
 
-    private void resumeReady(ByteBuffer input) {
+    private void resumeReady(ByteBuffer input, DecodingCallback action) throws IOException {
         int b = input.get(input.position()) & 0xff; // absolute read
         State s = states.get(b);
         if (logger.isLoggable(EXTRA)) {
@@ -289,6 +324,9 @@ public final class Decoder {
                 }
                 break;
             case LITERAL_WITH_INDEXING:
+                if (maxIndexed > 0 && ++indexed > maxIndexed) {
+                    action.onMaxLiteralWithIndexingReached(indexed, maxIndexed);
+                }
                 state = State.LITERAL_WITH_INDEXING;
                 firstValueIndex = (b & 0b0011_1111) != 0;
                 if (firstValueIndex) {
@@ -315,6 +353,12 @@ public final class Decoder {
         }
     }
 
+    private void checkMaxHeaderListSize(long sz, DecodingCallback consumer) throws ProtocolException {
+        if (maxHeaderListSize > 0 && sz > maxHeaderListSize) {
+            consumer.onMaxHeaderListSizeReached(sz, maxHeaderListSize);
+        }
+    }
+
     //              0   1   2   3   4   5   6   7
     //            +---+---+---+---+---+---+---+---+
     //            | 1 |        Index (7+)         |
@@ -332,6 +376,8 @@ public final class Decoder {
         }
         try {
             SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
+            size = size + 32 + f.name.length() + f.value.length();
+            checkMaxHeaderListSize(size, action);
             action.onIndexed(intValue, f.name, f.value);
         } finally {
             state = State.READY;
@@ -374,7 +420,7 @@ public final class Decoder {
     //
     private void resumeLiteral(ByteBuffer input, DecodingCallback action)
             throws IOException {
-        if (!completeReading(input)) {
+        if (!completeReading(input, action)) {
             return;
         }
         try {
@@ -385,6 +431,8 @@ public final class Decoder {
                             intValue, value, valueHuffmanEncoded));
                 }
                 SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
+                size = size + 32 + f.name.length() + value.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteral(intValue, f.name, value, valueHuffmanEncoded);
             } else {
                 if (logger.isLoggable(NORMAL)) {
@@ -392,6 +440,8 @@ public final class Decoder {
                             "literal without indexing ('%s', huffman=%b, '%s', huffman=%b)",
                             name, nameHuffmanEncoded, value, valueHuffmanEncoded));
                 }
+                size = size + 32 + name.length() + value.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteral(name, nameHuffmanEncoded, value, valueHuffmanEncoded);
             }
         } finally {
@@ -425,7 +475,7 @@ public final class Decoder {
     private void resumeLiteralWithIndexing(ByteBuffer input,
                                            DecodingCallback action)
             throws IOException {
-        if (!completeReading(input)) {
+        if (!completeReading(input, action)) {
             return;
         }
         try {
@@ -445,6 +495,8 @@ public final class Decoder {
                 }
                 SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
                 n = f.name;
+                size = size + 32 + n.length() + v.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteralWithIndexing(intValue, n, v, valueHuffmanEncoded);
             } else {
                 n = name.toString();
@@ -453,6 +505,8 @@ public final class Decoder {
                             "literal with incremental indexing ('%s', huffman=%b, '%s', huffman=%b)",
                             n, nameHuffmanEncoded, value, valueHuffmanEncoded));
                 }
+                size = size + 32 + n.length() + v.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteralWithIndexing(n, nameHuffmanEncoded, v, valueHuffmanEncoded);
             }
             table.put(n, v);
@@ -486,7 +540,7 @@ public final class Decoder {
     private void resumeLiteralNeverIndexed(ByteBuffer input,
                                            DecodingCallback action)
             throws IOException {
-        if (!completeReading(input)) {
+        if (!completeReading(input, action)) {
             return;
         }
         try {
@@ -497,6 +551,8 @@ public final class Decoder {
                             intValue, value, valueHuffmanEncoded));
                 }
                 SimpleHeaderTable.HeaderField f = getHeaderFieldAt(intValue);
+                size = size + 32 + f.name.length() + value.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteralNeverIndexed(intValue, f.name, value, valueHuffmanEncoded);
             } else {
                 if (logger.isLoggable(NORMAL)) {
@@ -504,6 +560,8 @@ public final class Decoder {
                             "literal never indexed ('%s', huffman=%b, '%s', huffman=%b)",
                             name, nameHuffmanEncoded, value, valueHuffmanEncoded));
                 }
+                size = size + 32 + name.length() + value.length();
+                checkMaxHeaderListSize(size, action);
                 action.onLiteralNeverIndexed(name, nameHuffmanEncoded, value, valueHuffmanEncoded);
             }
         } finally {
@@ -541,7 +599,7 @@ public final class Decoder {
         }
     }
 
-    private boolean completeReading(ByteBuffer input) throws IOException {
+    private boolean completeReading(ByteBuffer input, DecodingCallback action) throws IOException {
         if (!firstValueRead) {
             if (firstValueIndex) {
                 if (!integerReader.read(input)) {
@@ -551,6 +609,8 @@ public final class Decoder {
                 integerReader.reset();
             } else {
                 if (!stringReader.read(input, name)) {
+                    long sz = size + 32 + name.length();
+                    checkMaxHeaderListSize(sz, action);
                     return false;
                 }
                 nameHuffmanEncoded = stringReader.isHuffmanEncoded();
@@ -560,6 +620,8 @@ public final class Decoder {
             return false;
         } else {
             if (!stringReader.read(input, value)) {
+                long sz = size + 32 + name.length() + value.length();
+                checkMaxHeaderListSize(sz, action);
                 return false;
             }
         }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java
index 5e9df860feb..228f9bf0206 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/DecodingCallback.java
@@ -24,6 +24,7 @@
  */
 package jdk.internal.net.http.hpack;
 
+import java.net.ProtocolException;
 import java.nio.ByteBuffer;
 
 /**
@@ -292,4 +293,17 @@ public interface DecodingCallback {
      *         new capacity of the header table
      */
     default void onSizeUpdate(int capacity) { }
+
+    default void onMaxHeaderListSizeReached(long size, int maxHeaderListSize)
+        throws ProtocolException {
+        throw new ProtocolException(String
+                .format("Size exceeds MAX_HEADERS_LIST_SIZE: %s > %s",
+                        size, maxHeaderListSize));
+    }
+
+    default void onMaxLiteralWithIndexingReached(long indexed, int maxIndexed)
+            throws ProtocolException {
+        throw new ProtocolException(String.format("Too many literal with indexing: %s > %s",
+                indexed, maxIndexed));
+    }
 }
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java
index 4188937b1ad..c603e917ca4 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/hpack/Encoder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -258,9 +258,10 @@ public class Encoder {
                 }
             }
         }
+        assert encoding : "encoding is false";
     }
 
-    private boolean isHuffmanBetterFor(CharSequence value) {
+    protected final boolean isHuffmanBetterFor(CharSequence value) {
         // prefer Huffman encoding only if it is strictly smaller than Latin-1
         return huffmanWriter.lengthOf(value) < value.length();
     }
@@ -340,6 +341,10 @@ public class Encoder {
         return 0;
     }
 
+    protected final int tableIndexOf(CharSequence name, CharSequence value) {
+        return getHeaderTable().indexOf(name, value);
+    }
+
     /**
      * Encodes the {@linkplain #header(CharSequence, CharSequence) set up}
      * header into the given buffer.
@@ -380,6 +385,7 @@ public class Encoder {
             writer.reset(); // FIXME: WHY?
             encoding = false;
         }
+        assert done || encoding : "done: " + done + ", encoding: " + encoding;
         return done;
     }
 
@@ -542,4 +548,8 @@ public class Encoder {
                     "Previous encoding operation hasn't finished yet");
         }
     }
+
+    protected final Logger logger() {
+        return logger;
+    }
 }
diff --git a/src/java.net.http/share/classes/module-info.java b/src/java.net.http/share/classes/module-info.java
index cf9d07bdf32..5303e818866 100644
--- a/src/java.net.http/share/classes/module-info.java
+++ b/src/java.net.http/share/classes/module-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -115,6 +115,25 @@
  * The HTTP/2 client maximum frame size in bytes. The server is not permitted to send a frame
  * larger than this.
  * </li>
+ * <li><p><b>{@systemProperty jdk.httpclient.maxLiteralWithIndexing}</b> (default: 512)<br>
+ * The maximum number of header field lines (header name and value pairs) that a
+ * client is willing to add to the HPack Decoder dynamic table during the decoding
+ * of an entire header field section.
+ * This is purely an implementation limit.
+ * If a peer sends a field section with encoding that
+ * exceeds this limit a {@link java.net.ProtocolException ProtocolException} will be raised.
+ * A value of zero or a negative value means no limit.
+ * </li>
+ * <li><p><b>{@systemProperty jdk.httpclient.maxNonFinalResponses}</b> (default: 8)<br>
+ * The maximum number of interim (non-final) responses that a client is prepared
+ * to accept on a request-response stream before the final response is received.
+ * Interim responses are responses with a status in the range [100, 199] inclusive.
+ * This is purely an implementation limit.
+ * If a peer sends a number of interim response that exceeds this limit before
+ * sending the final response, a {@link java.net.ProtocolException ProtocolException}
+ * will be raised.
+ * A value of zero or a negative value means no limit.
+ * </li>
  * <li><p><b>{@systemProperty jdk.httpclient.maxstreams}</b> (default: 100)<br>
  * The maximum number of HTTP/2 push streams that the client will permit servers to open
  * simultaneously.
@@ -155,6 +174,15 @@
  * conf/net.properties)<br>A comma separated list of HTTP authentication scheme names, that
  * are disallowed for use by the HTTP client implementation, for HTTP CONNECT tunneling.
  * </li>
+ * <li><p><b>{@systemProperty jdk.http.maxHeaderSize}</b> (default: 393216 or 384kB)
+ * <br>The maximum header field section size that the client is prepared to accept.
+ * This is computed as the sum of the size of the uncompressed header name, plus
+ * the size of the uncompressed header value, plus an overhead of 32 bytes for
+ * each field section line. If a peer sends a field section that exceeds this
+ * size a {@link java.net.ProtocolException ProtocolException} will be raised.
+ * This applies to all versions of the protocol. A value of zero or a negative
+ * value means no limit.
+ * </li>
  * </ul>
  * @moduleGraph
  * @since 11
diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java
index 5a6f74e130c..6140168ebbb 100644
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/EncryptionKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -170,7 +170,7 @@ public final class EncryptionKey implements SecretKey {
         if (destroyed) {
             return "Destroyed EncryptionKey";
         }
-        return "key "  + key.toString();
+        return "EncryptionKey: " + key.toString();
     }
 
     /**
diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java
index c6f3f083a66..c331833e9f0 100644
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosCredMessage.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@ package javax.security.auth.kerberos;
 
 import javax.security.auth.Destroyable;
 import java.util.Arrays;
-import java.util.Base64;
 import java.util.Objects;
 
 /**
@@ -140,8 +139,7 @@ public final class KerberosCredMessage implements Destroyable {
         if (destroyed) {
             return "Destroyed KerberosCredMessage";
         } else {
-            return "KRB_CRED from " + sender + " to " + recipient + ":\n"
-                    + Base64.getUrlEncoder().encodeToString(message);
+            return "KRB_CRED from " + sender + " to " + recipient;
         }
     }
 
diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java
index 55c1be3c0d8..71aaddda9de 100644
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KerberosKey.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -273,9 +273,9 @@ public class KerberosKey implements SecretKey {
         if (destroyed) {
             return "Destroyed KerberosKey";
         }
-        return "Kerberos Principal " + principal +
-                "Key Version " + versionNum +
-                "key "  + key.toString();
+        return "KerberosKey: principal " + principal +
+                ", version " + versionNum +
+                ", key "  + key.toString();
     }
 
     /**
diff --git a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java
index 46168cf8377..b18f7d8eae1 100644
--- a/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java
+++ b/src/java.security.jgss/share/classes/javax/security/auth/kerberos/KeyImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,8 @@ import java.util.Arrays;
 import javax.crypto.SecretKey;
 import javax.security.auth.Destroyable;
 import javax.security.auth.DestroyFailedException;
-import sun.security.util.HexDumpEncoder;
+
+import sun.security.jgss.krb5.Krb5Util;
 import sun.security.krb5.Asn1Exception;
 import sun.security.krb5.PrincipalName;
 import sun.security.krb5.EncryptionKey;
@@ -225,15 +226,8 @@ class KeyImpl implements SecretKey, Destroyable, Serializable {
     }
 
     public String toString() {
-        HexDumpEncoder hd = new HexDumpEncoder();
-        return "EncryptionKey: keyType=" + keyType
-                          + " keyBytes (hex dump)="
-                          + (keyBytes == null || keyBytes.length == 0 ?
-                             " Empty Key" :
-                             '\n' + hd.encodeBuffer(keyBytes)
-                          + '\n');
-
-
+        return "keyType=" + keyType
+                + ", " + Krb5Util.keyInfo(keyBytes);
     }
 
     public int hashCode() {
diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
index fa596fc6a1e..92b694efb86 100644
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Context.java
@@ -33,8 +33,10 @@ import sun.security.jgss.spi.*;
 import sun.security.jgss.TokenTracker;
 import sun.security.krb5.*;
 import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.InvalidObjectException;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.OutputStream;
 import java.security.*;
 import javax.security.auth.Subject;
 import javax.security.auth.kerberos.ServicePermission;
@@ -899,15 +901,11 @@ class Krb5Context implements GSSContextSpi {
 
     public final byte[] wrap(byte[] inBuf, int offset, int len,
                              MessageProp msgProp) throws GSSException {
-        if (DEBUG != null) {
-            DEBUG.println("Krb5Context.wrap: data=["
-                               + getHexBytes(inBuf, offset, len)
-                               + "]");
-        }
 
-        if (state != STATE_DONE)
-        throw new GSSException(GSSException.NO_CONTEXT, -1,
-                               "Wrap called in invalid state!");
+        if (state != STATE_DONE) {
+            throw new GSSException(GSSException.NO_CONTEXT, -1,
+                    "Wrap called in invalid state!");
+        }
 
         byte[] encToken = null;
         try {
@@ -1050,12 +1048,6 @@ class Krb5Context implements GSSContextSpi {
                 setSequencingAndReplayProps(token, msgProp);
             }
 
-            if (DEBUG != null) {
-                DEBUG.println("Krb5Context.unwrap: data=["
-                                   + getHexBytes(data, 0, data.length)
-                                   + "]");
-            }
-
             return data;
         }
 
@@ -1405,8 +1397,22 @@ class Krb5Context implements GSSContextSpi {
 
         @Override
         public String toString() {
-            return "Kerberos session key: etype: " + key.getEType() + "\n" +
-                    new HexDumpEncoder().encodeBuffer(key.getBytes());
+            return "Kerberos session key: etype=" + key.getEType()
+                    + ", " + Krb5Util.keyInfo(key.getBytes());
+        }
+
+        /**
+         * Restores the state of this object from the stream.
+         *
+         * @param  stream the {@code ObjectInputStream} from which data is read
+         * @throws IOException if an I/O error occurs
+         * @throws ClassNotFoundException if a serialized class cannot be loaded
+         */
+        @java.io.Serial
+        private void readObject(ObjectInputStream stream)
+                throws IOException, ClassNotFoundException {
+            throw new InvalidObjectException
+                    ("KerberosSessionKey not directly deserializable");
         }
     }
 
@@ -1477,5 +1483,4 @@ class Krb5Context implements GSSContextSpi {
     public void setAuthzData(AuthorizationData authzData) {
         this.authzData = authzData;
     }
-
 }
diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
index 1b109cc881f..4cc306282e6 100644
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5InitCredential.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,9 @@ import javax.security.auth.kerberos.KerberosTicket;
 import javax.security.auth.kerberos.KerberosPrincipal;
 import java.io.Serial;
 import java.net.InetAddress;
+import java.io.InvalidObjectException;
 import java.io.IOException;
+import java.io.ObjectInputStream;
 import java.util.Date;
 import java.security.AccessController;
 import java.security.PrivilegedExceptionAction;
@@ -400,4 +402,17 @@ public class Krb5InitCredential
             throw ge;
         }
     }
+
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  stream the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        throw new InvalidObjectException("Krb5InitCredential not deserializable");
+    }
 }
diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java
index 10dea6749e5..e784b7b33ca 100644
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/Krb5Util.java
@@ -187,4 +187,19 @@ public class Krb5Util {
             KeyTab ktab, PrincipalName cname) {
         return snapshotFromJavaxKeyTab(ktab).readServiceKeys(cname);
     }
+
+    public static String keyInfo(byte[] data) {
+        if (data == null) {
+            return "null key";
+        } else if (data.length == 0) {
+            return "empty key";
+        } else {
+            for (byte b : data) {
+                if (b != 0) {
+                    return data.length + "-byte key";
+                }
+            }
+            return data.length + "-byte zero key";
+        }
+    }
 }
diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java
index f975ba15a67..b5453fae916 100644
--- a/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/EncryptionKey.java
@@ -31,6 +31,7 @@
 
 package sun.security.krb5;
 
+import sun.security.jgss.krb5.Krb5Util;
 import sun.security.util.*;
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.crypto.*;
@@ -498,12 +499,7 @@ public class EncryptionKey
 
     public String toString() {
         return "EncryptionKey: keyType=" + keyType
-                + " kvno=" + kvno
-                + " keyValue (hex dump)="
-                + (keyValue == null || keyValue.length == 0 ?
-                " Empty Key" : '\n'
-                + Krb5.hexDumper.encodeBuffer(keyValue)
-                + '\n');
+                + ", kvno=" + kvno + ", " + Krb5Util.keyInfo(keyValue);
     }
 
     /**
diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
index b93ced00c65..db6192ce9ee 100644
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/KRBError.java
@@ -83,28 +83,36 @@ import static sun.security.krb5.internal.Krb5.DEBUG;
  * <a href="http://www.ietf.org/rfc/rfc4120.txt">
  * http://www.ietf.org/rfc/rfc4120.txt</a>.
  */
-// The instance fields not statically typed as Serializable are ASN.1
-// encoded and written by the writeObject method.
-@SuppressWarnings("serial")
+
 public class KRBError implements java.io.Serializable {
     static final long serialVersionUID = 3643809337475284503L;
 
-    private int pvno;
-    private int msgType;
-    private KerberosTime cTime; //optional
-    private Integer cuSec; //optional
-    private KerberosTime sTime;
-    private Integer suSec;
-    private int errorCode;
-    private Realm crealm; //optional
-    private PrincipalName cname; //optional
-    private PrincipalName sname;
-    private String eText; //optional
-    private byte[] eData; //optional
-    private Checksum eCksum; //optional
+    private transient int pvno;
+    private transient int msgType;
+    private transient KerberosTime cTime; //optional
+    private transient Integer cuSec; //optional
+    private transient KerberosTime sTime;
+    private transient Integer suSec;
+    private transient int errorCode;
+    private transient Realm crealm; //optional
+    private transient PrincipalName cname; //optional
+    private transient PrincipalName sname;
+    private transient String eText; //optional
+    private transient byte[] eData; //optional
+    private transient Checksum eCksum; //optional
 
-    private PAData[] pa;    // PA-DATA in eData
+    private transient PAData[] pa;    // PA-DATA in eData
 
+
+
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  is the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
     private void readObject(ObjectInputStream is)
             throws IOException, ClassNotFoundException {
         try {
diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java
index c3cac113c40..0850abb53c8 100644
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/Krb5.java
@@ -320,9 +320,6 @@ public class Krb5 {
     public static final Debug DEBUG = Debug.of("krb5", GetPropertyAction
             .privilegedGetProperty("sun.security.krb5.debug"));
 
-    public static final sun.security.util.HexDumpEncoder hexDumper =
-        new sun.security.util.HexDumpEncoder();
-
     static {
         errMsgList = new Hashtable<Integer,String> ();
         errMsgList.put(KDC_ERR_NONE, "No error");
diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
index 9d24de5c2e6..6b9f5de0c3d 100644
--- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
+++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java
@@ -195,10 +195,6 @@ public class Kinit {
                 System.out.print("Password for " + princName + ":");
                 System.out.flush();
                 psswd = Password.readPassword(System.in);
-                if (DEBUG != null) {
-                    DEBUG.println(">>> Kinit console input " +
-                        new String(psswd));
-                }
             }
             builder = new KrbAsReqBuilder(principal, psswd);
         } else {
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
index d528f1b8485..49718e254b3 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
@@ -240,6 +240,19 @@ abstract class P11Key implements Key, Length {
         return new KeyRep(type, getAlgorithm(), format, getEncodedInternal());
     }
 
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  stream the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        throw new InvalidObjectException("P11Key not directly deserializable");
+    }
+
     public String toString() {
         token.ensureValid();
         String s1 = token.provider.getName() + " " + algorithm + " " + type
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
index 70effc141bc..7ef8510ddee 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecureRandom.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -187,9 +187,23 @@ final class P11SecureRandom extends SecureRandomSpi {
         }
     }
 
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  in the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
     private void readObject(ObjectInputStream in)
             throws IOException, ClassNotFoundException {
         in.defaultReadObject();
+        if (token == null) {
+            throw new InvalidObjectException("token is null");
+        }
+        if (mixBuffer != null) {
+            mixBuffer = mixBuffer.clone();
+        }
         // assign default values to non-null transient fields
         iBuffer = new byte[IBUFFER_SIZE];
         ibuffered = 0;
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
index 44a2c4efb06..e77edc98399 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java
@@ -1947,6 +1947,19 @@ public final class SunPKCS11 extends AuthProvider {
         return new SunPKCS11Rep(this);
     }
 
+    /**
+     * Restores the state of this object from the stream.
+     *
+     * @param  stream the {@code ObjectInputStream} from which data is read
+     * @throws IOException if an I/O error occurs
+     * @throws ClassNotFoundException if a serialized class cannot be loaded
+     */
+    @java.io.Serial
+    private void readObject(ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        throw new InvalidObjectException("SunPKCS11 not directly deserializable");
+    }
+
     /**
      * Serialized representation of the SunPKCS11 provider.
      */
diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
index a25fa1c39e5..d6c291ebc57 100644
--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
+++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_PBE_PARAMS.java
@@ -127,11 +127,6 @@ public class CK_PBE_PARAMS {
         sb.append(pPassword.length);
         sb.append(Constants.NEWLINE);
 
-        sb.append(Constants.INDENT);
-        sb.append("pPassword: ");
-        sb.append(pPassword);
-        sb.append(Constants.NEWLINE);
-
         sb.append(Constants.INDENT);
         sb.append("ulSaltLen: ");
         sb.append(pSalt.length);
diff --git a/src/jdk.httpserver/share/classes/module-info.java b/src/jdk.httpserver/share/classes/module-info.java
index 46dbb6ea64f..23e04405ee8 100644
--- a/src/jdk.httpserver/share/classes/module-info.java
+++ b/src/jdk.httpserver/share/classes/module-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,6 +70,16 @@
  * while the headers are being read, then the connection is terminated and the request ignored.
  * If the value is less than or equal to zero, then the default value is used.
  * </li>
+ * <li><p><b>{@systemProperty sun.net.httpserver.maxReqHeaderSize}</b> (default: 393216 or 384kB)<br>
+ *  The maximum header field section size that the server is prepared to accept.
+ *  This is computed as the sum of the size of the header name, plus
+ *  the size of the header value, plus an overhead of 32 bytes for
+ *  each field section line. The request line counts as a first field section line,
+ *  where the name is empty and the value is the whole line.
+ *  If this limit is exceeded while the headers are being read, then the connection
+ *  is terminated and the request ignored.
+ *  If the value is less than or equal to zero, there is no limit.
+ * </li>
  * <li><p><b>{@systemProperty sun.net.httpserver.maxReqTime}</b> (default: -1)<br>
  * The maximum time in milliseconds allowed to receive a request headers and body.
  * In practice, the actual time is a function of request size, network speed, and handler
diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java
index 99dac0547ce..6c0c2c271ed 100644
--- a/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java
+++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/Request.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -44,8 +44,10 @@ class Request {
     private SocketChannel chan;
     private InputStream is;
     private OutputStream os;
+    private final int maxReqHeaderSize;
 
     Request (InputStream rawInputStream, OutputStream rawout) throws IOException {
+        this.maxReqHeaderSize = ServerConfig.getMaxReqHeaderSize();
         is = rawInputStream;
         os = rawout;
         do {
@@ -75,6 +77,7 @@ class Request {
     public String readLine () throws IOException {
         boolean gotCR = false, gotLF = false;
         pos = 0; lineBuf = new StringBuffer();
+        long lsize = 32;
         while (!gotLF) {
             int c = is.read();
             if (c == -1) {
@@ -87,20 +90,27 @@ class Request {
                     gotCR = false;
                     consume (CR);
                     consume (c);
+                    lsize = lsize + 2;
                 }
             } else {
                 if (c == CR) {
                     gotCR = true;
                 } else {
                     consume (c);
+                    lsize = lsize + 1;
                 }
             }
+            if (maxReqHeaderSize > 0 && lsize > maxReqHeaderSize) {
+                throw new IOException("Maximum header (" +
+                        "sun.net.httpserver.maxReqHeaderSize) exceeded, " +
+                        ServerConfig.getMaxReqHeaderSize() + ".");
+            }
         }
         lineBuf.append (buf, 0, pos);
         return new String (lineBuf);
     }
 
-    private void consume (int c) {
+    private void consume (int c) throws IOException {
         if (pos == BUF_LEN) {
             lineBuf.append (buf);
             pos = 0;
@@ -138,13 +148,22 @@ class Request {
             len = 1;
             firstc = c;
         }
+        long hsize = startLine.length() + 32L;
 
         while (firstc != LF && firstc != CR && firstc >= 0) {
             int keyend = -1;
             int c;
             boolean inKey = firstc > ' ';
             s[len++] = (char) firstc;
+            hsize = hsize + 1;
     parseloop:{
+                // We start parsing for a new name value pair here.
+                // The max header size includes an overhead of 32 bytes per
+                // name value pair.
+                // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
+                long maxRemaining = maxReqHeaderSize > 0
+                        ? maxReqHeaderSize - hsize - 32
+                        : Long.MAX_VALUE;
                 while ((c = is.read()) >= 0) {
                     switch (c) {
                       /*fallthrough*/
@@ -178,6 +197,11 @@ class Request {
                         s = ns;
                     }
                     s[len++] = (char) c;
+                    if (maxReqHeaderSize > 0 && len > maxRemaining) {
+                        throw new IOException("Maximum header (" +
+                                "sun.net.httpserver.maxReqHeaderSize) exceeded, " +
+                                ServerConfig.getMaxReqHeaderSize() + ".");
+                    }
                 }
                 firstc = -1;
             }
@@ -205,6 +229,13 @@ class Request {
                         "sun.net.httpserver.maxReqHeaders) exceeded, " +
                         ServerConfig.getMaxReqHeaders() + ".");
             }
+            hsize = hsize + len + 32;
+            if (maxReqHeaderSize > 0 && hsize > maxReqHeaderSize) {
+                throw new IOException("Maximum header (" +
+                        "sun.net.httpserver.maxReqHeaderSize) exceeded, " +
+                        ServerConfig.getMaxReqHeaderSize() + ".");
+            }
+
             if (k == null) {  // Headers disallows null keys, use empty string
                 k = "";       // instead to represent invalid key
             }
diff --git a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java
index 21f6165b05e..9186dd4c168 100644
--- a/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java
+++ b/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,6 +49,7 @@ class ServerConfig {
     // timing out request/response if max request/response time is configured
     private static final long DEFAULT_REQ_RSP_TIMER_TASK_SCHEDULE_MILLIS = 1000;
     private static final int  DEFAULT_MAX_REQ_HEADERS = 200;
+    private static final int  DEFAULT_MAX_REQ_HEADER_SIZE = 380 * 1024;
     private static final long DEFAULT_DRAIN_AMOUNT = 64 * 1024;
 
     private static long idleTimerScheduleMillis;
@@ -62,6 +63,9 @@ class ServerConfig {
     private static int maxIdleConnections;
     // The maximum number of request headers allowable
     private static int maxReqHeaders;
+    // a maximum value for the header list size. This is the
+    // names size + values size + 32 bytes per field line
+    private static int maxReqHeadersSize;
     // max time a request or response is allowed to take
     private static long maxReqTime;
     private static long maxRspTime;
@@ -107,6 +111,14 @@ class ServerConfig {
                         maxReqHeaders = DEFAULT_MAX_REQ_HEADERS;
                     }
 
+                    // a value <= 0 means unlimited
+                    maxReqHeadersSize = Integer.getInteger(
+                            "sun.net.httpserver.maxReqHeaderSize",
+                            DEFAULT_MAX_REQ_HEADER_SIZE);
+                    if (maxReqHeadersSize <= 0) {
+                        maxReqHeadersSize = 0;
+                    }
+
                     maxReqTime = Long.getLong("sun.net.httpserver.maxReqTime",
                             DEFAULT_MAX_REQ_TIME);
 
@@ -215,6 +227,10 @@ class ServerConfig {
         return maxReqHeaders;
     }
 
+    static int getMaxReqHeaderSize() {
+        return maxReqHeadersSize;
+    }
+
     /**
      * @return Returns the maximum amount of time the server will wait for the request to be read
      * completely. This method can return a value of 0 or negative to imply no maximum limit has
diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
index 24f26d4364b..18016a07260 100644
--- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
+++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
@@ -43,7 +43,7 @@ import sun.security.krb5.*;
 import sun.security.jgss.krb5.Krb5Util;
 import sun.security.krb5.Credentials;
 import sun.security.util.Debug;
-import sun.security.util.HexDumpEncoder;
+
 import static sun.security.util.ResourcesMgr.getAuthResourceString;
 
 /**
@@ -769,15 +769,11 @@ public class Krb5LoginModule implements LoginModule {
 
                 if (debug != null) {
                     debug.println("principal is " + principal);
-                    HexDumpEncoder hd = new HexDumpEncoder();
                     if (ktab != null) {
                         debug.println("Will use keytab");
                     } else if (storeKey) {
                         for (int i = 0; i < encKeys.length; i++) {
-                            debug.println("EncryptionKey: keyType=" +
-                                encKeys[i].getEType() +
-                                " keyBytes (hex dump)=" +
-                                hd.encodeBuffer(encKeys[i].getBytes()));
+                            debug.println(encKeys[i].toString());
                         }
                     }
                 }
@@ -868,7 +864,7 @@ public class Krb5LoginModule implements LoginModule {
             }
             if (debug != null) {
                 debug.println
-                    ("password is " + new String(password));
+                    ("Get password from shared state");
             }
             return;
         }
diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java
index b68ddfe2799..2fdbb0816ad 100644
--- a/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java
+++ b/test/hotspot/jtreg/compiler/c2/irTests/TestVectorizationMismatchedAccess.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2023, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,7 +36,6 @@ import java.nio.ByteOrder;
  * @test
  * @bug 8300258
  * @key randomness
- * @requires (os.simpleArch == "x64") | (os.simpleArch == "aarch64")
  * @summary C2: vectorization fails on simple ByteBuffer loop
  * @modules java.base/jdk.internal.misc
  * @library /test/lib /
@@ -147,193 +147,420 @@ public class TestVectorizationMismatchedAccess {
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteLong1(byte[] dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteLong1a(byte[] dest, long[] src) {
         for (int i = 0; i < src.length; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, src[i]);
         }
     }
 
-    @Run(test = "testByteLong1")
-    public static void testByteLong1_runner() {
-        runAndVerify(() -> testByteLong1(byteArray, longArray), 0);
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteLong1b(byte[] dest, long[] src) {
+        for (int i = 0; i < src.length; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, src[i]);
+        }
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteLong2(byte[] dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"})
+    public static void testByteLong1c(byte[] dest, long[] src) {
+        long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit)
+        for (int i = 0; i < src.length - 8; i++) {
+            UNSAFE.putLongUnaligned(dest, base + 8 * i, src[i]);
+        }
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteLong1d(byte[] dest, long[] src) {
+        long base = 64; // make sure it is big enough and 8 byte aligned (required for 32-bit)
+        for (int i = 0; i < src.length - 8; i++) {
+            UNSAFE.putLongUnaligned(dest, base + 8L * i, src[i]);
+        }
+    }
+
+    @Run(test = {"testByteLong1a", "testByteLong1b", "testByteLong1c", "testByteLong1d"})
+    public static void testByteLong1_runner() {
+        runAndVerify(() -> testByteLong1a(byteArray, longArray), 0);
+        runAndVerify(() -> testByteLong1b(byteArray, longArray), 0);
+        testByteLong1c(byteArray, longArray);
+        testByteLong1d(byteArray, longArray);
+    }
+
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteLong2a(byte[] dest, long[] src) {
         for (int i = 1; i < src.length; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), src[i]);
         }
     }
 
-    @Run(test = "testByteLong2")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteLong2b(byte[] dest, long[] src) {
+        for (int i = 1; i < src.length; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), src[i]);
+        }
+    }
+
+    @Run(test = {"testByteLong2a", "testByteLong2b"})
     public static void testByteLong2_runner() {
-        runAndVerify(() -> testByteLong2(byteArray, longArray), -8);
+        runAndVerify(() -> testByteLong2a(byteArray, longArray), -8);
+        runAndVerify(() -> testByteLong2b(byteArray, longArray), -8);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteLong3(byte[] dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteLong3a(byte[] dest, long[] src) {
         for (int i = 0; i < src.length - 1; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), src[i]);
         }
     }
 
-    @Run(test = "testByteLong3")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteLong3b(byte[] dest, long[] src) {
+        for (int i = 0; i < src.length - 1; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), src[i]);
+        }
+    }
+
+    @Run(test = {"testByteLong3a", "testByteLong3b"})
     public static void testByteLong3_runner() {
-        runAndVerify(() -> testByteLong3(byteArray, longArray), 8);
+        runAndVerify(() -> testByteLong3a(byteArray, longArray), 8);
+        runAndVerify(() -> testByteLong3b(byteArray, longArray), 8);
     }
 
     @Test
     @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"},
         applyIf = {"AlignVector", "false"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
     // AlignVector cannot guarantee that invar is aligned.
-    public static void testByteLong4(byte[] dest, long[] src, int start, int stop) {
+    public static void testByteLong4a(byte[] dest, long[] src, int start, int stop) {
         for (int i = start; i < stop; i++) {
             UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, src[i]);
         }
     }
 
-    @Run(test = "testByteLong4")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"},
+        applyIf = {"AlignVector", "false"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    // AlignVector cannot guarantee that invar is aligned.
+    public static void testByteLong4b(byte[] dest, long[] src, int start, int stop) {
+        for (int i = start; i < stop; i++) {
+            UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, src[i]);
+        }
+    }
+
+    @Run(test = {"testByteLong4a", "testByteLong4b"})
     public static void testByteLong4_runner() {
         baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET;
-        runAndVerify(() -> testByteLong4(byteArray, longArray, 0, size), 0);
+        runAndVerify(() -> testByteLong4a(byteArray, longArray, 0, size), 0);
+        runAndVerify(() -> testByteLong4b(byteArray, longArray, 0, size), 0);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteLong5(byte[] dest, long[] src, int start, int stop) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteLong5a(byte[] dest, long[] src, int start, int stop) {
         for (int i = start; i < stop; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), src[i]);
         }
     }
 
-    @Run(test = "testByteLong5")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteLong5b(byte[] dest, long[] src, int start, int stop) {
+        for (int i = start; i < stop; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), src[i]);
+        }
+    }
+
+    @Run(test = {"testByteLong5a", "testByteLong5b"})
     public static void testByteLong5_runner() {
         baseOffset = 1;
-        runAndVerify(() -> testByteLong5(byteArray, longArray, 0, size-1), 8);
+        runAndVerify(() -> testByteLong5a(byteArray, longArray, 0, size-1), 8);
+        runAndVerify(() -> testByteLong5b(byteArray, longArray, 0, size-1), 8);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteByte1(byte[] dest, byte[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteByte1a(byte[] dest, byte[] src) {
         for (int i = 0; i < src.length / 8; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i));
         }
     }
 
-    @Run(test = "testByteByte1")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteByte1b(byte[] dest, byte[] src) {
+        for (int i = 0; i < src.length / 8; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i));
+        }
+    }
+
+    @Run(test = {"testByteByte1a", "testByteByte1b"})
     public static void testByteByte1_runner() {
-        runAndVerify2(() -> testByteByte1(byteArray, byteArray), 0);
+        runAndVerify2(() -> testByteByte1a(byteArray, byteArray), 0);
+        runAndVerify2(() -> testByteByte1b(byteArray, byteArray), 0);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testByteByte2(byte[] dest, byte[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: offsets are badly aligned (UNSAFE.ARRAY_BYTE_BASE_OFFSET is 4 byte aligned, but not 8 byte aligned).
+    //         might get fixed with JDK-8325155.
+    public static void testByteByte2a(byte[] dest, byte[] src) {
         for (int i = 1; i < src.length / 8; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i));
         }
     }
 
-    @Run(test = "testByteByte2")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+        applyIfCPUFeatureOr = {"sse2", "true", "asimd", "true"},
+        applyIfPlatform = {"64-bit", "true"})
+    // 32-bit: address has ConvL2I for cast of long to address, not supported.
+    public static void testByteByte2b(byte[] dest, byte[] src) {
+        for (int i = 1; i < src.length / 8; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i - 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i));
+        }
+    }
+
+    @Run(test = {"testByteByte2a", "testByteByte2b"})
     public static void testByteByte2_runner() {
-        runAndVerify2(() -> testByteByte2(byteArray, byteArray), -8);
+        runAndVerify2(() -> testByteByte2a(byteArray, byteArray), -8);
+        runAndVerify2(() -> testByteByte2b(byteArray, byteArray), -8);
     }
 
     @Test
     @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
-    public static void testByteByte3(byte[] dest, byte[] src) {
+    public static void testByteByte3a(byte[] dest, byte[] src) {
         for (int i = 0; i < src.length / 8 - 1; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i));
         }
     }
 
-    @Run(test = "testByteByte3")
+    @Test
+    @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
+    public static void testByteByte3b(byte[] dest, byte[] src) {
+        for (int i = 0; i < src.length / 8 - 1; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + 1), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i));
+        }
+    }
+
+    @Run(test = {"testByteByte3a", "testByteByte3b"})
     public static void testByteByte3_runner() {
-        runAndVerify2(() -> testByteByte3(byteArray, byteArray), 8);
+        runAndVerify2(() -> testByteByte3a(byteArray, byteArray), 8);
+        runAndVerify2(() -> testByteByte3b(byteArray, byteArray), 8);
     }
 
     @Test
     @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
-    public static void testByteByte4(byte[] dest, byte[] src, int start, int stop) {
+    public static void testByteByte4a(byte[] dest, byte[] src, int start, int stop) {
         for (int i = start; i < stop; i++) {
             UNSAFE.putLongUnaligned(dest, 8 * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i));
         }
     }
 
-    @Run(test = "testByteByte4")
+    @Test
+    @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
+    public static void testByteByte4b(byte[] dest, byte[] src, int start, int stop) {
+        for (int i = start; i < stop; i++) {
+            UNSAFE.putLongUnaligned(dest, 8L * i + baseOffset, UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i));
+        }
+    }
+
+    @Run(test = {"testByteByte4a", "testByteByte4b"})
     public static void testByteByte4_runner() {
         baseOffset = UNSAFE.ARRAY_BYTE_BASE_OFFSET;
-        runAndVerify2(() -> testByteByte4(byteArray, byteArray, 0, size), 0);
+        runAndVerify2(() -> testByteByte4a(byteArray, byteArray, 0, size), 0);
+        runAndVerify2(() -> testByteByte4b(byteArray, byteArray, 0, size), 0);
     }
 
     @Test
     @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
-    public static void testByteByte5(byte[] dest, byte[] src, int start, int stop) {
+    public static void testByteByte5a(byte[] dest, byte[] src, int start, int stop) {
         for (int i = start; i < stop; i++) {
             UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8 * i));
         }
     }
 
-    @Run(test = "testByteByte5")
+    @Test
+    @IR(failOn = { IRNode.LOAD_VECTOR_L, IRNode.STORE_VECTOR })
+    public static void testByteByte5b(byte[] dest, byte[] src, int start, int stop) {
+        for (int i = start; i < stop; i++) {
+            UNSAFE.putLongUnaligned(dest, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * (i + baseOffset), UNSAFE.getLongUnaligned(src, UNSAFE.ARRAY_BYTE_BASE_OFFSET + 8L * i));
+        }
+    }
+
+    @Run(test = {"testByteByte5a", "testByteByte5b"})
     public static void testByteByte5_runner() {
         baseOffset = 1;
-        runAndVerify2(() -> testByteByte5(byteArray, byteArray, 0, size-1), 8);
+        runAndVerify2(() -> testByteByte5a(byteArray, byteArray, 0, size-1), 8);
+        runAndVerify2(() -> testByteByte5b(byteArray, byteArray, 0, size-1), 8);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testOffHeapLong1(long dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P(dest + 8 * (i + int_con))
+    // See: JDK-8331576
+    public static void testOffHeapLong1a(long dest, long[] src) {
         for (int i = 0; i < src.length; i++) {
             UNSAFE.putLongUnaligned(null, dest + 8 * i, src[i]);
         }
     }
 
-    @Run(test = "testOffHeapLong1")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P(dest + 8L * (i + int_con))
+    // See: JDK-8331576
+    public static void testOffHeapLong1b(long dest, long[] src) {
+        for (int i = 0; i < src.length; i++) {
+            UNSAFE.putLongUnaligned(null, dest + 8L * i, src[i]);
+        }
+    }
+
+    @Run(test = {"testOffHeapLong1a", "testOffHeapLong1b"})
     public static void testOffHeapLong1_runner() {
-        runAndVerify3(() -> testOffHeapLong1(baseOffHeap, longArray), 0);
+        runAndVerify3(() -> testOffHeapLong1a(baseOffHeap, longArray), 0);
+        runAndVerify3(() -> testOffHeapLong1b(baseOffHeap, longArray), 0);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testOffHeapLong2(long dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
+    public static void testOffHeapLong2a(long dest, long[] src) {
         for (int i = 1; i < src.length; i++) {
             UNSAFE.putLongUnaligned(null, dest + 8 * (i - 1), src[i]);
         }
     }
 
-    @Run(test = "testOffHeapLong2")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
+    public static void testOffHeapLong2b(long dest, long[] src) {
+        for (int i = 1; i < src.length; i++) {
+            UNSAFE.putLongUnaligned(null, dest + 8L * (i - 1), src[i]);
+        }
+    }
+
+    @Run(test = {"testOffHeapLong2a", "testOffHeapLong2b"})
     public static void testOffHeapLong2_runner() {
-        runAndVerify3(() -> testOffHeapLong2(baseOffHeap, longArray), -8);
+        runAndVerify3(() -> testOffHeapLong2a(baseOffHeap, longArray), -8);
+        runAndVerify3(() -> testOffHeapLong2b(baseOffHeap, longArray), -8);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
-    public static void testOffHeapLong3(long dest, long[] src) {
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
+    public static void testOffHeapLong3a(long dest, long[] src) {
         for (int i = 0; i < src.length - 1; i++) {
             UNSAFE.putLongUnaligned(null, dest + 8 * (i + 1), src[i]);
         }
     }
 
-    @Run(test = "testOffHeapLong3")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" })
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
+    public static void testOffHeapLong3b(long dest, long[] src) {
+        for (int i = 0; i < src.length - 1; i++) {
+            UNSAFE.putLongUnaligned(null, dest + 8L * (i + 1), src[i]);
+        }
+    }
+
+    @Run(test = {"testOffHeapLong3a", "testOffHeapLong3b"})
     public static void testOffHeapLong3_runner() {
-        runAndVerify3(() -> testOffHeapLong3(baseOffHeap, longArray), 8);
+        runAndVerify3(() -> testOffHeapLong3a(baseOffHeap, longArray), 8);
+        runAndVerify3(() -> testOffHeapLong3b(baseOffHeap, longArray), 8);
     }
 
     @Test
-    @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
-        applyIf = {"AlignVector", "false"})
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+    //     applyIf = {"AlignVector", "false"})
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
     // AlignVector cannot guarantee that invar is aligned.
-    public static void testOffHeapLong4(long dest, long[] src, int start, int stop) {
+    public static void testOffHeapLong4a(long dest, long[] src, int start, int stop) {
         for (int i = start; i < stop; i++) {
             UNSAFE.putLongUnaligned(null, dest + 8 * i + baseOffset, src[i]);
         }
     }
 
-    @Run(test = "testOffHeapLong4")
+    @Test
+    @IR(counts = { IRNode.LOAD_VECTOR_L, "=0", IRNode.STORE_VECTOR, "=0" }) // temporary
+    // @IR(counts = { IRNode.LOAD_VECTOR_L, ">=1", IRNode.STORE_VECTOR, ">=1" },
+    //     applyIf = {"AlignVector", "false"})
+    // FAILS: adr is CastX2P
+    // See: JDK-8331576
+    // AlignVector cannot guarantee that invar is aligned.
+    public static void testOffHeapLong4b(long dest, long[] src, int start, int stop) {
+        for (int i = start; i < stop; i++) {
+            UNSAFE.putLongUnaligned(null, dest + 8L * i + baseOffset, src[i]);
+        }
+    }
+
+    @Run(test = {"testOffHeapLong4a", "testOffHeapLong4b"})
     public static void testOffHeapLong4_runner() {
         baseOffset = 8;
-        runAndVerify3(() -> testOffHeapLong4(baseOffHeap, longArray, 0, size-1), 8);
+        runAndVerify3(() -> testOffHeapLong4a(baseOffHeap, longArray, 0, size-1), 8);
+        runAndVerify3(() -> testOffHeapLong4b(baseOffHeap, longArray, 0, size-1), 8);
     }
 }
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java
index fd5c2969074..c77f4f6fa2e 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVector.java
@@ -1363,7 +1363,7 @@ public class TestAlignVector {
     static Object[] test17a(long[] a) {
         // Unsafe: vectorizes with profiling (not xcomp)
         for (int i = 0; i < RANGE; i++) {
-            int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i;
+            long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i;
             long v = UNSAFE.getLongUnaligned(a, adr);
             UNSAFE.putLongUnaligned(a, adr, v + 1);
         }
@@ -1375,7 +1375,7 @@ public class TestAlignVector {
     static Object[] test17b(long[] a) {
         // Not alignable
         for (int i = 0; i < RANGE-1; i++) {
-            int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1;
+            long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1;
             long v = UNSAFE.getLongUnaligned(a, adr);
             UNSAFE.putLongUnaligned(a, adr, v + 1);
         }
@@ -1392,7 +1392,7 @@ public class TestAlignVector {
     static Object[] test17c(long[] a) {
         // Unsafe: aligned vectorizes
         for (int i = 0; i < RANGE-1; i+=4) {
-            int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i;
+            long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i;
             long v0 = UNSAFE.getLongUnaligned(a, adr + 0);
             long v1 = UNSAFE.getLongUnaligned(a, adr + 8);
             UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1);
@@ -1422,7 +1422,7 @@ public class TestAlignVector {
     static Object[] test17d(long[] a) {
         // Not alignable
         for (int i = 0; i < RANGE-1; i+=4) {
-            int adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8 * i + 1;
+            long adr = UNSAFE.ARRAY_LONG_BASE_OFFSET + 8L * i + 1;
             long v0 = UNSAFE.getLongUnaligned(a, adr + 0);
             long v1 = UNSAFE.getLongUnaligned(a, adr + 8);
             UNSAFE.putLongUnaligned(a, adr + 0, v0 + 1);
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
index 7b95781905e..d75db965ea3 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestAlignVectorFuzzer.java
@@ -1090,11 +1090,11 @@ public class TestAlignVectorFuzzer {
         int init   = init_con_or_var();
         int limit  = limit_con_or_var();
         int stride = stride_con();
-        int scale  = scale_con();
-        int offset = offset1_con_or_var();
+        long scale  = scale_con();
+        long offset = offset1_con_or_var();
 
         for (int i = init; i < limit; i += stride) {
-            int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale;
+            long adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset + i * scale;
             int v = UNSAFE.getIntUnaligned(a, adr);
             UNSAFE.putIntUnaligned(a, adr, v + 1);
         }
@@ -1105,19 +1105,19 @@ public class TestAlignVectorFuzzer {
         int init   = init_con_or_var();
         int limit  = limit_con_or_var();
         int stride = stride_con();
-        int scale  = scale_con();
-        int offset1 = offset1_con_or_var();
-        int offset2 = offset2_con_or_var();
-        int offset3 = offset3_con_or_var();
+        long scale  = scale_con();
+        long offset1 = offset1_con_or_var();
+        long offset2 = offset2_con_or_var();
+        long offset3 = offset3_con_or_var();
 
         int h1 = hand_unrolling1_con();
         int h2 = hand_unrolling2_con();
         int h3 = hand_unrolling3_con();
 
         for (int i = init; i < limit; i += stride) {
-            int adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale;
-            int adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale;
-            int adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale;
+            long adr1 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset1 + i * scale;
+            long adr2 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset2 + i * scale;
+            long adr3 = UNSAFE.ARRAY_BYTE_BASE_OFFSET + offset3 + i * scale;
 
             if (h1 >=  1) { UNSAFE.putIntUnaligned(a, adr1 +  0*4, UNSAFE.getIntUnaligned(a, adr1 +  0*4) + 1); }
             if (h1 >=  2) { UNSAFE.putIntUnaligned(a, adr1 +  1*4, UNSAFE.getIntUnaligned(a, adr1 +  1*4) + 1); }
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java
index 65398e8adfd..197ae08b6d8 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency.java
@@ -172,10 +172,10 @@ public class TestIndependentPacksWithCyclicDependency {
     static void test2(int[] dataIa, int[] dataIb, float[] dataFa, float[] dataFb) {
         for (int i = 0; i < RANGE; i+=2) {
             // int and float arrays are two slices. But we pretend both are of type int.
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1);
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1);
-            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0);
-            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4);
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1);
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1);
+            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0);
+            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4);
         }
     }
 
@@ -248,10 +248,10 @@ public class TestIndependentPacksWithCyclicDependency {
         for (int i = 0; i < RANGE; i+=2) {
             // same as test2, except that reordering leads to different semantics
             // explanation analogue to test4
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1); // A
-            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0); // X
-            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4); // Y
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] + 1); // B
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1); // A
+            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0); // X
+            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4); // Y
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] + 1); // B
         }
     }
 
@@ -275,18 +275,18 @@ public class TestIndependentPacksWithCyclicDependency {
                       long[] dataLa, long[] dataLb) {
         for (int i = 0; i < RANGE; i+=2) {
             // Chain of parallelizable op and conversion
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3;
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45;
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45;
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f;
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f;
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
         }
     }
 
@@ -307,18 +307,18 @@ public class TestIndependentPacksWithCyclicDependency {
                       long[] dataLa, long[] dataLb) {
         for (int i = 0; i < RANGE; i+=2) {
             // Cycle involving 3 memory slices
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45;
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45;
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f;
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f;
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
         }
     }
 
@@ -340,19 +340,19 @@ public class TestIndependentPacksWithCyclicDependency {
                       long[] dataLa, long[] dataLb) {
         for (int i = 0; i < RANGE; i+=2) {
             // 2-cycle, with more ops after
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45;
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45;
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
             // more stuff after
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f;
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f;
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
         }
     }
 
@@ -373,19 +373,19 @@ public class TestIndependentPacksWithCyclicDependency {
                       long[] dataLa, long[] dataLb) {
         for (int i = 0; i < RANGE; i+=2) {
             // 2-cycle, with more stuff before
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f;
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f;
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
             // 2-cycle
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) * 45;
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45;
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) * 45;
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
         }
     }
 
@@ -423,18 +423,18 @@ public class TestIndependentPacksWithCyclicDependency {
             //
             // The cycle thus does not only go via packs, but also scalar ops.
             //
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3; // A
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45; // R: constant mismatch
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43; // S
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f; // U
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f; // V
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // B: moved down
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3; // A
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45; // R: constant mismatch
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43; // S
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f; // U
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f; // V
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // B: moved down
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
         }
     }
 
@@ -463,8 +463,8 @@ public class TestIndependentPacksWithCyclicDependency {
 
     static void verify(String name, float[] data, float[] gold) {
         for (int i = 0; i < RANGE; i++) {
-            int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
-            int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
+            int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i);
+            int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i);
             if (datav != goldv) {
                 throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv);
             }
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java
index 32d69689a42..2be7d52c780 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestIndependentPacksWithCyclicDependency2.java
@@ -58,18 +58,18 @@ public class TestIndependentPacksWithCyclicDependency2 {
                      long[] dataLa, long[] dataLb) {
         for (int i = 0; i < RANGE; i+=2) {
             // For explanation, see test 10 in TestIndependentPacksWithCyclicDependency.java
-            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0) + 3;
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, v00);
-            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0) * 45;
-            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4) + 43;
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0, v10);
-            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4, v11);
-            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 0) + 0.55f;
-            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4 * i + 4) + 0.55f;
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0, v20);
-            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4, v21);
-            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4) + 3; // moved down
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, v01);
+            int v00 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0) + 3;
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, v00);
+            int v10 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0) * 45;
+            int v11 = unsafe.getInt(dataFb, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4) + 43;
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0, v10);
+            unsafe.putInt(dataLa, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4, v11);
+            float v20 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 0) + 0.55f;
+            float v21 = unsafe.getFloat(dataLb, unsafe.ARRAY_LONG_BASE_OFFSET + 4L * i + 4) + 0.55f;
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0, v20);
+            unsafe.putFloat(dataIb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4, v21);
+            int v01 = unsafe.getInt(dataIa, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4) + 3; // moved down
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, v01);
         }
     }
 
@@ -83,8 +83,8 @@ public class TestIndependentPacksWithCyclicDependency2 {
 
     static void verify(String name, float[] data, float[] gold) {
         for (int i = 0; i < RANGE; i++) {
-            int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
-            int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i);
+            int datav = unsafe.getInt(data, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i);
+            int goldv = unsafe.getInt(gold, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i);
             if (datav != goldv) {
                 throw new RuntimeException(" Invalid " + name + " result: dataF[" + i + "]: " + datav + " != " + goldv);
             }
diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java
index f2ed8b6aec2..c54a684c691 100644
--- a/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java
+++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestScheduleReordersScalarMemops.java
@@ -124,10 +124,10 @@ public class TestScheduleReordersScalarMemops {
         for (int i = 0; i < RANGE; i+=2) {
             // Do the same as test0, but without int-float conversion.
             // This should reproduce on machines where conversion is not implemented.
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 0, dataIa[i+0] + 1);  // A +1
-            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 0);  // X
-            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4 * i + 4);  // Y
-            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4 * i + 4, dataIa[i+1] * 11); // B *11
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 0, dataIa[i+0] + 1);  // A +1
+            dataIb[i+0] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 0);  // X
+            dataIb[i+1] = 11 * unsafe.getInt(dataFb, unsafe.ARRAY_INT_BASE_OFFSET + 4L * i + 4);  // Y
+            unsafe.putInt(dataFa, unsafe.ARRAY_FLOAT_BASE_OFFSET + 4L * i + 4, dataIa[i+1] * 11); // B *11
         }
     }
 
diff --git a/test/jdk/java/net/httpclient/ExpectContinueTest.java b/test/jdk/java/net/httpclient/ExpectContinueTest.java
index 3d28ae8c8b4..50e43099255 100644
--- a/test/jdk/java/net/httpclient/ExpectContinueTest.java
+++ b/test/jdk/java/net/httpclient/ExpectContinueTest.java
@@ -59,6 +59,7 @@ import java.io.PrintWriter;
 import java.io.Writer;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.ProtocolException;
 import java.net.ServerSocket;
 import java.net.Socket;
 import java.net.URI;
@@ -361,7 +362,7 @@ public class ExpectContinueTest implements HttpServerAdapters {
         }
         if (exceptionally && testThrowable != null) {
             err.println("Finished exceptionally Test throwable: " + testThrowable);
-            assertEquals(IOException.class, testThrowable.getClass());
+            assertEquals(testThrowable.getClass(), ProtocolException.class);
         } else if (exceptionally) {
             throw new TestException("Expected case to finish with an IOException but testException is null");
         } else if (resp != null) {
diff --git a/test/jdk/java/net/httpclient/ShutdownNow.java b/test/jdk/java/net/httpclient/ShutdownNow.java
index 77504b5052a..47eb1f6d7c9 100644
--- a/test/jdk/java/net/httpclient/ShutdownNow.java
+++ b/test/jdk/java/net/httpclient/ShutdownNow.java
@@ -136,6 +136,7 @@ public class ShutdownNow implements HttpServerAdapters {
         if (message.equals("shutdownNow")) return true;
         // exception from cancelling an HTTP/2 stream
         if (message.matches("Stream [0-9]+ cancelled")) return true;
+        if (message.contains("connection closed locally")) return true;
         return false;
     }
 
diff --git a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java
index 6395cc839a2..c0021e7e4ea 100644
--- a/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java
+++ b/test/jdk/java/net/httpclient/http2/PushPromiseContinuation.java
@@ -40,6 +40,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.ProtocolException;
 import java.net.URI;
 import java.net.http.HttpClient;
 import java.net.http.HttpHeaders;
@@ -195,7 +196,8 @@ public class PushPromiseContinuation {
                 client.sendAsync(hreq, HttpResponse.BodyHandlers.ofString(UTF_8), pph);
 
         CompletionException t = expectThrows(CompletionException.class, () -> cf.join());
-        assertEquals(t.getCause().getClass(), IOException.class, "Expected an IOException but got " + t.getCause());
+        assertEquals(t.getCause().getClass(), ProtocolException.class,
+                "Expected a ProtocolException but got " + t.getCause());
         System.err.println("Client received the following expected exception: " + t.getCause());
         faultyServer.stop();
     }
@@ -222,7 +224,10 @@ public class PushPromiseContinuation {
 
     static class Http2PushPromiseHeadersExchangeImpl extends Http2TestExchangeImpl {
 
-        Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders, HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is, SSLSession sslSession, BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) {
+        Http2PushPromiseHeadersExchangeImpl(int streamid, String method, HttpHeaders reqheaders,
+                                            HttpHeadersBuilder rspheadersBuilder, URI uri, InputStream is,
+                                            SSLSession sslSession, BodyOutputStream os,
+                                            Http2TestServerConnection conn, boolean pushAllowed) {
             super(streamid, method, reqheaders, rspheadersBuilder, uri, is, sslSession, os, conn, pushAllowed);
         }
 
diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java
index 36498684a9a..27dbe637b94 100644
--- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java
+++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/common/HttpServerAdapters.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -241,6 +241,7 @@ public interface HttpServerAdapters {
         public abstract void close();
         public abstract InetSocketAddress getRemoteAddress();
         public abstract String getConnectionKey();
+        public abstract InetSocketAddress getLocalAddress();
         public void serverPush(URI uri, HttpHeaders headers, byte[] body) {
             ByteArrayInputStream bais = new ByteArrayInputStream(body);
             serverPush(uri, headers, bais);
@@ -303,7 +304,10 @@ public interface HttpServerAdapters {
             public InetSocketAddress getRemoteAddress() {
                 return exchange.getRemoteAddress();
             }
-
+            @Override
+            public InetSocketAddress getLocalAddress() {
+                return exchange.getLocalAddress();
+            }
             @Override
             public URI getRequestURI() { return exchange.getRequestURI(); }
             @Override
@@ -370,6 +374,10 @@ public interface HttpServerAdapters {
             public InetSocketAddress getRemoteAddress() {
                 return exchange.getRemoteAddress();
             }
+            @Override
+            public InetSocketAddress getLocalAddress() {
+                return exchange.getLocalAddress();
+            }
 
             @Override
             public String getConnectionKey() {
diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java
new file mode 100644
index 00000000000..f54a4a766b8
--- /dev/null
+++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/HpackTestEncoder.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.httpclient.test.lib.http2;
+
+import java.util.function.*;
+
+import jdk.internal.net.http.hpack.Encoder;
+
+import static java.lang.String.format;
+import static java.util.Objects.requireNonNull;
+import static jdk.internal.net.http.hpack.HPACK.Logger.Level.EXTRA;
+import static jdk.internal.net.http.hpack.HPACK.Logger.Level.NORMAL;
+
+public class HpackTestEncoder extends Encoder {
+
+    public HpackTestEncoder(int maxCapacity) {
+        super(maxCapacity);
+    }
+
+    /**
+     * Sets up the given header {@code (name, value)} with possibly sensitive
+     * value.
+     *
+     * <p> If the {@code value} is sensitive (think security, secrecy, etc.)
+     * this encoder will compress it using a special representation
+     * (see <a href="https://tools.ietf.org/html/rfc7541#section-6.2.3">6.2.3.  Literal Header Field Never Indexed</a>).
+     *
+     * <p> Fixates {@code name} and {@code value} for the duration of encoding.
+     *
+     * @param name
+     *         the name
+     * @param value
+     *         the value
+     * @param sensitive
+     *         whether or not the value is sensitive
+     *
+     * @throws NullPointerException
+     *         if any of the arguments are {@code null}
+     * @throws IllegalStateException
+     *         if the encoder hasn't fully encoded the previous header, or
+     *         hasn't yet started to encode it
+     * @see #header(CharSequence, CharSequence)
+     * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean)
+     */
+    public void header(CharSequence name,
+                       CharSequence value,
+                       boolean sensitive) throws IllegalStateException {
+        if (sensitive || getMaxCapacity() == 0) {
+            super.header(name, value, true);
+        } else {
+            header(name, value, false, (n,v) -> false);
+        }
+    }
+    /**
+     * Sets up the given header {@code (name, value)} with possibly sensitive
+     * value.
+     *
+     * <p> If the {@code value} is sensitive (think security, secrecy, etc.)
+     * this encoder will compress it using a special representation
+     * (see <a href="https://tools.ietf.org/html/rfc7541#section-6.2.3">6.2.3.  Literal Header Field Never Indexed</a>).
+     *
+     * <p> Fixates {@code name} and {@code value} for the duration of encoding.
+     *
+     * @param name
+     *         the name
+     * @param value
+     *         the value
+     * @param insertionPolicy
+     *         a bipredicate to indicate whether a name value pair
+     *         should be added to the dynamic table
+     *
+     * @throws NullPointerException
+     *         if any of the arguments are {@code null}
+     * @throws IllegalStateException
+     *         if the encoder hasn't fully encoded the previous header, or
+     *         hasn't yet started to encode it
+     * @see #header(CharSequence, CharSequence)
+     * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean)
+     */
+    public void header(CharSequence name,
+                       CharSequence value,
+                       BiPredicate<CharSequence, CharSequence> insertionPolicy)
+            throws IllegalStateException {
+        header(name, value, false, insertionPolicy);
+    }
+
+    /**
+     * Sets up the given header {@code (name, value)} with possibly sensitive
+     * value.
+     *
+     * <p> If the {@code value} is sensitive (think security, secrecy, etc.)
+     * this encoder will compress it using a special representation
+     * (see <a href="https://tools.ietf.org/html/rfc7541#section-6.2.3">
+     *     6.2.3.  Literal Header Field Never Indexed</a>).
+     *
+     * <p> Fixates {@code name} and {@code value} for the duration of encoding.
+     *
+     * @param name
+     *         the name
+     * @param value
+     *         the value
+     * @param sensitive
+     *         whether or not the value is sensitive
+     * @param insertionPolicy
+     *         a bipredicate to indicate whether a name value pair
+     *         should be added to the dynamic table
+     *
+     * @throws NullPointerException
+     *         if any of the arguments are {@code null}
+     * @throws IllegalStateException
+     *         if the encoder hasn't fully encoded the previous header, or
+     *         hasn't yet started to encode it
+     * @see #header(CharSequence, CharSequence)
+     * @see DecodingCallback#onDecoded(CharSequence, CharSequence, boolean)
+     */
+    public void header(CharSequence name,
+                       CharSequence value,
+                       boolean sensitive,
+                       BiPredicate<CharSequence, CharSequence> insertionPolicy)
+            throws IllegalStateException {
+        if (sensitive == true || getMaxCapacity() == 0 || !insertionPolicy.test(name, value)) {
+            super.header(name, value, sensitive);
+            return;
+        }
+        var logger = logger();
+        // Arguably a good balance between complexity of implementation and
+        // efficiency of encoding
+        requireNonNull(name, "name");
+        requireNonNull(value, "value");
+        var t = getHeaderTable();
+        int index = tableIndexOf(name, value);
+        if (logger.isLoggable(NORMAL)) {
+            logger.log(NORMAL, () -> format("encoding with indexing ('%s', '%s'): index:%s",
+                    name, value, index));
+        }
+        if (index > 0) {
+            indexed(index);
+        } else {
+            boolean huffmanValue = isHuffmanBetterFor(value);
+            if (index < 0) {
+                literalWithIndexing(-index, value, huffmanValue);
+            } else {
+                boolean huffmanName = isHuffmanBetterFor(name);
+                literalWithIndexing(name, huffmanName, value, huffmanValue);
+            }
+        }
+    }
+
+    protected int calculateCapacity(int maxCapacity) {
+        return maxCapacity;
+    }
+
+}
diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java
index d982349dac5..828c939f53f 100644
--- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java
+++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchange.java
@@ -29,9 +29,12 @@ import java.io.OutputStream;
 import java.net.URI;
 import java.net.InetSocketAddress;
 import java.net.http.HttpHeaders;
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.BiPredicate;
 import javax.net.ssl.SSLSession;
 import jdk.internal.net.http.common.HttpHeadersBuilder;
+import jdk.internal.net.http.frame.Http2Frame;
 
 public interface Http2TestExchange {
 
@@ -53,6 +56,12 @@ public interface Http2TestExchange {
 
     void sendResponseHeaders(int rCode, long responseLength) throws IOException;
 
+    default void sendResponseHeaders(int rCode, long responseLength,
+                                     BiPredicate<CharSequence, CharSequence> insertionPolicy)
+            throws IOException {
+        sendResponseHeaders(rCode, responseLength);
+    }
+
     InetSocketAddress getRemoteAddress();
 
     int getResponseCode();
@@ -65,6 +74,10 @@ public interface Http2TestExchange {
 
     void serverPush(URI uri, HttpHeaders headers, InputStream content);
 
+    default void sendFrames(List<Http2Frame> frames) throws IOException {
+        throw new UnsupportedOperationException("not implemented");
+    }
+
     /**
      * Send a PING on this exchanges connection, and completes the returned CF
      * with the number of milliseconds it took to get a valid response.
diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java
index d25019f9094..fa7589c0232 100644
--- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java
+++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestExchangeImpl.java
@@ -27,6 +27,7 @@ import jdk.httpclient.test.lib.http2.Http2TestServerConnection.ResponseHeaders;
 import jdk.internal.net.http.common.HttpHeadersBuilder;
 import jdk.internal.net.http.frame.HeaderFrame;
 import jdk.internal.net.http.frame.HeadersFrame;
+import jdk.internal.net.http.frame.Http2Frame;
 import jdk.internal.net.http.frame.ResetFrame;
 
 import javax.net.ssl.SSLSession;
@@ -39,6 +40,7 @@ import java.net.http.HttpHeaders;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.BiPredicate;
 
 public class Http2TestExchangeImpl implements Http2TestExchange {
 
@@ -132,8 +134,13 @@ public class Http2TestExchangeImpl implements Http2TestExchange {
         return os;
     }
 
-    @Override
     public void sendResponseHeaders(int rCode, long responseLength) throws IOException {
+        sendResponseHeaders(rCode, responseLength, (n,v) -> false);
+    }
+    @Override
+    public void sendResponseHeaders(int rCode, long responseLength,
+                                    BiPredicate<CharSequence, CharSequence> insertionPolicy)
+            throws IOException {
         // Do not set Content-Length for 100, and do not set END_STREAM
         if (rCode == 100) responseLength = 0;
 
@@ -147,7 +154,7 @@ public class Http2TestExchangeImpl implements Http2TestExchange {
         HttpHeaders headers = rspheadersBuilder.build();
 
         ResponseHeaders response
-                = new ResponseHeaders(headers);
+                = new ResponseHeaders(headers, insertionPolicy);
         response.streamid(streamid);
         response.setFlag(HeaderFrame.END_HEADERS);
 
@@ -172,6 +179,11 @@ public class Http2TestExchangeImpl implements Http2TestExchange {
         conn.outputQ.put(response);
     }
 
+    @Override
+    public void sendFrames(List<Http2Frame> frames) throws IOException {
+        conn.sendFrames(frames);
+    }
+
     @Override
     public InetSocketAddress getRemoteAddress() {
         return (InetSocketAddress) conn.socket.getRemoteSocketAddress();
diff --git a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java
index 1aeeee60b19..c98e986ca85 100644
--- a/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java
+++ b/test/jdk/java/net/httpclient/lib/jdk/httpclient/test/lib/http2/Http2TestServerConnection.java
@@ -24,6 +24,8 @@
 package jdk.httpclient.test.lib.http2;
 
 import jdk.internal.net.http.common.HttpHeadersBuilder;
+import jdk.internal.net.http.common.Log;
+import jdk.internal.net.http.frame.ContinuationFrame;
 import jdk.internal.net.http.frame.DataFrame;
 import jdk.internal.net.http.frame.ErrorFrame;
 import jdk.internal.net.http.frame.FramesDecoder;
@@ -80,6 +82,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.ReentrantLock;
 import java.util.function.BiPredicate;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
@@ -87,6 +90,7 @@ import java.util.function.Predicate;
 import static java.nio.charset.StandardCharsets.ISO_8859_1;
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static jdk.internal.net.http.frame.ErrorFrame.REFUSED_STREAM;
+import static jdk.internal.net.http.frame.SettingsFrame.DEFAULT_MAX_FRAME_SIZE;
 import static jdk.internal.net.http.frame.SettingsFrame.HEADER_TABLE_SIZE;
 
 /**
@@ -105,7 +109,7 @@ public class Http2TestServerConnection {
     final Http2TestExchangeSupplier exchangeSupplier;
     final InputStream is;
     final OutputStream os;
-    volatile Encoder hpackOut;
+    volatile HpackTestEncoder hpackOut;
     volatile Decoder hpackIn;
     volatile SettingsFrame clientSettings;
     final SettingsFrame serverSettings;
@@ -421,7 +425,9 @@ public class Http2TestServerConnection {
     }
 
     public int getMaxFrameSize() {
-        return clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE);
+        var max = clientSettings.getParameter(SettingsFrame.MAX_FRAME_SIZE);
+        if (max <= 0) max = DEFAULT_MAX_FRAME_SIZE;
+        return max;
     }
 
     /** Sends a pre-canned HTTP/1.1 response. */
@@ -482,7 +488,7 @@ public class Http2TestServerConnection {
         //System.out.println("ServerSettings: " + serverSettings);
         //System.out.println("ClientSettings: " + clientSettings);
 
-        hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
+        hpackOut = new HpackTestEncoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
         hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
 
         if (!secure) {
@@ -812,6 +818,14 @@ public class Http2TestServerConnection {
         }
     }
 
+    public void sendFrames(List<Http2Frame> frames) throws IOException {
+        synchronized (outputQ) {
+            for (var frame : frames) {
+                outputQ.put(frame);
+            }
+        }
+    }
+
     protected HttpHeadersBuilder createNewHeadersBuilder() {
         return new HttpHeadersBuilder();
     }
@@ -938,26 +952,38 @@ public class Http2TestServerConnection {
         return (streamid & 0x01) == 0x00;
     }
 
+    final ReentrantLock headersLock = new ReentrantLock();
+
     /** Encodes an group of headers, without any ordering guarantees. */
     public List<ByteBuffer> encodeHeaders(HttpHeaders headers) {
+        return encodeHeaders(headers, (n,v) -> false);
+    }
+
+    public List<ByteBuffer> encodeHeaders(HttpHeaders headers,
+                                          BiPredicate<CharSequence, CharSequence> insertionPolicy) {
         List<ByteBuffer> buffers = new LinkedList<>();
 
         ByteBuffer buf = getBuffer();
         boolean encoded;
-        for (Map.Entry<String, List<String>> entry : headers.map().entrySet()) {
-            List<String> values = entry.getValue();
-            String key = entry.getKey().toLowerCase();
-            for (String value : values) {
-                do {
-                    hpackOut.header(key, value);
-                    encoded = hpackOut.encode(buf);
-                    if (!encoded) {
-                        buf.flip();
-                        buffers.add(buf);
-                        buf = getBuffer();
-                    }
-                } while (!encoded);
+        headersLock.lock();
+        try {
+            for (Map.Entry<String, List<String>> entry : headers.map().entrySet()) {
+                List<String> values = entry.getValue();
+                String key = entry.getKey().toLowerCase();
+                for (String value : values) {
+                    hpackOut.header(key, value, insertionPolicy);
+                    do {
+                        encoded = hpackOut.encode(buf);
+                        if (!encoded && !buf.hasRemaining()) {
+                            buf.flip();
+                            buffers.add(buf);
+                            buf = getBuffer();
+                        }
+                    } while (!encoded);
+                }
             }
+        } finally {
+            headersLock.unlock();
         }
         buf.flip();
         buffers.add(buf);
@@ -970,18 +996,23 @@ public class Http2TestServerConnection {
 
         ByteBuffer buf = getBuffer();
         boolean encoded;
-        for (Map.Entry<String, String> entry : headers) {
-            String value = entry.getValue();
-            String key = entry.getKey().toLowerCase();
-            do {
+        headersLock.lock();
+        try {
+            for (Map.Entry<String, String> entry : headers) {
+                String value = entry.getValue();
+                String key = entry.getKey().toLowerCase();
                 hpackOut.header(key, value);
-                encoded = hpackOut.encode(buf);
-                if (!encoded) {
-                    buf.flip();
-                    buffers.add(buf);
-                    buf = getBuffer();
-                }
-            } while (!encoded);
+                do {
+                    encoded = hpackOut.encode(buf);
+                    if (!encoded && !buf.hasRemaining()) {
+                        buf.flip();
+                        buffers.add(buf);
+                        buf = getBuffer();
+                    }
+                } while (!encoded);
+            }
+        } finally {
+            headersLock.unlock();
         }
         buf.flip();
         buffers.add(buf);
@@ -1008,10 +1039,50 @@ public class Http2TestServerConnection {
                         break;
                     } else throw x;
                 }
-                if (frame instanceof ResponseHeaders) {
-                    ResponseHeaders rh = (ResponseHeaders)frame;
-                    HeadersFrame hf = new HeadersFrame(rh.streamid(), rh.getFlags(), encodeHeaders(rh.headers));
-                    writeFrame(hf);
+                if (frame instanceof ResponseHeaders rh) {
+                    var buffers = encodeHeaders(rh.headers, rh.insertionPolicy);
+                    int maxFrameSize = Math.min(rh.getMaxFrameSize(), getMaxFrameSize() - 64);
+                    int next = 0;
+                    int cont = 0;
+                    do {
+                        // If the total size of headers exceeds the max frame
+                        // size we need to split the headers into one
+                        // HeadersFrame + N x ContinuationFrames
+                        int remaining = maxFrameSize;
+                        var list = new ArrayList<ByteBuffer>(buffers.size());
+                        for (; next < buffers.size(); next++) {
+                            var b = buffers.get(next);
+                            var len = b.remaining();
+                            if (!b.hasRemaining()) continue;
+                            if (len <= remaining) {
+                                remaining -= len;
+                                list.add(b);
+                            } else {
+                                if (next == 0) {
+                                    list.add(b.slice(b.position(), remaining));
+                                    b.position(b.position() + remaining);
+                                    remaining = 0;
+                                }
+                                break;
+                            }
+                        }
+                        int flags = rh.getFlags();
+                        if (next != buffers.size()) {
+                            flags = flags & ~HeadersFrame.END_HEADERS;
+                        }
+                        if (cont > 0)  {
+                            flags = flags & ~HeadersFrame.END_STREAM;
+                        }
+                        HeaderFrame hf = cont == 0
+                                ? new HeadersFrame(rh.streamid(), flags, list)
+                                : new ContinuationFrame(rh.streamid(), flags, list);
+                        if (Log.headers()) {
+                            // avoid too much chatter: log only if Log.headers() is enabled
+                            System.err.println("TestServer writing " + hf);
+                        }
+                        writeFrame(hf);
+                        cont++;
+                    } while (next < buffers.size());
                 } else if (frame instanceof OutgoingPushPromise) {
                     handlePush((OutgoingPushPromise)frame);
                 } else
@@ -1322,11 +1393,29 @@ public class Http2TestServerConnection {
     // for the hashmap.
 
     public static class ResponseHeaders extends Http2Frame {
-        HttpHeaders headers;
+        final HttpHeaders headers;
+        final BiPredicate<CharSequence, CharSequence> insertionPolicy;
+
+        final int maxFrameSize;
 
         public ResponseHeaders(HttpHeaders headers) {
+            this(headers, (n,v) -> false);
+        }
+        public ResponseHeaders(HttpHeaders headers, BiPredicate<CharSequence, CharSequence> insertionPolicy) {
+            this(headers, insertionPolicy, Integer.MAX_VALUE);
+        }
+
+        public ResponseHeaders(HttpHeaders headers,
+                               BiPredicate<CharSequence, CharSequence> insertionPolicy,
+                               int maxFrameSize) {
             super(0, 0);
             this.headers = headers;
+            this.insertionPolicy = insertionPolicy;
+            this.maxFrameSize = maxFrameSize;
+        }
+
+        public int getMaxFrameSize() {
+            return maxFrameSize;
         }
 
     }
diff --git a/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java
new file mode 100644
index 00000000000..e12dabb6383
--- /dev/null
+++ b/test/jdk/java/text/Format/MessageFormat/MaxArgumentIndexTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8331446
+ * @summary Enforce the MAX_ARGUMENT_INDEX(10,000) implementation limit for the
+ *          ArgumentIndex element in the MessageFormat pattern syntax. This
+ *          should be checked during construction/applyPattern/readObject and should effectively
+ *          prevent parse/format from being invoked with values over the limit.
+ * @run junit MaxArgumentIndexTest
+ */
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class MaxArgumentIndexTest {
+
+    // A MessageFormat pattern that contains an ArgumentIndex value
+    // which violates this implementation's limit: MAX_ARGUMENT_INDEX(10,000)
+    // As this check is exclusive, 10,000 will violate the limit
+    private static final String VIOLATES_MAX_ARGUMENT_INDEX = "{10000}";
+
+    // Check String constructor enforces the limit
+    @Test
+    public void constructorTest() {
+        assertThrows(IllegalArgumentException.class,
+                () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX));
+    }
+
+    // Check String, Locale constructor enforces the limit
+    @ParameterizedTest
+    @MethodSource
+    public void constructorWithLocaleTest(Locale locale) {
+        assertThrows(IllegalArgumentException.class,
+                () -> new MessageFormat(VIOLATES_MAX_ARGUMENT_INDEX, locale));
+    }
+
+    // Provide some basic common locale values
+    private static Stream<Locale> constructorWithLocaleTest() {
+        return Stream.of(null, Locale.US, Locale.ROOT);
+    }
+
+    // Edge case: Test a locale dependent subformat (with null locale) with a
+    // violating ArgumentIndex. In this instance, the violating ArgumentIndex
+    // will be caught and IAE thrown instead of the NPE
+    @Test
+    public void localeDependentSubFormatTest() {
+        assertThrows(IllegalArgumentException.class,
+                () -> new MessageFormat("{10000,number,short}", null));
+        // For reference
+        assertThrows(NullPointerException.class,
+                () -> new MessageFormat("{999,number,short}", null));
+    }
+
+    // Check that the static format method enforces the limit
+    @Test
+    public void staticFormatTest() {
+        assertThrows(IllegalArgumentException.class,
+                () -> MessageFormat.format(VIOLATES_MAX_ARGUMENT_INDEX, new Object[]{1}));
+    }
+
+    // Check that applyPattern(String) enforces the limit
+    @Test
+    public void applyPatternTest() {
+        MessageFormat mf = new MessageFormat("");
+        assertThrows(IllegalArgumentException.class,
+                () -> mf.applyPattern(VIOLATES_MAX_ARGUMENT_INDEX));
+    }
+}
diff --git a/test/jdk/java/text/Format/MessageFormat/SerializationTest.java b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java
new file mode 100644
index 00000000000..9191c5caef3
--- /dev/null
+++ b/test/jdk/java/text/Format/MessageFormat/SerializationTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8331446
+ * @summary Check correctness of deserialization
+ * @run junit SerializationTest
+ */
+
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class SerializationTest {
+
+    // Ensure basic correctness of serialization round trip
+    @ParameterizedTest
+    @MethodSource
+    public void serializationRoundTrip(MessageFormat expectedMf)
+            throws IOException, ClassNotFoundException {
+        byte[] bytes = ser(expectedMf);
+        MessageFormat actualMf = (MessageFormat) deSer(bytes);
+        assertEquals(expectedMf, actualMf);
+    }
+
+    // Various valid MessageFormats
+    private static Stream<MessageFormat> serializationRoundTrip() {
+        return Stream.of(
+                // basic pattern
+                new MessageFormat("{0} foo"),
+                // Multiple arguments
+                new MessageFormat("{0} {1} foo"),
+                // duplicate arguments
+                new MessageFormat("{0} {0} {1} foo"),
+                // Non-ascending arguments
+                new MessageFormat("{1} {0} foo"),
+                // With locale
+                new MessageFormat("{1} {0} foo", Locale.UK),
+                // With null locale. (NPE not thrown, if no format defined)
+                new MessageFormat("{1} {0} foo", null),
+                // With formats
+                new MessageFormat("{0,number,short} {0} {1,date,long} foo")
+        );
+    }
+
+    // Utility method to serialize
+    private static byte[] ser(Object obj) throws IOException {
+        ByteArrayOutputStream byteArrayOutputStream = new
+                ByteArrayOutputStream();
+        ObjectOutputStream oos = new
+                ObjectOutputStream(byteArrayOutputStream);
+        oos.writeObject(obj);
+        return byteArrayOutputStream.toByteArray();
+    }
+
+    // Utility method to deserialize
+    private static Object deSer(byte[] bytes) throws
+            IOException, ClassNotFoundException {
+        ByteArrayInputStream byteArrayInputStream = new
+                ByteArrayInputStream(bytes);
+        ObjectInputStream ois = new
+                ObjectInputStream(byteArrayInputStream);
+        return ois.readObject();
+    }
+}
diff --git a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java
index 304cb0695d6..120e6b258e6 100644
--- a/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java
+++ b/test/jdk/javax/net/ssl/DTLS/InvalidRecords.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
 
 /*
  * @test
- * @bug 8043758
+ * @bug 8043758 8307383
  * @summary Datagram Transport Layer Security (DTLS)
  * @modules java.base/sun.security.util
  * @library /test/lib
@@ -36,6 +36,7 @@
 
 import java.net.DatagramPacket;
 import java.net.SocketAddress;
+import java.nio.ByteBuffer;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -73,11 +74,34 @@ public class InvalidRecords extends DTLSOverDatagram {
             // ClientHello with cookie
             needInvalidRecords.set(false);
             System.out.println("invalidate ClientHello message");
-            if (ba[ba.length - 1] == (byte)0xFF) {
-                ba[ba.length - 1] = (byte)0xFE;
+            // We will alter the compression method field in order to make the cookie
+            // check fail.
+            ByteBuffer chRec = ByteBuffer.wrap(ba);
+            // Skip 59 bytes past the record header (13), the handshake header (12),
+            // the protocol version (2), and client random (32)
+            chRec.position(59);
+            // Jump past the session ID
+            int len = Byte.toUnsignedInt(chRec.get());
+            chRec.position(chRec.position() + len);
+            // Skip the cookie
+            len = Byte.toUnsignedInt(chRec.get());
+            chRec.position(chRec.position() + len);
+            // Skip past cipher suites
+            len = Short.toUnsignedInt(chRec.getShort());
+            chRec.position(chRec.position() + len);
+            // Read the data on the compression methods, should be at least 1
+            len = Byte.toUnsignedInt(chRec.get());
+            if (len >= 1) {
+                System.out.println("Detected compression methods (count = " + len + ")");
             } else {
                 ba[ba.length - 1] = (byte)0xFF;
+                throw new RuntimeException("Got zero length comp methods");
             }
+            // alter the first comp method.
+            int compMethodVal = Byte.toUnsignedInt(chRec.get(chRec.position()));
+            System.out.println("Changing value at position " + chRec.position() +
+                    " from " + compMethodVal + " to " + ++compMethodVal);
+            chRec.put(chRec.position(), (byte)compMethodVal);
         }
 
         return super.createHandshakePacket(ba, socketAddr);
diff --git a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java
index ee50f21ae27..0867925f135 100644
--- a/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java
+++ b/test/jdk/javax/net/ssl/TLSCommon/MFLNTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,7 +34,15 @@ public class MFLNTest extends SSLEngineTestCase {
     public static void main(String[] args) {
         setUpAndStartKDCIfNeeded();
         System.setProperty("jsse.enableMFLNExtension", "true");
-        for (int mfl = 4096; mfl >= 256; mfl /= 2) {
+        String testMode = System.getProperty("test.mode", "norm");
+        int mflLen;
+        if (testMode.equals("norm_sni")) {
+            mflLen = 512;
+        } else {
+            mflLen = 256;
+        }
+
+        for (int mfl = 4096; mfl >= mflLen; mfl /= 2) {
             System.out.println("=============================================="
                     + "==============");
             System.out.printf("Testsing DTLS handshake with MFL = %d%n", mfl);