diff a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp
--- a/src/hotspot/share/opto/output.cpp
+++ b/src/hotspot/share/opto/output.cpp
@@ -31,10 +31,11 @@
 #include "compiler/compileBroker.hpp"
 #include "compiler/compilerDirectives.hpp"
 #include "compiler/disassembler.hpp"
 #include "compiler/oopMap.hpp"
 #include "gc/shared/barrierSet.hpp"
+#include "gc/shared/gc_globals.hpp"
 #include "gc/shared/c2/barrierSetC2.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/allocation.hpp"
 #include "opto/ad.hpp"
 #include "opto/block.hpp"
@@ -244,11 +245,19 @@
     _buf_sizes(),
     _block(nullptr),
     _index(0) {
   C->set_output(this);
   if (C->stub_name() == nullptr) {
-    _orig_pc_slot = C->fixed_slots() - (sizeof(address) / VMRegImpl::stack_slot_size);
+    int fixed_slots = C->fixed_slots();
+    if (C->needs_stack_repair()) {
+      fixed_slots -= 2;
+    }
+    // TODO 8284443 Only reserve extra slot if needed
+    if (InlineTypeReturnedAsFields) {
+      fixed_slots -= 2;
+    }
+    _orig_pc_slot = fixed_slots - (sizeof(address) / VMRegImpl::stack_slot_size);
   }
 }
 
 PhaseOutput::~PhaseOutput() {
   C->set_output(nullptr);
@@ -285,28 +294,38 @@
   Block *broot = C->cfg()->get_root_block();
 
   const StartNode *start = entry->head()->as_Start();
 
   // Replace StartNode with prolog
-  MachPrologNode *prolog = new MachPrologNode();
+  Label verified_entry;
+  MachPrologNode* prolog = new MachPrologNode(&verified_entry);
   entry->map_node(prolog, 0);
   C->cfg()->map_node_to_block(prolog, entry);
   C->cfg()->unmap_node_from_block(start); // start is no longer in any block
 
   // Virtual methods need an unverified entry point
-
-  if( C->is_osr_compilation() ) {
-    if( PoisonOSREntry ) {
+  if (C->is_osr_compilation()) {
+    if (PoisonOSREntry) {
       // TODO: Should use a ShouldNotReachHereNode...
       C->cfg()->insert( broot, 0, new MachBreakpointNode() );
     }
   } else {
-    if( C->method() && !C->method()->flags().is_static() ) {
-      // Insert unvalidated entry point
-      C->cfg()->insert( broot, 0, new MachUEPNode() );
+    if (C->method()) {
+      if (C->method()->has_scalarized_args()) {
+        // Add entry point to unpack all inline type arguments
+        C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ true, /* receiver_only */ false));
+        if (!C->method()->is_static()) {
+          // Add verified/unverified entry points to only unpack inline type receiver at interface calls
+          C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ false, /* receiver_only */ false));
+          C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ true,  /* receiver_only */ true));
+          C->cfg()->insert(broot, 0, new MachVEPNode(&verified_entry, /* verified */ false, /* receiver_only */ true));
+        }
+      } else if (!C->method()->is_static()) {
+        // Insert unvalidated entry point
+        C->cfg()->insert(broot, 0, new MachUEPNode());
+      }
     }
-
   }
 
   // Break before main entry point
   if ((C->method() && C->directive()->BreakAtExecuteOption) ||
       (OptoBreakpoint && C->is_method_compilation())       ||
@@ -342,10 +361,35 @@
   // Must be done before ScheduleAndBundle due to SPARC delay slots
   uint* blk_starts = NEW_RESOURCE_ARRAY(uint, C->cfg()->number_of_blocks() + 1);
   blk_starts[0] = 0;
   shorten_branches(blk_starts);
 
+  if (!C->is_osr_compilation() && C->has_scalarized_args()) {
+    // Compute the offsets of the entry points required by the inline type calling convention
+    if (!C->method()->is_static()) {
+      // We have entries at the beginning of the method, implemented by the first 4 nodes.
+      // Entry                     (unverified) @ offset 0
+      // Verified_Inline_Entry_RO
+      // Inline_Entry              (unverified)
+      // Verified_Inline_Entry
+      uint offset = 0;
+      _code_offsets.set_value(CodeOffsets::Entry, offset);
+
+      offset += ((MachVEPNode*)broot->get_node(0))->size(C->regalloc());
+      _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, offset);
+
+      offset += ((MachVEPNode*)broot->get_node(1))->size(C->regalloc());
+      _code_offsets.set_value(CodeOffsets::Inline_Entry, offset);
+
+      offset += ((MachVEPNode*)broot->get_node(2))->size(C->regalloc());
+      _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, offset);
+    } else {
+      _code_offsets.set_value(CodeOffsets::Entry, -1); // will be patched later
+      _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, 0);
+    }
+  }
+
   ScheduleAndBundle();
   if (C->failing()) {
     return;
   }
 
