diff a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
--- a/src/hotspot/share/oops/method.cpp
+++ b/src/hotspot/share/oops/method.cpp
@@ -58,10 +58,11 @@
 #include "oops/methodData.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
+#include "oops/inlineKlass.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/methodHandles.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/continuationEntry.hpp"
@@ -118,11 +119,10 @@
 
   if (access_flags.is_native()) {
     clear_native_function();
     set_signature_handler(nullptr);
   }
-
   NOT_PRODUCT(set_compiled_invocation_count(0);)
   // Name is very useful for debugging.
   NOT_PRODUCT(_name = name;)
 }
 
@@ -156,15 +156,25 @@
 address Method::get_c2i_entry() {
   assert(adapter() != nullptr, "must have");
   return adapter()->get_c2i_entry();
 }
 
+address Method::get_c2i_inline_entry() {
+  assert(adapter() != nullptr, "must have");
+  return adapter()->get_c2i_inline_entry();
+}
+
 address Method::get_c2i_unverified_entry() {
   assert(adapter() != nullptr, "must have");
   return adapter()->get_c2i_unverified_entry();
 }
 
+address Method::get_c2i_unverified_inline_entry() {
+  assert(adapter() != nullptr, "must have");
+  return adapter()->get_c2i_unverified_inline_entry();
+}
+
 address Method::get_c2i_no_clinit_check_entry() {
   assert(VM_Version::supports_fast_class_init_checks(), "");
   assert(adapter() != nullptr, "must have");
   return adapter()->get_c2i_no_clinit_check_entry();
 }
@@ -385,11 +395,11 @@
 }
 
 void Method::metaspace_pointers_do(MetaspaceClosure* it) {
   log_trace(cds)("Iter(Method): %p", this);
 
-  if (!method_holder()->is_rewritten()) {
+  if (!method_holder()->is_rewritten() || CDSConfig::is_valhalla_preview()) {
     it->push(&_constMethod, MetaspaceClosure::_writable);
   } else {
     it->push(&_constMethod);
   }
   it->push(&_method_data);
@@ -662,10 +672,26 @@
 int Method::extra_stack_words() {
   // not an inline function, to avoid a header dependency on Interpreter
   return extra_stack_entries() * Interpreter::stackElementSize;
 }
 
+// InlineKlass the method is declared to return. This must not
+// safepoint as it is called with references live on the stack at
+// locations the GC is unaware of.
+InlineKlass* Method::returns_inline_type(Thread* thread) const {
+  assert(InlineTypeReturnedAsFields, "Inline types should never be returned as fields");
+  if (is_native()) {
+    return nullptr;
+  }
+  NoSafepointVerifier nsv;
+  SignatureStream ss(signature());
+  while (!ss.at_return_type()) {
+    ss.next();
+  }
+  return ss.as_inline_klass(method_holder());
+}
+
 bool Method::compute_has_loops_flag() {
   BytecodeStream bcs(methodHandle(Thread::current(), this));
   Bytecodes::Code bc;
 
   while ((bc = bcs.next()) >= 0) {
@@ -810,10 +836,15 @@
     case Bytecodes::_areturn:
       break;
     default:
       return false;
   }
+  if (has_scalarized_return()) {
+    // Don't treat this as (trivial) getter method because the
+    // inline type should be returned in a scalarized form.
+    return false;
+  }
   return true;
 }
 
 bool Method::is_setter() const {
   if (code_size() != 6) return false;
@@ -831,38 +862,41 @@
     default:
       return false;
   }
   if (java_code_at(2) != Bytecodes::_putfield) return false;
   if (java_code_at(5) != Bytecodes::_return)   return false;
+  if (has_scalarized_args()) {
+    // Don't treat this as (trivial) setter method because the
+    // inline type argument should be passed in a scalarized form.
+    return false;
+  }
   return true;
 }
 
 bool Method::is_constant_getter() const {
   int last_index = code_size() - 1;
   // Check if the first 1-3 bytecodes are a constant push
   // and the last bytecode is a return.
   return (2 <= code_size() && code_size() <= 4 &&
           Bytecodes::is_const(java_code_at(0)) &&
           Bytecodes::length_for(java_code_at(0)) == last_index &&
-          Bytecodes::is_return(java_code_at(last_index)));
+          Bytecodes::is_return(java_code_at(last_index)) &&
+          !has_scalarized_args());
 }
 
