diff a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp
@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/symbolTable.hpp"
+#include "classfile/systemDictionary.hpp"
 #include "classfile/vmClasses.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
 #include "compiler/compilationPolicy.hpp"
 #include "compiler/compileBroker.hpp"
@@ -43,10 +44,13 @@
 #include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/constantPool.inline.hpp"
 #include "oops/cpCache.inline.hpp"
+#include "oops/flatArrayKlass.hpp"
+#include "oops/flatArrayOop.inline.hpp"
+#include "oops/inlineKlass.inline.hpp"
 #include "oops/instanceKlass.inline.hpp"
 #include "oops/klass.inline.hpp"
 #include "oops/methodData.hpp"
 #include "oops/method.inline.hpp"
 #include "oops/objArrayKlass.hpp"
@@ -75,10 +79,11 @@
 #include "runtime/threadCritical.hpp"
 #include "utilities/align.hpp"
 #include "utilities/checkedCast.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/events.hpp"
+#include "utilities/globalDefinitions.hpp"
 #ifdef COMPILER2
 #include "opto/runtime.hpp"
 #endif
 
 // Helper class to access current interpreter state
@@ -225,30 +230,164 @@
 
   oop obj = klass->allocate_instance(CHECK);
   current->set_vm_result(obj);
 JRT_END
 
