diff a/src/hotspot/share/ci/ciInstanceKlass.cpp b/src/hotspot/share/ci/ciInstanceKlass.cpp
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp
@@ -22,22 +22,25 @@
  *
  */
 
 #include "precompiled.hpp"
 #include "ci/ciField.hpp"
+#include "ci/ciInlineKlass.hpp"
 #include "ci/ciInstance.hpp"
 #include "ci/ciInstanceKlass.hpp"
 #include "ci/ciUtilities.inline.hpp"
 #include "classfile/javaClasses.hpp"
+#include "classfile/systemDictionary.hpp"
 #include "classfile/vmClasses.hpp"
 #include "memory/allocation.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/instanceKlass.inline.hpp"
 #include "oops/klass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/fieldStreams.inline.hpp"
+#include "oops/inlineKlass.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
 
 // ciInstanceKlass
@@ -117,17 +120,18 @@
   _field_cache = nullptr;
 }
 
 // Version for unloaded classes:
 ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
-                                 jobject loader, jobject protection_domain)
-  : ciKlass(name, T_OBJECT)
+                                 jobject loader, jobject protection_domain,
+                                 BasicType bt)
+  : ciKlass(name, bt)
 {
   assert(name->char_at(0) != JVM_SIGNATURE_ARRAY, "not an instance klass");
   _init_state = (InstanceKlass::ClassState)0;
   _has_nonstatic_fields = false;
-  _nonstatic_fields = nullptr;
+  _nonstatic_fields = nullptr;         // initialized lazily by compute_nonstatic_fields
   _has_injected_fields = -1;
   _is_hidden = false;
   _is_record = false;
   _loader = loader;
   _protection_domain = protection_domain;
@@ -335,15 +339,15 @@
               bool_to_str(is_initialized()),
               bool_to_str(has_finalizer()),
               bool_to_str(has_subklass()),
               layout_helper());
 
-    _flags.print_klass_flags();
+    _flags.print_klass_flags(st);
 
     if (_super) {
       st->print(" super=");
-      _super->print_name();
+      _super->print_name_on(st);
     }
     if (_java_mirror) {
       st->print(" mirror=PRESENT");
     }
   }
@@ -433,10 +437,33 @@
   }
   ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
   return field;
 }
 
+ciField* ciInstanceKlass::get_non_flat_field_by_offset(int field_offset) {
+  if (super() != nullptr && super()->has_nonstatic_fields()) {
+    ciField* f = super()->get_non_flat_field_by_offset(field_offset);
+    if (f != nullptr) {
+      return f;
+    }
+  }
+
+  VM_ENTRY_MARK;
+  InstanceKlass* k = get_instanceKlass();
+  Arena* arena = CURRENT_ENV->arena();
+  for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
+    if (fs.access_flags().is_static())  continue;
+    fieldDescriptor& fd = fs.field_descriptor();
+    if (fd.offset() == field_offset) {
+      ciField* f = new (arena) ciField(&fd);
+      return f;
+    }
+  }
+
+  return nullptr;
+}
+
 // ------------------------------------------------------------------
 // ciInstanceKlass::get_field_by_name
 ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
   VM_ENTRY_MARK;
   InstanceKlass* k = get_instanceKlass();
@@ -491,22 +518,15 @@
     } else {
       return 0;
     }
   }
 
-  int flen = fields->length();
-
-  // Now sort them by offset, ascending.
-  // (In principle, they could mix with superclass fields.)
-  fields->sort(sort_field_by_offset);
   _nonstatic_fields = fields;
-  return flen;
+  return fields->length();
 }
 
-GrowableArray<ciField*>*
-ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
-                                               super_fields) {
+GrowableArray<ciField*>* ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields, bool is_flat) {
   ASSERT_IN_VM;
   Arena* arena = CURRENT_ENV->arena();
   int flen = 0;
   GrowableArray<ciField*>* fields = nullptr;
   InstanceKlass* k = get_instanceKlass();
@@ -528,14 +548,37 @@
   }
 
   for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
     if (fs.access_flags().is_static())  continue;
     fieldDescriptor& fd = fs.field_descriptor();
-    ciField* field = new (arena) ciField(&fd);
-    fields->append(field);
+    if (fd.is_flat() && is_flat) {
+      // Inline type fields are embedded
+      int field_offset = fd.offset();
+      // Get InlineKlass and adjust number of fields
+      Klass* k = get_instanceKlass()->get_inline_type_field_klass(fd.index());
+      ciInlineKlass* vk = CURRENT_ENV->get_klass(k)->as_inline_klass();
+      flen += vk->nof_nonstatic_fields() - 1;
+      // Iterate over fields of the flat inline type and copy them to 'this'
+      for (int i = 0; i < vk->nof_nonstatic_fields(); ++i) {
+        ciField* flat_field = vk->nonstatic_field_at(i);
+        // Adjust offset to account for missing oop header
+        int offset = field_offset + (flat_field->offset_in_bytes() - vk->first_field_offset());
+        // A flat field can be treated as final if the non-flat
+        // field is declared final or the holder klass is an inline type itself.
+        bool is_final = fd.is_final() || is_inlinetype();
+        ciField* field = new (arena) ciField(flat_field, this, offset, is_final);
+        fields->append(field);
+      }
+    } else {
+      ciField* field = new (arena) ciField(&fd);
+      fields->append(field);
+    }
   }
   assert(fields->length() == flen, "sanity");