-bool Method::has_valid_initializer_flags() const {
-  return (is_static() ||
-          method_holder()->major_version() < 51);
-}
-
-bool Method::is_static_initializer() const {
+bool Method::is_class_initializer() const {
   // For classfiles version 51 or greater, ensure that the clinit method is
   // static.  Non-static methods with the name "<clinit>" are not static
   // initializers. (older classfiles exempted for backward compatibility)
-  return name() == vmSymbols::class_initializer_name() &&
-         has_valid_initializer_flags();
+  return (name() == vmSymbols::class_initializer_name() &&
+          (is_static() ||
+           method_holder()->major_version() < 51));
 }
 
-bool Method::is_object_initializer() const {
-   return name() == vmSymbols::object_initializer_name();
+// A method named <init>, is a classic object constructor.
+bool Method::is_object_constructor() const {
+  return name() == vmSymbols::object_initializer_name();
 }
 
 bool Method::needs_clinit_barrier() const {
   return is_static() && !method_holder()->is_initialized();
 }
@@ -916,11 +950,11 @@
   return best_line;
 }
 
 
 bool Method::is_klass_loaded_by_klass_index(int klass_index) const {
-  if( constants()->tag_at(klass_index).is_unresolved_klass() ) {
+  if( constants()->tag_at(klass_index).is_unresolved_klass()) {
     Thread *thread = Thread::current();
     Symbol* klass_name = constants()->klass_name_at(klass_index);
     Handle loader(thread, method_holder()->class_loader());
     Handle prot  (thread, method_holder()->protection_domain());
     return SystemDictionary::find_instance_klass(thread, klass_name, loader, prot) != nullptr;
@@ -932,11 +966,13 @@
 
 bool Method::is_klass_loaded(int refinfo_index, Bytecodes::Code bc, bool must_be_resolved) const {
   int klass_index = constants()->klass_ref_index_at(refinfo_index, bc);
   if (must_be_resolved) {
     // Make sure klass is resolved in constantpool.
-    if (constants()->tag_at(klass_index).is_unresolved_klass()) return false;
+    if (constants()->tag_at(klass_index).is_unresolved_klass()) {
+      return false;
+    }
   }
   return is_klass_loaded_by_klass_index(klass_index);
 }
 
 
@@ -1101,12 +1137,16 @@
 void Method::clear_code() {
   // this may be null if c2i adapters have not been made yet
   // Only should happen at allocate time.
   if (adapter() == nullptr) {
     _from_compiled_entry    = nullptr;
+    _from_compiled_inline_entry = nullptr;
+    _from_compiled_inline_ro_entry = nullptr;
   } else {
     _from_compiled_entry    = adapter()->get_c2i_entry();
+    _from_compiled_inline_entry = adapter()->get_c2i_inline_entry();
+    _from_compiled_inline_ro_entry = adapter()->get_c2i_inline_ro_entry();
   }
   OrderAccess::storestore();
   _from_interpreted_entry = _i2i_entry;
   OrderAccess::storestore();
   _code = nullptr;
@@ -1134,10 +1174,12 @@
   assert(CDSConfig::is_dumping_archive(), "sanity");
   _code = nullptr;
   _adapter = nullptr;
   _i2i_entry = nullptr;
   _from_compiled_entry = nullptr;
+  _from_compiled_inline_entry = nullptr;
+  _from_compiled_inline_ro_entry = nullptr;
   _from_interpreted_entry = nullptr;
 
   if (is_native()) {
     *native_function_addr() = nullptr;
     set_signature_handler(nullptr);
@@ -1159,10 +1201,12 @@
   set_queued_for_compilation(false);
   set_is_not_c2_compilable(false);
   set_is_not_c1_compilable(false);
   set_is_not_c2_osr_compilable(false);
   set_on_stack_flag(false);
+  set_has_scalarized_args(false);
+  set_has_scalarized_return(false);
 }
 #endif
 
 // Called when the method_holder is getting linked. Setup entrypoints so the method
 // is ready to be called from interpreter, compiler, and vtables.
@@ -1191,10 +1235,13 @@
   if (is_native() && !has_native_function()) {
     set_native_function(
       SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
       !native_bind_event_is_interesting);
   }
+  if (InlineTypeReturnedAsFields && returns_inline_type(THREAD) && !has_scalarized_return()) {
+    set_has_scalarized_return();
+  }
 
   // Setup compiler entrypoint.  This is made eagerly, so we do not need
   // special handling of vtables.  An alternative is to make adapters more
   // lazily by calling make_adapter() from from_compiled_entry() for the
   // normal calls.  For vtable calls life gets more complicated.  When a
@@ -1239,10 +1286,12 @@
     }
   }
 
   mh->set_adapter_entry(adapter);
   mh->_from_compiled_entry = adapter->get_c2i_entry();
+  mh->_from_compiled_inline_entry = adapter->get_c2i_inline_entry();
+  mh->_from_compiled_inline_ro_entry = adapter->get_c2i_inline_ro_entry();
   return adapter->get_c2i_entry();
 }
 
 // The verified_code_entry() must be called when a invoke is resolved
 // on this method.
@@ -1255,10 +1304,22 @@
   debug_only(NoSafepointVerifier nsv;)
   assert(_from_compiled_entry != nullptr, "must be set");
   return _from_compiled_entry;
 }
 
+address Method::verified_inline_code_entry() {
+  debug_only(NoSafepointVerifier nsv;)
+  assert(_from_compiled_inline_entry != nullptr, "must be set");
+  return _from_compiled_inline_entry;
+}
+
+address Method::verified_inline_ro_code_entry() {
+  debug_only(NoSafepointVerifier nsv;)
+  assert(_from_compiled_inline_ro_entry != nullptr, "must be set");
+  return _from_compiled_inline_ro_entry;
+}
+
 // Check that if an nmethod ref exists, it has a backlink to this or no backlink at all
 // (could be racing a deopt).
 // Not inline to avoid circular ref.
 bool Method::check_code() const {
   // cached in a register or local.  There's a race on the value of the field.
@@ -1286,10 +1347,12 @@
     mh->set_highest_comp_level(comp_level);
   }
 
   OrderAccess::storestore();
   mh->_from_compiled_entry = code->verified_entry_point();
+  mh->_from_compiled_inline_entry = code->verified_inline_entry_point();
+  mh->_from_compiled_inline_ro_entry = code->verified_inline_ro_entry_point();
   OrderAccess::storestore();
 
   if (mh->is_continuation_native_intrinsic()) {
     assert(mh->_from_interpreted_entry == nullptr, "initialized incorrectly"); // see link_method
 
@@ -2263,10 +2326,35 @@
   } else {
     return false;
   }
 }
 