+JRT_ENTRY(void, InterpreterRuntime::uninitialized_static_inline_type_field(JavaThread* current, oopDesc* mirror, ResolvedFieldEntry* entry))
+  // The interpreter tries to access an inline static field that has not been initialized.
+  // This situation can happen in different scenarios:
+  //   1 - if the load or initialization of the field failed during step 8 of
+  //       the initialization of the holder of the field, in this case the access to the field
+  //       must fail
+  //   2 - it can also happen when the initialization of the holder class triggered the initialization of
+  //       another class which accesses this field in its static initializer, in this case the
+  //       access must succeed to allow circularity
+  // The code below tries to load and initialize the field's class again before returning the default value.
+  // If the field was not initialized because of an error, an exception should be thrown.
+  // If the class is being initialized, the default value is returned.
+  assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
+  instanceHandle mirror_h(THREAD, (instanceOop)mirror);
+  InstanceKlass* klass = entry->field_holder();
+  u2 index = entry->field_index();
+  assert(klass == java_lang_Class::as_Klass(mirror), "Not the field holder klass");
+  assert(klass->field_is_null_free_inline_type(index), "Sanity check");
+  if (klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD)) {
+    int offset = klass->field_offset(index);
+    Klass* field_k = klass->get_inline_type_field_klass_or_null(index);
+    if (field_k == nullptr) {
+      field_k = SystemDictionary::resolve_or_fail(klass->field_signature(index)->fundamental_name(THREAD),
+          Handle(THREAD, klass->class_loader()),
+          Handle(THREAD, klass->protection_domain()),
+          true, CHECK);
+      assert(field_k != nullptr, "Should have been loaded or an exception thrown above");
+      klass->set_inline_type_field_klass(index, InlineKlass::cast(field_k));
+    }
+    field_k->initialize(CHECK);
+    oop defaultvalue = InlineKlass::cast(field_k)->default_value();
+    // It is safe to initialize the static field because 1) the current thread is the initializing thread
+    // and is the only one that can access it, and 2) the field is actually not initialized (i.e. null)
+    // otherwise the JVM should not be executing this code.
+    mirror_h()->obj_field_put(offset, defaultvalue);
+    current->set_vm_result(defaultvalue);
+  } else {
+    assert(klass->is_in_error_state(), "If not initializing, initialization must have failed to get there");
+    ResourceMark rm(THREAD);
+    const char* desc = "Could not initialize class ";
+    const char* className = klass->external_name();
+    size_t msglen = strlen(desc) + strlen(className) + 1;
+    char* message = NEW_RESOURCE_ARRAY(char, msglen);
+    if (nullptr == message) {
+      // Out of memory: can't create detailed error message
+      THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
+    } else {
+      jio_snprintf(message, msglen, "%s%s", desc, className);
+      THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
+    }
+  }
+JRT_END
+
+JRT_ENTRY(void, InterpreterRuntime::read_flat_field(JavaThread* current, oopDesc* obj, int index, Klass* field_holder))
+  Handle obj_h(THREAD, obj);
+
+  assert(oopDesc::is_oop(obj), "Sanity check");
+
+  assert(field_holder->is_instance_klass(), "Sanity check");
+  InstanceKlass* klass = InstanceKlass::cast(field_holder);
+
+  assert(klass->field_is_flat(index), "Sanity check");
+
+  InlineKlass* field_vklass = InlineKlass::cast(klass->get_inline_type_field_klass(index));
+
+  oop res = field_vklass->read_flat_field(obj_h(), klass->field_offset(index), CHECK);
+  current->set_vm_result(res);
+JRT_END
+
+// The protocol to read a nullable flat field is:
+// Step 1: read the null marker with an load_acquire barrier to ensure that
+//         reordered loads won't try to load the value before the null marker is read
+// Step 2: if the null marker value is zero, the field's value is null
+//         otherwise the flat field value can be read like a regular flat field
+JRT_ENTRY(void, InterpreterRuntime::read_nullable_flat_field(JavaThread* current, oopDesc* obj, ResolvedFieldEntry* entry))
+  assert(oopDesc::is_oop(obj), "Sanity check");
+  assert(entry->has_null_marker(), "Otherwise should not get there");
+  Handle obj_h(THREAD, obj);
+
+  InstanceKlass* ik = InstanceKlass::cast(obj_h()->klass());
+  int field_index = entry->field_index();
+  int nm_offset = ik->null_marker_offsets_array()->at(field_index);
+  if (obj_h()->byte_field_acquire(nm_offset) == 0) {
+    current->set_vm_result(nullptr);
+  } else {
+    InlineKlass* field_vklass = InlineKlass::cast(ik->get_inline_type_field_klass(field_index));
+    oop res = field_vklass->read_flat_field(obj_h(), ik->field_offset(field_index), CHECK);
+    current->set_vm_result(res);
+  }
+JRT_END
+
+// The protocol to write a nullable flat field is:
+// If the new field value is null, just write zero to the null marker
+// Otherwise:
+// Step 1: write the field value like a regular flat field
+// Step 2: have a memory barrier to ensure that the whole value content is visible
+// Step 3: update the null marker to a non zero value
+JRT_ENTRY(void, InterpreterRuntime::write_nullable_flat_field(JavaThread* current, oopDesc* obj, oopDesc* value, ResolvedFieldEntry* entry))
+  assert(oopDesc::is_oop(obj), "Sanity check");
+  Handle obj_h(THREAD, obj);
+  assert(value == nullptr || oopDesc::is_oop(value), "Sanity check");
+  Handle val_h(THREAD, value);
+
+  InstanceKlass* ik = InstanceKlass::cast(obj_h()->klass());
+  int nm_offset = ik->null_marker_offsets_array()->at(entry->field_index());
+  if (val_h() == nullptr) {
+    obj_h()->byte_field_put(nm_offset, (jbyte)0);
+    return;
+  }
+  InlineKlass* vk = InlineKlass::cast(val_h()->klass());
+  if (entry->has_internal_null_marker()) {
+    // The interpreter copies values with a bulk operation
+    // To avoid accidently setting the null marker to "null" during
+    // the copying, the null marker is set to non zero in the source object
+    if (val_h()->byte_field(vk->get_internal_null_marker_offset()) == 0) {
+      val_h()->byte_field_put(vk->get_internal_null_marker_offset(), (jbyte)1);
+    }
+    vk->write_non_null_flat_field(obj_h(), entry->field_offset(), val_h());
+  } else {
+    vk->write_non_null_flat_field(obj_h(), entry->field_offset(), val_h());
+    OrderAccess::release();
+    obj_h()->byte_field_put(nm_offset, (jbyte)1);
+  }
+JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* current, BasicType type, jint size))
   oop obj = oopFactory::new_typeArray(type, size, CHECK);
   current->set_vm_result(obj);
 JRT_END
 
 
 JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size))
   Klass*    klass = pool->klass_at(index, CHECK);
-  objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
+  arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
   current->set_vm_result(obj);
 JRT_END
 
