diff a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp
--- a/src/hotspot/share/classfile/verifier.cpp
+++ b/src/hotspot/share/classfile/verifier.cpp
@@ -1,7 +1,7 @@
 /*
- * 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.
@@ -62,10 +62,11 @@
 #include "utilities/bytes.hpp"
 
 #define NOFAILOVER_MAJOR_VERSION                       51
 #define NONZERO_PADDING_BYTES_IN_SWITCH_MAJOR_VERSION  51
 #define STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION       52
+#define INLINE_TYPE_MAJOR_VERSION                       56
 #define MAX_ARRAY_DIMENSIONS 255
 
 // Access to external entry for VerifyClassForMajorVersion - old byte code verifier
 
 extern "C" {
@@ -275,11 +276,11 @@
                                 klass->is_subtype_of(refl_serialization_ctor_klass);
 
   return (should_verify_for(klass->class_loader(), should_verify_class) &&
     // return if the class is a bootstrapping class
     // or defineClass specified not to verify by default (flags override passed arg)
-    // We need to skip the following four for bootstraping
+    // We need to skip the following four for bootstrapping
     name != vmSymbols::java_lang_Object() &&
     name != vmSymbols::java_lang_Class() &&
     name != vmSymbols::java_lang_String() &&
     name != vmSymbols::java_lang_Throwable() &&
 
@@ -494,10 +495,17 @@
       ss->print("Expected stackmap frame at this location.");
       break;
     case BAD_STACKMAP:
       ss->print("Invalid stackmap specification.");
       break;
+    case WRONG_INLINE_TYPE:
+      ss->print("Type ");
+      _type.details(ss);
+      ss->print(" and type ");
+      _expected.details(ss);
+      ss->print(" must be identical inline types.");
+      break;
     case UNKNOWN:
     default:
       ShouldNotReachHere();
       ss->print_cr("Unknown");
   }
@@ -614,10 +622,15 @@
   VerificationType vt = VerificationType::reference_type(
                          create_temporary_symbol(sig, (int)strlen(sig)));
   return TypeOrigin::implicit(vt);
 }
 
+static bool supports_strict_fields(InstanceKlass* klass) {
+  int ver = klass->major_version();
+  return ver > Verifier::VALUE_TYPES_MAJOR_VERSION ||
+         (ver == Verifier::VALUE_TYPES_MAJOR_VERSION && klass->minor_version() == Verifier::JAVA_PREVIEW_MINOR_VERSION);
+}
 
 void ClassVerifier::verify_class(TRAPS) {
   log_info(verification)("Verifying class %s with new format", _klass->external_name());
 
   // Either verifying both local and remote classes or just remote classes.
@@ -1681,11 +1694,11 @@
                          "Method expects a return value");
             return;
           }
           // Make sure "this" has been initialized if current method is an
           // <init>.
-          if (_method->name() == vmSymbols::object_initializer_name() &&
+          if (_method->is_object_constructor() &&
               current_frame.flag_this_uninit()) {
             verify_error(ErrorContext::bad_code(bci),
                          "Constructor must call super() or this() "
                          "before return");
             return;
@@ -1704,19 +1717,15 @@
             &bcs, &current_frame, cp, false, CHECK_VERIFY(this));
           no_control_flow = false; break;
         case Bytecodes::_invokevirtual :
         case Bytecodes::_invokespecial :
         case Bytecodes::_invokestatic :
-          verify_invoke_instructions(
-            &bcs, code_length, &current_frame, (bci >= ex_min && bci < ex_max),
-            &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
-          no_control_flow = false; break;
         case Bytecodes::_invokeinterface :
         case Bytecodes::_invokedynamic :
           verify_invoke_instructions(
             &bcs, code_length, &current_frame, (bci >= ex_min && bci < ex_max),
-            &this_uninit, return_type, cp, &stackmap_table, CHECK_VERIFY(this));
+            &this_uninit, cp, &stackmap_table, CHECK_VERIFY(this));
           no_control_flow = false; break;
         case Bytecodes::_new :
         {
           u2 index = bcs.get_index_u2();
           verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
@@ -1770,14 +1779,15 @@
           current_frame.push_stack(
             VerificationType::integer_type(), CHECK_VERIFY(this));
           no_control_flow = false; break;
         }
         case Bytecodes::_monitorenter :
-        case Bytecodes::_monitorexit :
-          current_frame.pop_stack(
+        case Bytecodes::_monitorexit : {
+          VerificationType ref = current_frame.pop_stack(
             VerificationType::reference_check(), CHECK_VERIFY(this));
           no_control_flow = false; break;
+        }
         case Bytecodes::_multianewarray :
         {
           u2 index = bcs.get_index_u2();
           u2 dim = *(bcs.bcp()+3);
           verify_cp_class_type(bci, index, cp, CHECK_VERIFY(this));
@@ -2038,10 +2048,11 @@
   // We must check was_recursively_verified() before we get here.
   guarantee(cp->cache() == nullptr, "not rewritten yet");
 
   verify_cp_index(bci, cp, index, CHECK_VERIFY(this));
   unsigned int tag = cp->tag_at(index).value();
+
   if ((types & (1 << tag)) == 0) {
     verify_error(ErrorContext::bad_cp_index(bci, index),
       "Illegal type at constant pool entry %d in class %s",
       index, cp->pool_holder()->external_name());
     return;
@@ -2152,11 +2163,11 @@
   constantTag tag = cp->tag_at(index);
   unsigned int types = 0;
   if (opcode == Bytecodes::_ldc || opcode == Bytecodes::_ldc_w) {
     if (!tag.is_unresolved_klass()) {
       types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float)
-            | (1 << JVM_CONSTANT_String)  | (1 << JVM_CONSTANT_Class)
+            | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class)
             | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType)
             | (1 << JVM_CONSTANT_Dynamic);
       // Note:  The class file parser already verified the legality of
       // MethodHandle and MethodType constants.
       verify_cp_type(bci, index, cp, types, CHECK_VERIFY(this));
@@ -2328,17 +2339,18 @@
 
   // Get referenced class type
   VerificationType ref_class_type = cp_ref_index_to_type(
     index, cp, CHECK_VERIFY(this));
   if (!ref_class_type.is_object() &&
-    (!allow_arrays || !ref_class_type.is_array())) {
+      (!allow_arrays || !ref_class_type.is_array())) {
     verify_error(ErrorContext::bad_type(bcs->bci(),
         TypeOrigin::cp(index, ref_class_type)),
         "Expecting reference to class in class %s at constant pool index %d",
         _klass->external_name(), index);
     return;
   }
+
   VerificationType target_class_type = ref_class_type;
 
   assert(sizeof(VerificationType) == sizeof(uintptr_t),
         "buffer type must match VerificationType size");
   uintptr_t field_type_buffer[2];
@@ -2376,17 +2388,27 @@
       for (int i = n - 1; i >= 0; i--) {
         current_frame->pop_stack(field_type[i], CHECK_VERIFY(this));
       }
       stack_object_type = current_frame->pop_stack(CHECK_VERIFY(this));
 
-      // The JVMS 2nd edition allows field initialization before the superclass
+      // Field initialization is allowed before the superclass
       // initializer, if the field is defined within the current class.
       fieldDescriptor fd;
-      if (stack_object_type == VerificationType::uninitialized_this_type() &&
-          target_class_type.equals(current_type()) &&
-          _klass->find_local_field(field_name, field_sig, &fd)) {
-        stack_object_type = current_type();
+      bool is_local_field = _klass->find_local_field(field_name, field_sig, &fd) &&
+                            target_class_type.equals(current_type());
+      if (stack_object_type == VerificationType::uninitialized_this_type()) {
+        if (is_local_field) {
+          // Set the type to the current type so the is_assignable check passes.
+          stack_object_type = current_type();
+        }
+      } else if (supports_strict_fields(_klass)) {
+        // `strict` fields are not writable, but only local fields produce verification errors
+        if (is_local_field && fd.access_flags().is_strict()) {
+          verify_error(ErrorContext::bad_code(bci),
+                       "Illegal use of putfield on a strict field");
+          return;
+        }
       }
       is_assignable = target_class_type.is_assignable_from(
         stack_object_type, this, false, CHECK_VERIFY(this));
       if (!is_assignable) {
         verify_error(ErrorContext::bad_type(bci,
@@ -2787,11 +2809,11 @@
   return false;
 }
 
 void ClassVerifier::verify_invoke_instructions(
     RawBytecodeStream* bcs, u4 code_length, StackMapFrame* current_frame,
-    bool in_try_block, bool *this_uninit, VerificationType return_type,
+    bool in_try_block, bool *this_uninit,
     const constantPoolHandle& cp, StackMapTable* stackmap_table, TRAPS) {
   // Make sure the constant pool item is the right type
   u2 index = bcs->get_index_u2();
   Bytecodes::Code opcode = bcs->raw_code();
   unsigned int types = 0;
@@ -2819,11 +2841,11 @@
 
   // Method signature was checked in ClassFileParser.
   assert(SignatureVerifier::is_valid_method_signature(method_sig),
          "Invalid method signature");
 
-  // Get referenced class type
+  // Get referenced class
   VerificationType ref_class_type;
   if (opcode == Bytecodes::_invokedynamic) {
     if (_klass->major_version() < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
       class_format_error(
         "invokedynamic instructions not supported by this class file version (%d), class %s",
@@ -2885,21 +2907,22 @@
       return;
     }
   }
 
   if (method_name->char_at(0) == JVM_SIGNATURE_SPECIAL) {
-    // Make sure <init> can only be invoked by invokespecial
+    // Make sure:
+    //   <init> can only be invoked by invokespecial.
     if (opcode != Bytecodes::_invokespecial ||
-        method_name != vmSymbols::object_initializer_name()) {
+          method_name != vmSymbols::object_initializer_name()) {
       verify_error(ErrorContext::bad_code(bci),
           "Illegal call to internal method");
       return;
     }
   } else if (opcode == Bytecodes::_invokespecial
              && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type)
              && !ref_class_type.equals(VerificationType::reference_type(
-                  current_class()->super()->name()))) {
+                  current_class()->super()->name()))) { // super() can never be an inline_type.
     bool subtype = false;
     bool have_imr_indirect = cp->tag_at(index).value() == JVM_CONSTANT_InterfaceMethodref;
     subtype = ref_class_type.is_assignable_from(
                current_type(), this, false, CHECK_VERIFY(this));
     if (!subtype) {
@@ -2980,13 +3003,11 @@
   }
   // Push the result type.
   int sig_verif_types_len = sig_verif_types->length();
   if (sig_verif_types_len > nargs) {  // There's a return type
     if (method_name == vmSymbols::object_initializer_name()) {
-      // <init> method must have a void return type
-      /* Unreachable?  Class file parser verifies that methods with '<' have
-       * void return */
+      // an <init> method must have a void return type
       verify_error(ErrorContext::bad_code(bci),
           "Return type must be void in <init> method");
       return;
     }
 