@@ -503,11 +547,13 @@
           reloc_size += CallStubImpl::reloc_call_trampoline();
 
           MachCallNode *mcall = mach->as_MachCall();
           // This destination address is NOT PC-relative
 
-          mcall->method_set((intptr_t)mcall->entry_point());
+          if (mcall->entry_point() != nullptr) {
+            mcall->method_set((intptr_t)mcall->entry_point());
+          }
 
           if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
             stub_size  += CompiledDirectCall::to_interp_stub_size();
             reloc_size += CompiledDirectCall::reloc_to_interp_stub();
           }
@@ -758,15 +804,31 @@
     ObjectValue* sv = sv_for_node_id(objs, spobj->_idx);
     if (sv == nullptr) {
       ciKlass* cik = t->is_oopptr()->exact_klass();
       assert(cik->is_instance_klass() ||
              cik->is_array_klass(), "Not supported allocation.");
+      uint first_ind = spobj->first_index(sfpt->jvms());
+      // Nullable, scalarized inline types have an is_init input
+      // that needs to be checked before using the field values.
+      ScopeValue* is_init = nullptr;
+      if (cik->is_inlinetype()) {
+        Node* init_node = sfpt->in(first_ind++);
+        assert(init_node != nullptr, "is_init node not found");
+        if (!init_node->is_top()) {
+          const TypeInt* init_type = init_node->bottom_type()->is_int();
+          if (init_node->is_Con()) {
+            is_init = new ConstantIntValue(init_type->get_con());
+          } else {
+            OptoReg::Name init_reg = C->regalloc()->get_reg_first(init_node);
+            is_init = new_loc_value(C->regalloc(), init_reg, Location::normal);
+          }
+        }
+      }
       sv = new ObjectValue(spobj->_idx,
-                           new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()));
+                           new ConstantOopWriteValue(cik->java_mirror()->constant_encoding()), true, is_init);
       set_sv_for_object_node(objs, sv);
 
-      uint first_ind = spobj->first_index(sfpt->jvms());
       for (uint i = 0; i < spobj->n_fields(); i++) {
         Node* fld_node = sfpt->in(first_ind+i);
         (void)FillLocArray(sv->field_values()->length(), sfpt, fld_node, sv->field_values(), objs);
       }
     }
@@ -1009,10 +1071,11 @@
   MachCallNode      *mcall;
 
   int safepoint_pc_offset = current_offset;
   bool is_method_handle_invoke = false;
   bool return_oop = false;
+  bool return_scalarized = false;
   bool has_ea_local_in_scope = sfn->_has_ea_local_in_scope;
   bool arg_escape = false;
 
   // Add the safepoint in the DebugInfoRecorder
   if( !mach->is_MachCall() ) {
@@ -1029,13 +1092,16 @@
       }
       arg_escape = mcall->as_MachCallJava()->_arg_escape;
     }
 
     // Check if a call returns an object.
-    if (mcall->returns_pointer()) {
+    if (mcall->returns_pointer() || mcall->returns_scalarized()) {
       return_oop = true;
     }
+    if (mcall->returns_scalarized()) {
+      return_scalarized = true;
+    }
     safepoint_pc_offset += mcall->ret_addr_offset();
     C->debug_info()->add_safepoint(safepoint_pc_offset, mcall->_oop_map);
   }
 
   // Loop over the JVMState list to add scope information
@@ -1210,10 +1276,11 @@
       jvms->bci(),
       jvms->should_reexecute(),
       rethrow_exception,
       is_method_handle_invoke,
       return_oop,
+      return_scalarized,
       has_ea_local_in_scope,
       arg_escape,
       locvals,
       expvals,
       monvals
@@ -1584,12 +1651,14 @@
         bool observe_safepoint = is_sfn;
         // Remember the start of the last call in a basic block
         if (is_mcall) {
           MachCallNode *mcall = mach->as_MachCall();
 
-          // This destination address is NOT PC-relative
-          mcall->method_set((intptr_t)mcall->entry_point());
+          if (mcall->entry_point() != nullptr) {
+            // This destination address is NOT PC-relative
+            mcall->method_set((intptr_t)mcall->entry_point());
+          }
 
           // Save the return address
           call_returns[block->_pre_order] = current_offset + mcall->ret_addr_offset();
 
           observe_safepoint = mcall->guaranteed_safepoint();
@@ -1726,11 +1795,10 @@
         return;
       }
 
       assert(!is_mcall || (call_returns[block->_pre_order] <= (uint)current_offset),
              "ret_addr_offset() not within emitted code");
-
 #ifdef ASSERT
       uint n_size = n->size(C->regalloc());
       if (n_size < (current_offset-instr_offset)) {
         MachNode* mach = n->as_Mach();
         n->dump();
@@ -3162,10 +3230,23 @@
             t->is_ptr()->offset() != 0 ) {
           last_safept_node->add_prec( m );
           break;
         }
       }