+  // Now sort them by offset, ascending.
+  // (In principle, they could mix with superclass fields.)
+  fields->sort(sort_field_by_offset);
   return fields;
 }
 
 bool ciInstanceKlass::compute_injected_fields_helper() {
   ASSERT_IN_VM;
@@ -638,86 +681,156 @@
     _implementor = impl;
   }
   return impl;
 }
 
+bool ciInstanceKlass::can_be_inline_klass(bool is_exact) {
+  if (!EnableValhalla) {
+    return false;
+  }
+  if (!is_loaded() || is_inlinetype()) {
+    // Not loaded or known to be an inline klass
+    return true;
+  }
+  if (!is_exact) {
+    // Not exact, check if this is a valid super for an inline klass
+    VM_ENTRY_MARK;
+    return !get_instanceKlass()->access_flags().is_identity_class() || is_java_lang_Object() ;
+  }
+  return false;
+}
+
 // Utility class for printing of the contents of the static fields for
 // use by compilation replay.  It only prints out the information that
 // could be consumed by the compiler, so for primitive types it prints
 // out the actual value.  For Strings it's the actual string value.
 // For array types it it's first level array size since that's the
 // only value which statically unchangeable.  For all other reference
 // types it simply prints out the dynamic type.
 
-class StaticFinalFieldPrinter : public FieldClosure {
+class StaticFieldPrinter : public FieldClosure {
+protected:
   outputStream* _out;
+public:
+  StaticFieldPrinter(outputStream* out) :
+    _out(out) {
+  }
+  void do_field_helper(fieldDescriptor* fd, oop obj, bool is_flat);
+};
+
+class StaticFinalFieldPrinter : public StaticFieldPrinter {
   const char*   _holder;
  public:
   StaticFinalFieldPrinter(outputStream* out, const char* holder) :
-    _out(out),
-    _holder(holder) {
+    StaticFieldPrinter(out), _holder(holder) {
   }
   void do_field(fieldDescriptor* fd) {
     if (fd->is_final() && !fd->has_initial_value()) {
       ResourceMark rm;
-      oop mirror = fd->field_holder()->java_mirror();
-      _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
-      BasicType field_type = fd->field_type();
-      switch (field_type) {
-        case T_BYTE:    _out->print_cr("%d", mirror->byte_field(fd->offset()));   break;
-        case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset()));   break;
-        case T_SHORT:   _out->print_cr("%d", mirror->short_field(fd->offset()));  break;
-        case T_CHAR:    _out->print_cr("%d", mirror->char_field(fd->offset()));   break;
-        case T_INT:     _out->print_cr("%d", mirror->int_field(fd->offset()));    break;
-        case T_LONG:    _out->print_cr(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
-        case T_FLOAT: {
-          float f = mirror->float_field(fd->offset());
-          _out->print_cr("%d", *(int*)&f);
-          break;
-        }
-        case T_DOUBLE: {
-          double d = mirror->double_field(fd->offset());
-          _out->print_cr(INT64_FORMAT, *(int64_t*)&d);
-          break;
-        }
-        case T_ARRAY:  // fall-through
-        case T_OBJECT: {
-          oop value =  mirror->obj_field_acquire(fd->offset());
-          if (value == nullptr) {
-            if (field_type == T_ARRAY) {
-              _out->print("%d", -1);
-            }
-            _out->cr();
-          } else if (value->is_instance()) {
-            assert(field_type == T_OBJECT, "");
-            if (value->is_a(vmClasses::String_klass())) {
-              const char* ascii_value = java_lang_String::as_quoted_ascii(value);
-              _out->print_cr("\"%s\"", (ascii_value != nullptr) ? ascii_value : "");
-            } else {
-              const char* klass_name  = value->klass()->name()->as_quoted_ascii();
-              _out->print_cr("%s", klass_name);
-            }
-          } else if (value->is_array()) {
-            typeArrayOop ta = (typeArrayOop)value;
-            _out->print("%d", ta->length());
-            if (value->is_objArray()) {
-              objArrayOop oa = (objArrayOop)value;
-              const char* klass_name  = value->klass()->name()->as_quoted_ascii();
-              _out->print(" %s", klass_name);
-            }
-            _out->cr();
+      InstanceKlass* holder = fd->field_holder();
+      oop mirror = holder->java_mirror();
+      _out->print("staticfield %s %s ", _holder, fd->name()->as_quoted_ascii());
+      BasicType bt = fd->field_type();
+      if (bt != T_OBJECT && bt != T_ARRAY) {
+        _out->print("%s ", fd->signature()->as_quoted_ascii());
+      }
+      do_field_helper(fd, mirror, false);
+      _out->cr();
+    }
+  }
+};
+
+class InlineTypeFieldPrinter : public StaticFieldPrinter {
+  oop _obj;
+public:
+  InlineTypeFieldPrinter(outputStream* out, oop obj) :
+    StaticFieldPrinter(out), _obj(obj) {
+  }
+  void do_field(fieldDescriptor* fd) {
+    do_field_helper(fd, _obj, true);
+    _out->print(" ");
+  }
+};
+
+void StaticFieldPrinter::do_field_helper(fieldDescriptor* fd, oop mirror, bool is_flat) {
+  BasicType field_type = fd->field_type();
+  switch (field_type) {
+    case T_BYTE:    _out->print("%d", mirror->byte_field(fd->offset()));   break;
+    case T_BOOLEAN: _out->print("%d", mirror->bool_field(fd->offset()));   break;
+    case T_SHORT:   _out->print("%d", mirror->short_field(fd->offset()));  break;
+    case T_CHAR:    _out->print("%d", mirror->char_field(fd->offset()));   break;
+    case T_INT:     _out->print("%d", mirror->int_field(fd->offset()));    break;
+    case T_LONG:    _out->print(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset())));   break;
+    case T_FLOAT: {
+      float f = mirror->float_field(fd->offset());
+      _out->print("%d", *(int*)&f);
+      break;
+    }
+    case T_DOUBLE: {
+      double d = mirror->double_field(fd->offset());
+      _out->print(INT64_FORMAT, *(int64_t*)&d);
+      break;
+    }
+    case T_ARRAY:  // fall-through
+    case T_OBJECT:
+      if (!fd->is_null_free_inline_type()) {
+        _out->print("%s ", fd->signature()->as_quoted_ascii());
+        oop value =  mirror->obj_field_acquire(fd->offset());
+        if (value == nullptr) {
+          if (field_type == T_ARRAY) {
+            _out->print("%d", -1);
+          }
+          _out->cr();
+        } else if (value->is_instance()) {
+          assert(field_type == T_OBJECT, "");
+          if (value->is_a(vmClasses::String_klass())) {
+            const char* ascii_value = java_lang_String::as_quoted_ascii(value);
+            _out->print("\"%s\"", (ascii_value != nullptr) ? ascii_value : "");
           } else {
-            ShouldNotReachHere();
+            const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+            _out->print("%s", klass_name);
           }
-          break;
-        }
-        default:
+        } else if (value->is_array()) {
+          typeArrayOop ta = (typeArrayOop)value;
+          _out->print("%d", ta->length());
+          if (value->is_objArray() || value->is_flatArray()) {
+            objArrayOop oa = (objArrayOop)value;
+            const char* klass_name  = value->klass()->name()->as_quoted_ascii();
+            _out->print(" %s", klass_name);
+          }
+        } else {
           ShouldNotReachHere();
         }
-    }
+        break;
+      } else {
+        // handling of null free inline type
+        ResetNoHandleMark rnhm;
+        Thread* THREAD = Thread::current();
+        SignatureStream ss(fd->signature(), false);
+        Symbol* name = ss.as_symbol();
+        assert(!HAS_PENDING_EXCEPTION, "can resolve klass?");
+        InstanceKlass* holder = fd->field_holder();
+        InstanceKlass* k = SystemDictionary::find_instance_klass(THREAD, name,
+                                                                 Handle(THREAD, holder->class_loader()),
+                                                                 Handle(THREAD, holder->protection_domain()));
+        assert(k != nullptr && !HAS_PENDING_EXCEPTION, "can resolve klass?");
+        InlineKlass* vk = InlineKlass::cast(k);
+        oop obj;
+        if (is_flat) {
+          int field_offset = fd->offset() - vk->first_field_offset();
+          obj = cast_to_oop(cast_from_oop<address>(mirror) + field_offset);
+        } else {
+          obj = mirror->obj_field_acquire(fd->offset());
+        }
+        InlineTypeFieldPrinter print_field(_out, obj);
+        vk->do_nonstatic_fields(&print_field);
+        break;
+      }
+    default:
+      ShouldNotReachHere();
   }
-};
+}
 
 const char *ciInstanceKlass::replay_name() const {
   return CURRENT_ENV->replay_name(get_instanceKlass());
 }
 