+JRT_ENTRY(void, InterpreterRuntime::value_array_load(JavaThread* current, arrayOopDesc* array, int index))
+  flatArrayHandle vah(current, (flatArrayOop)array);
+  oop value_holder = flatArrayOopDesc::value_alloc_copy_from_index(vah, index, CHECK);
+  current->set_vm_result(value_holder);
+JRT_END
+
+JRT_ENTRY(void, InterpreterRuntime::value_array_store(JavaThread* current, void* val, arrayOopDesc* array, int index))
+  assert(val != nullptr, "can't store null into flat array");
+  ((flatArrayOop)array)->value_copy_to_index(cast_to_oop(val), index);
+JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* first_size_address))
   // We may want to pass in more arguments - could make this slightly faster
   LastFrameAccessor last_frame(current);
   ConstantPool* constants = last_frame.method()->constants();
-  int          i = last_frame.get_index_u2(Bytecodes::_multianewarray);
-  Klass* klass   = constants->klass_at(i, CHECK);
+  int i = last_frame.get_index_u2(Bytecodes::_multianewarray);
+  Klass* klass = constants->klass_at(i, CHECK);
   int   nof_dims = last_frame.number_of_dimensions();
   assert(klass->is_klass(), "not a class");
   assert(nof_dims >= 1, "multianewarray rank must be nonzero");
 
   // We must create an array of jints to pass to multi_allocate.
@@ -273,10 +412,34 @@
   assert(oopDesc::is_oop(obj), "must be a valid oop");
   assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
   InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
 JRT_END
 
+JRT_ENTRY(jboolean, InterpreterRuntime::is_substitutable(JavaThread* current, oopDesc* aobj, oopDesc* bobj))
+  assert(oopDesc::is_oop(aobj) && oopDesc::is_oop(bobj), "must be valid oops");
+
+  Handle ha(THREAD, aobj);
+  Handle hb(THREAD, bobj);
+  JavaValue result(T_BOOLEAN);
+  JavaCallArguments args;
+  args.push_oop(ha);
+  args.push_oop(hb);
+  methodHandle method(current, Universe::is_substitutable_method());
+  method->method_holder()->initialize(CHECK_false); // Ensure class ValueObjectMethods is initialized
+  JavaCalls::call(&result, method, &args, THREAD);
+  if (HAS_PENDING_EXCEPTION) {
+    // Something really bad happened because isSubstitutable() should not throw exceptions
+    // If it is an error, just let it propagate
+    // If it is an exception, wrap it into an InternalError
+    if (!PENDING_EXCEPTION->is_a(vmClasses::Error_klass())) {
+      Handle e(THREAD, PENDING_EXCEPTION);
+      CLEAR_PENDING_EXCEPTION;
+      THROW_MSG_CAUSE_(vmSymbols::java_lang_InternalError(), "Internal error in substitutability test", e, false);
+    }
+  }
+  return result.get_jboolean();
+JRT_END
 
 // Quicken instance-of and check-cast bytecodes
 JRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* current))
   // Force resolving; quicken the bytecode
   LastFrameAccessor last_frame(current);
@@ -616,10 +779,14 @@
   ResourceMark rm(current);
   methodHandle mh = methodHandle(current, missingMethod);
   LinkResolver::throw_abstract_method_error(mh, recvKlass, THREAD);
 JRT_END
 
+JRT_ENTRY(void, InterpreterRuntime::throw_InstantiationError(JavaThread* current))
+  THROW(vmSymbols::java_lang_InstantiationError());
+JRT_END
+
 
 JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* current))
   THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
 JRT_END
 
@@ -700,18 +867,25 @@
   assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");
 
   Bytecodes::Code get_code = (Bytecodes::Code)0;
   Bytecodes::Code put_code = (Bytecodes::Code)0;
   if (!uninitialized_static) {
-    get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
+    if (is_static) {
+      get_code = Bytecodes::_getstatic;
+    } else {
+      get_code = Bytecodes::_getfield;
+    }
     if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
-      put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
+        put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
     }
   }
 
   ResolvedFieldEntry* entry = pool->resolved_field_entry_at(field_index);
-  entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile());
+  entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile(),
+                   info.is_flat(), info.is_null_free_inline_type(),
+                   info.has_null_marker(), info.has_internal_null_marker());
+
   entry->fill_in(info.field_holder(), info.offset(),
                  checked_cast<u2>(info.index()), checked_cast<u1>(state),
                  static_cast<u1>(get_code), static_cast<u1>(put_code));
 }
 