+
+      // Do not allow a CheckCastPP node whose input is a raw pointer to
+      // float past a safepoint.  This can occur when a buffered inline
+      // type is allocated in a loop and the CheckCastPP from that
+      // allocation is reused outside the loop.  If the use inside the
+      // loop is scalarized the CheckCastPP will no longer be connected
+      // to the loop safepoint.  See JDK-8264340.
+      if (m->is_Mach() && m->as_Mach()->ideal_Opcode() == Op_CheckCastPP) {
+        Node *def = m->in(1);
+        if (def != nullptr && def->bottom_type()->base() == Type::RawPtr) {
+          last_safept_node->add_prec(m);
+        }
+      }
     }
 
     if( n->jvms() ) {           // Precedence edge from derived to safept
       // Check if last_safept_node was moved by pinch-point insertion in anti_do_use()
       if( b->get_node(last_safept) != last_safept_node ) {
@@ -3320,10 +3401,29 @@
     }
 
     ResourceMark rm;
     _scratch_const_size = const_size;
     int size = C2Compiler::initial_code_buffer_size(const_size);
+    if (C->has_scalarized_args()) {
+      // Inline type entry points (MachVEPNodes) require lots of space for GC barriers and oop verification
+      // when loading object fields from the buffered argument. Increase scratch buffer size accordingly.
+      ciMethod* method = C->method();
+      int barrier_size = UseZGC ? 200 : (7 DEBUG_ONLY(+ 37));
+      int arg_num = 0;
+      if (!method->is_static()) {
+        if (method->is_scalarized_arg(arg_num)) {
+          size += method->holder()->as_inline_klass()->oop_count() * barrier_size;
+        }
+        arg_num++;
+      }
+      for (ciSignatureStream str(method->signature()); !str.at_return_type(); str.next()) {
+        if (method->is_scalarized_arg(arg_num)) {
+          size += str.type()->as_inline_klass()->oop_count() * barrier_size;
+        }
+        arg_num++;
+      }
+    }
     blob = BufferBlob::create("Compile::scratch_buffer", size);
     // Record the buffer blob for next time.
     set_scratch_buffer_blob(blob);
     // Have we run out of code space?
     if (scratch_buffer_blob() == nullptr) {
@@ -3390,12 +3490,14 @@
   n->emit(&masm, C->regalloc());
 
   // Emitting into the scratch buffer should not fail
   assert(!C->failing_internal() || C->failure_is_artificial(), "Must not have pending failure. Reason is: %s", C->failure_reason());
 
-  if (is_branch) // Restore label.
+  // Restore label.
+  if (is_branch) {
     n->as_MachBranch()->label_set(saveL, save_bnum);
+  }
 
   // End scratch_emit_size section.
   set_in_scratch_emit_size(false);
 
   return buf.insts_size();
@@ -3432,35 +3534,38 @@
 
     if (C->is_osr_compilation()) {
       _code_offsets.set_value(CodeOffsets::Verified_Entry, 0);
       _code_offsets.set_value(CodeOffsets::OSR_Entry, _first_block_size);
     } else {
-      if (!target->is_static()) {
-        // The UEP of an nmethod ensures that the VEP is padded. However, the padding of the UEP is placed
-        // before the inline cache check, so we don't have to execute any nop instructions when dispatching
-        // through the UEP, yet we can ensure that the VEP is aligned appropriately.
-        _code_offsets.set_value(CodeOffsets::Entry, _first_block_size - MacroAssembler::ic_check_size());
-      }
       _code_offsets.set_value(CodeOffsets::Verified_Entry, _first_block_size);
+      if (_code_offsets.value(CodeOffsets::Verified_Inline_Entry) == -1) {
+        _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry, _first_block_size);
+      }
+      if (_code_offsets.value(CodeOffsets::Verified_Inline_Entry_RO) == -1) {
+        _code_offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, _first_block_size);
+      }
+      if (_code_offsets.value(CodeOffsets::Entry) == -1) {
+        _code_offsets.set_value(CodeOffsets::Entry, _first_block_size);
+      }
       _code_offsets.set_value(CodeOffsets::OSR_Entry, 0);
     }
 
     C->env()->register_method(target,
-                                     entry_bci,
-                                     &_code_offsets,
-                                     _orig_pc_slot_offset_in_bytes,
-                                     code_buffer(),
-                                     frame_size_in_words(),
-                                     oop_map_set(),
-                                     &_handler_table,
-                                     inc_table(),
-                                     compiler,
-                                     has_unsafe_access,
-                                     SharedRuntime::is_wide_vector(C->max_vector_size()),
-                                     C->has_monitors(),
-                                     C->has_scoped_access(),
-                                     0);
+                              entry_bci,
+                              &_code_offsets,
+                              _orig_pc_slot_offset_in_bytes,
+                              code_buffer(),
+                              frame_size_in_words(),
+                              _oop_map_set,
+                              &_handler_table,
+                              inc_table(),
+                              compiler,
+                              has_unsafe_access,
+                              SharedRuntime::is_wide_vector(C->max_vector_size()),
+                              C->has_monitors(),
+                              C->has_scoped_access(),
+                              0);
 
     if (C->log() != nullptr) { // Print code cache state into compiler log
       C->log()->code_cache_state();
     }
   }