+bool Method::is_scalarized_arg(int idx) const {
+  if (!has_scalarized_args()) {
+    return false;
+  }
+  // Search through signature and check if argument is wrapped in T_METADATA/T_VOID
+  int depth = 0;
+  const GrowableArray<SigEntry>* sig = adapter()->get_sig_cc();
+  for (int i = 0; i < sig->length(); i++) {
+    BasicType bt = sig->at(i)._bt;
+    if (bt == T_METADATA) {
+      depth++;
+    }
+    if (idx == 0) {
+      break; // Argument found
+    }
+    if (bt == T_VOID && (sig->at(i-1)._bt != T_LONG && sig->at(i-1)._bt != T_DOUBLE)) {
+      depth--;
+    }
+    if (depth == 0 && bt != T_LONG && bt != T_DOUBLE) {
+      idx--; // Advance to next argument
+    }
+  }
+  return depth != 0;
+}
+
 #ifndef PRODUCT
 void Method::print_jmethod_ids_count(const ClassLoaderData* loader_data, outputStream* out) {
   out->print("%d", loader_data->jmethod_ids()->count_methods());
 }
 #endif // PRODUCT
@@ -2295,18 +2383,24 @@
   if (intrinsic_id() != vmIntrinsics::_none)
     st->print_cr(" - intrinsic id:      %d %s", vmIntrinsics::as_int(intrinsic_id()), vmIntrinsics::name_at(intrinsic_id()));
   if (highest_comp_level() != CompLevel_none)
     st->print_cr(" - highest level:     %d", highest_comp_level());
   st->print_cr(" - vtable index:      %d",   _vtable_index);
+#ifdef ASSERT
+  if (valid_itable_index())
+    st->print_cr(" - itable index:      %d",   itable_index());
+#endif
   st->print_cr(" - i2i entry:         " PTR_FORMAT, p2i(interpreter_entry()));
   st->print(   " - adapters:          ");
   AdapterHandlerEntry* a = ((Method*)this)->adapter();
   if (a == nullptr)
     st->print_cr(PTR_FORMAT, p2i(a));
   else
     a->print_adapter_on(st);
-  st->print_cr(" - compiled entry     " PTR_FORMAT, p2i(from_compiled_entry()));
+  st->print_cr(" - compiled entry           " PTR_FORMAT, p2i(from_compiled_entry()));
+  st->print_cr(" - compiled inline entry    " PTR_FORMAT, p2i(from_compiled_inline_entry()));
+  st->print_cr(" - compiled inline ro entry " PTR_FORMAT, p2i(from_compiled_inline_ro_entry()));
   st->print_cr(" - code size:         %d",   code_size());
   if (code_size() != 0) {
     st->print_cr(" - code start:        " PTR_FORMAT, p2i(code_base()));
     st->print_cr(" - code end (excl):   " PTR_FORMAT, p2i(code_base() + code_size()));
   }
@@ -2372,10 +2466,11 @@
 void Method::print_value_on(outputStream* st) const {
   assert(is_method(), "must be method");
   st->print("%s", internal_name());
   print_address_on(st);
   st->print(" ");
+  if (WizardMode) access_flags().print_on(st);
   name()->print_value_on(st);
   st->print(" ");
   signature()->print_value_on(st);
   st->print(" in ");
   method_holder()->print_value_on(st);