@@ -754,16 +928,14 @@
   // Free entry. If it is not cleared, the exception handling code will try to unlock the monitor
   // again at method exit or in the case of an exception.
   elem->set_obj(nullptr);
 JRT_END
 
-
 JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* current))
   THROW(vmSymbols::java_lang_IllegalMonitorStateException());
 JRT_END
 
-
 JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* current))
   // Returns an illegal exception to install into the current thread. The
   // pending_exception flag is cleared so normal exception handling does not
   // trigger. Any current installed exception will be overwritten. This
   // method will be called during an exception unwind.
@@ -774,10 +946,25 @@
   current->set_vm_result(nullptr); // clear vm result before continuing (may cause memory leaks and assert failures)
   exception = get_preinitialized_exception(vmClasses::IllegalMonitorStateException_klass(), CATCH);
   current->set_vm_result(exception());
 JRT_END
 
+JRT_ENTRY(void, InterpreterRuntime::throw_identity_exception(JavaThread* current, oopDesc* obj))
+  Klass* klass = cast_to_oop(obj)->klass();
+  ResourceMark rm(THREAD);
+  const char* desc = "Cannot synchronize on an instance of value class ";
+  const char* className = klass->external_name();
+  size_t msglen = strlen(desc) + strlen(className) + 1;
+  char* message = NEW_RESOURCE_ARRAY(char, msglen);
+  if (nullptr == message) {
+    // Out of memory: can't create detailed error message
+    THROW_MSG(vmSymbols::java_lang_IdentityException(), className);
+  } else {
+    jio_snprintf(message, msglen, "%s%s", desc, className);
+    THROW_MSG(vmSymbols::java_lang_IdentityException(), message);
+  }
+JRT_END
 
 //------------------------------------------------------------------------------------------------------------------------
 // Invokes
 
 JRT_ENTRY(Bytecodes::Code, InterpreterRuntime::get_original_bytecode_at(JavaThread* current, Method* method, address bcp))
@@ -1166,33 +1353,36 @@
 JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDesc* obj,
                                                       ResolvedFieldEntry *entry))
 
+  assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
   // check the access_flags for the field in the klass
 
   InstanceKlass* ik = entry->field_holder();
   int index = entry->field_index();
   if (!ik->field_status(index).is_access_watched()) return;
 
   bool is_static = (obj == nullptr);
+  bool is_flat = entry->is_flat();
   HandleMark hm(current);
 
   Handle h_obj;
   if (!is_static) {
     // non-static field accessors have an object, but we need a handle
     h_obj = Handle(current, obj);
   }
   InstanceKlass* field_holder = entry->field_holder(); // HERE
-  jfieldID fid = jfieldIDWorkaround::to_jfieldID(field_holder, entry->field_offset(), is_static);
+  jfieldID fid = jfieldIDWorkaround::to_jfieldID(field_holder, entry->field_offset(), is_static, is_flat);
   LastFrameAccessor last_frame(current);
   JvmtiExport::post_field_access(current, last_frame.method(), last_frame.bcp(), field_holder, h_obj, fid);
 JRT_END
 
 JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread* current, oopDesc* obj,
                                                             ResolvedFieldEntry *entry, jvalue *value))
 
+  assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
   InstanceKlass* ik = entry->field_holder();
 
   // check the access_flags for the field in the klass
   int index = entry->field_index();
   // bail out if field modifications are not watched
@@ -1210,14 +1400,16 @@
     case atos: sig_type = JVM_SIGNATURE_CLASS;   break;
     case ltos: sig_type = JVM_SIGNATURE_LONG;    break;
     case dtos: sig_type = JVM_SIGNATURE_DOUBLE;  break;
     default:  ShouldNotReachHere(); return;
   }
+
   bool is_static = (obj == nullptr);
+  bool is_flat = entry->is_flat();
 
   HandleMark hm(current);
-  jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static);
+  jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static, is_flat);
   jvalue fvalue;
 #ifdef _LP64
   fvalue = *value;
 #else
   // Long/double values are stored unaligned and also noncontiguously with
