diff a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -487,10 +487,11 @@
 758deedaae8406ae60147486107a54e9864aa7b0 jdk-11+13
 3595bd343b65f8c37818ebe6a4c343ddeb1a5f88 jdk-11+14
 a11c1cb542bbd1671d25b85efe7d09b983c48525 jdk-11+15
 02934b0d661b82b7fe1052a04998d2091352e08d jdk-11+16
 64e4b1686141e57a681936a8283983341484676e jdk-11+17
+d2aa5d494481a1039a092d70efa1f5c9826c5b77 lw1_0
 e1b3def126240d5433902f3cb0e91a4c27f6db50 jdk-11+18
 36ca515343e00b021dcfc902e986d26ec994a2e5 jdk-11+19
 95aad0c785e497f1bade3955c4e4a677b629fa9d jdk-12+0
 9816d7cc655e53ba081f938b656e31971b8f097a jdk-11+20
 14708e1acdc3974f4539027cbbcfa6d69f83cf51 jdk-11+21
@@ -509,10 +510,11 @@
 ef57958c7c511162da8d9a75f0b977f0f7ac464e jdk-12+7
 76072a077ee1d815152d45d1692c4b36c53c5c49 jdk-11+28
 492b366f8e5784cc4927c2c98f9b8a3f16c067eb jdk-12+8
 31b159f30fb281016c5f0c103552809aeda84063 jdk-12+9
 8f594f75e0547d4ca16649cb3501659e3155e81b jdk-12+10
+6132641c6ff61b7b8f3f10b9cd385aafadbd72ef lworld_stable
 f0f5d23449d31f1b3580c8a73313918cafeaefd7 jdk-12+11
 15094d12a632f452a2064318a4e416d0c7a9ce0c jdk-12+12
 511a9946f83e3e3c7b9dbe1840367063fb39b4e1 jdk-12+13
 8897e41b327c0a5601c6ba2bba5d07f15a3ffc91 jdk-12+14
 8897e41b327c0a5601c6ba2bba5d07f15a3ffc91 jdk-12+14
@@ -565,10 +567,14 @@
 22b3b7983adab54e318f75aeb94471f7a4429c1e jdk-14+0
 22b3b7983adab54e318f75aeb94471f7a4429c1e jdk-13+25
 2f4e214781a1d597ed36bf5a36f20928c6c82996 jdk-14+1
 0692b67f54621991ba7afbf23e55b788f3555e69 jdk-13+26
 43627549a488b7d0b4df8fad436e36233df89877 jdk-14+2
+6132641c6ff61b7b8f3f10b9cd385aafadbd72ef lworld_stable
+2b098533f1e52d7d541121409b745d9420886945 lworld_stable
+2b098533f1e52d7d541121409b745d9420886945 lworld_stable
+7c637fd25e7d6fccdab1098bedd48ed195a86cc7 lworld_stable
 b7f68ddec66f996ae3aad03291d129ca9f02482d jdk-13+27
 e64383344f144217c36196c3c8a2df8f588a2af3 jdk-14+3
 1e95931e7d8fa7e3899340a9c7cb28dbea50c10c jdk-13+28
 19d0b382f0869f72d4381b54fa129f1c74b6e766 jdk-14+4
 3081f39a3d30d63b112098386ac2bb027c2b7223 jdk-13+29
diff a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/c1_CodeStubs_aarch64.cpp
@@ -117,10 +117,76 @@
 #ifdef ASSERT
   __ should_not_reach_here();
 #endif
 }
 
+// Implementation of LoadFlattenedArrayStub
+
+LoadFlattenedArrayStub::LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info) {
+  _array = array;
+  _index = index;
+  _result = result;
+  _scratch_reg = FrameMap::r0_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_array->as_register(), 1);
+  ce->store_parameter(_index->as_register(), 0);
+  __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::load_flattened_array_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  if (_result->as_register() != r0) {
+    __ mov(_result->as_register(), r0);
+  }
+  __ b(_continuation);
+}
+
+
+// Implementation of StoreFlattenedArrayStub
+
+StoreFlattenedArrayStub::StoreFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr value, CodeEmitInfo* info) {
+  _array = array;
+  _index = index;
+  _value = value;
+  _scratch_reg = FrameMap::r0_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+
+void StoreFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_array->as_register(), 2);
+  ce->store_parameter(_index->as_register(), 1);
+  ce->store_parameter(_value->as_register(), 0);
+  __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::store_flattened_array_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
+
+// Implementation of SubstitutabilityCheckStub
+SubstitutabilityCheckStub::SubstitutabilityCheckStub(LIR_Opr left, LIR_Opr right, CodeEmitInfo* info) {
+  _left = left;
+  _right = right;
+  _scratch_reg = FrameMap::r0_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+void SubstitutabilityCheckStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_left->as_register(), 1);
+  ce->store_parameter(_right->as_register(), 0);
+  __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::substitutability_check_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ b(_continuation);
+}
 
 
 // Implementation of NewInstanceStub
 
 NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
@@ -133,12 +199,10 @@
          stub_id == Runtime1::fast_new_instance_init_check_id,
          "need new_instance id");
   _stub_id   = stub_id;
 }
 
-
-
 void NewInstanceStub::emit_code(LIR_Assembler* ce) {
   assert(__ rsp_offset() == 0, "frame size should be fixed");
   __ bind(_entry);
   __ mov(r3, _klass_reg->as_register());
   __ far_call(RuntimeAddress(Runtime1::entry_for(_stub_id)));
@@ -174,41 +238,63 @@
 }
 
 
 // Implementation of NewObjectArrayStub
 
-NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info, bool is_inline_type) {
   _klass_reg = klass_reg;
   _result = result;
   _length = length;
   _info = new CodeEmitInfo(info);
+  _is_inline_type = is_inline_type;
 }
 
 
 void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
   assert(__ rsp_offset() == 0, "frame size should be fixed");
   __ bind(_entry);
   assert(_length->as_register() == r19, "length must in r19,");
   assert(_klass_reg->as_register() == r3, "klass_reg must in r3");
-  __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+
+  if (_is_inline_type) {
+    __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_flat_array_id)));
+  } else {
+    __ far_call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+  }
+
   ce->add_call_info_here(_info);
   ce->verify_oop_map(_info);
   assert(_result->as_register() == r0, "result must in r0");
   __ b(_continuation);
 }
 // Implementation of MonitorAccessStubs
 
-MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
+MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info,  CodeStub* throw_imse_stub, LIR_Opr scratch_reg)
 : MonitorAccessStub(obj_reg, lock_reg)
 {
   _info = new CodeEmitInfo(info);
+  _scratch_reg = scratch_reg;
+  _throw_imse_stub = throw_imse_stub;
+  if (_throw_imse_stub != NULL) {
+    assert(_scratch_reg != LIR_OprFact::illegalOpr, "must be");
+  }
 }
 
 
 void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
   assert(__ rsp_offset() == 0, "frame size should be fixed");
   __ bind(_entry);
+  if (_throw_imse_stub != NULL) {
+    // When we come here, _obj_reg has already been checked to be non-null.
+    __ ldr(rscratch1, Address(_obj_reg->as_register(), oopDesc::mark_offset_in_bytes()));
+    __ mov(rscratch2, markWord::always_locked_pattern);
+    __ andr(rscratch1, rscratch1, rscratch2);
+
+    __ cmp(rscratch1, rscratch2);
+    __ br(Assembler::NE, *_throw_imse_stub->entry());
+  }
+
   ce->store_parameter(_obj_reg->as_register(),  1);
   ce->store_parameter(_lock_reg->as_register(), 0);
   Runtime1::StubID enter_id;
   if (ce->compilation()->has_fpu_code()) {
     enter_id = Runtime1::monitorenter_id;
diff a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp
@@ -24,10 +24,11 @@
  */
 
 #include "precompiled.hpp"
 #include "asm/macroAssembler.hpp"
 #include "asm/macroAssembler.inline.hpp"
+#include "classfile/symbolTable.hpp"
 #include "code/codeCache.hpp"
 #include "code/debugInfoRec.hpp"
 #include "code/icBuffer.hpp"
 #include "code/vtableStubs.hpp"
 #include "gc/shared/barrierSetAssembler.hpp"
@@ -289,10 +290,11 @@
       assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half");
       // fall through
     case T_OBJECT:
     case T_ARRAY:
     case T_ADDRESS:
+    case T_INLINE_TYPE:
       if (int_args < Argument::n_int_register_parameters_j) {
         regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
       } else {
         regs[i].set2(VMRegImpl::stack2reg(stk_args));
         stk_args += 2;
@@ -322,10 +324,94 @@
   }
 
   return align_up(stk_args, 2);
 }
 
+
+// const uint SharedRuntime::java_return_convention_max_int = Argument::n_int_register_parameters_j+1;
+const uint SharedRuntime::java_return_convention_max_int = 6;
+const uint SharedRuntime::java_return_convention_max_float = Argument::n_float_register_parameters_j;
+
+int SharedRuntime::java_return_convention(const BasicType *sig_bt, VMRegPair *regs, int total_args_passed) {
+
+  // Create the mapping between argument positions and
+  // registers.
+  // r1, r2 used to address klasses and states, exclude it from return convention to avoid colision
+
+  static const Register INT_ArgReg[java_return_convention_max_int] = {
+     r0 /* j_rarg7 */, j_rarg6, j_rarg5, j_rarg4, j_rarg3, j_rarg2
+  };
+
+  static const FloatRegister FP_ArgReg[java_return_convention_max_float] = {
+    j_farg0, j_farg1, j_farg2, j_farg3, j_farg4, j_farg5, j_farg6, j_farg7
+  };
+
+  uint int_args = 0;
+  uint fp_args = 0;
+
+  for (int i = 0; i < total_args_passed; i++) {
+    switch (sig_bt[i]) {
+    case T_BOOLEAN:
+    case T_CHAR:
+    case T_BYTE:
+    case T_SHORT:
+    case T_INT:
+      if (int_args < SharedRuntime::java_return_convention_max_int) {
+        regs[i].set1(INT_ArgReg[int_args]->as_VMReg());
+        int_args ++;
+      } else {
+        // Should we have gurantee here?
+        return -1;
+      }
+      break;
+    case T_VOID:
+      // halves of T_LONG or T_DOUBLE
+      assert(i != 0 && (sig_bt[i - 1] == T_LONG || sig_bt[i - 1] == T_DOUBLE), "expecting half");
+      regs[i].set_bad();
+      break;
+    case T_LONG:
+      assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half");
+      // fall through
+    case T_OBJECT:
+    case T_ARRAY:
+    case T_ADDRESS:
+      // Should T_METADATA be added to java_calling_convention as well ?
+    case T_METADATA:
+    case T_INLINE_TYPE:
+      if (int_args < SharedRuntime::java_return_convention_max_int) {
+        regs[i].set2(INT_ArgReg[int_args]->as_VMReg());
+        int_args ++;
+      } else {
+        return -1;
+      }
+      break;
+    case T_FLOAT:
+      if (fp_args < SharedRuntime::java_return_convention_max_float) {
+        regs[i].set1(FP_ArgReg[fp_args]->as_VMReg());
+        fp_args ++;
+      } else {
+        return -1;
+      }
+      break;
+    case T_DOUBLE:
+      assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half");
+      if (fp_args < Argument::n_float_register_parameters_j) {
+        regs[i].set2(FP_ArgReg[fp_args]->as_VMReg());
+        fp_args ++;
+      } else {
+        return -1;
+      }
+      break;
+    default:
+      ShouldNotReachHere();
+      break;
+    }
+  }
+
+  return int_args + fp_args;
+}
+
 // Patch the callers callsite with entry to compiled code if it exists.
 static void patch_callers_callsite(MacroAssembler *masm) {
   Label L;
   __ ldr(rscratch1, Address(rmethod, in_bytes(Method::code_offset())));
   __ cbz(rscratch1, L);
@@ -352,50 +438,60 @@
   // restore sp
   __ leave();
   __ bind(L);
 }
 
-static void gen_c2i_adapter(MacroAssembler *masm,
-                            int total_args_passed,
-                            int comp_args_on_stack,
-                            const BasicType *sig_bt,
-                            const VMRegPair *regs,
-                            Label& skip_fixup) {
-  // Before we get into the guts of the C2I adapter, see if we should be here
-  // at all.  We've come from compiled code and are attempting to jump to the
-  // interpreter, which means the caller made a static call to get here
-  // (vcalls always get a compiled target if there is one).  Check for a
-  // compiled target.  If there is one, we need to patch the caller's call.
-  patch_callers_callsite(masm);
-
-  __ bind(skip_fixup);
-
-  int words_pushed = 0;
-
-  // Since all args are passed on the stack, total_args_passed *
-  // Interpreter::stackElementSize is the space we need.
+// For each inline type argument, sig includes the list of fields of
+// the inline type. This utility function computes the number of
+// arguments for the call if inline types are passed by reference (the
+// calling convention the interpreter expects).
+static int compute_total_args_passed_int(const GrowableArray<SigEntry>* sig_extended) {
+  int total_args_passed = 0;
+  if (InlineTypePassFieldsAsArgs) {
+     for (int i = 0; i < sig_extended->length(); i++) {
+       BasicType bt = sig_extended->at(i)._bt;
+       if (SigEntry::is_reserved_entry(sig_extended, i)) {
+         // Ignore reserved entry
+       } else if (bt == T_INLINE_TYPE) {
+         // In sig_extended, an inline type argument starts with:
+         // T_INLINE_TYPE, followed by the types of the fields of the
+         // inline type and T_VOID to mark the end of the value
+         // type. Inline types are flattened so, for instance, in the
+         // case of an inline type with an int field and an inline type
+         // field that itself has 2 fields, an int and a long:
+         // T_INLINE_TYPE T_INT T_INLINE_TYPE T_INT T_LONG T_VOID (second
+         // slot for the T_LONG) T_VOID (inner T_INLINE_TYPE) T_VOID
+         // (outer T_INLINE_TYPE)
+         total_args_passed++;
+         int vt = 1;
+         do {
+           i++;
+           BasicType bt = sig_extended->at(i)._bt;
+           BasicType prev_bt = sig_extended->at(i-1)._bt;
+           if (bt == T_INLINE_TYPE) {
+             vt++;
+           } else if (bt == T_VOID &&
+                      prev_bt != T_LONG &&
+                      prev_bt != T_DOUBLE) {
+             vt--;
+           }
+         } while (vt != 0);
+       } else {
+         total_args_passed++;
+       }
+     }
+  } else {
+    total_args_passed = sig_extended->length();
+  }
 
-  int extraspace = total_args_passed * Interpreter::stackElementSize;
+  return total_args_passed;
+}
 
-  __ mov(r13, sp);
-
-  // stack is aligned, keep it that way
+
   extraspace = align_up(extraspace, 2*wordSize);
 
-  if (extraspace)
-    __ sub(sp, sp, extraspace);
-
-  // Now write the args into the outgoing interpreter space
-  for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
-      continue;
-    }
-
-    // offset to start parameters
-    int st_off   = (total_args_passed - i - 1) * Interpreter::stackElementSize;
-    int next_off = st_off - Interpreter::stackElementSize;
+    assert(bt != T_INLINE_TYPE || !InlineTypePassFieldsAsArgs, "no inline type here");
 
     // Say 4 args:
     // i   st_off
     // 0   32 T_LONG
     // 1   24 T_VOID
@@ -406,94 +502,222 @@
     // However to make thing extra confusing. Because we can fit a long/double in
     // a single slot on a 64 bt vm and it would be silly to break them up, the interpreter
     // leaves one slot empty and only stores to a single slot. In this case the
     // slot that is occupied is the T_VOID slot. See I said it was confusing.
 
-    VMReg r_1 = regs[i].first();
-    VMReg r_2 = regs[i].second();
+    // int next_off = st_off - Interpreter::stackElementSize;
+
+    VMReg r_1 = reg_pair.first();
+    VMReg r_2 = reg_pair.second();
+
     if (!r_1->is_valid()) {
       assert(!r_2->is_valid(), "");
-      continue;
+      return;
     }
+
     if (r_1->is_stack()) {
       // memory to memory use rscratch1
-      int ld_off = (r_1->reg2stack() * VMRegImpl::stack_slot_size
-                    + extraspace
-                    + words_pushed * wordSize);
+      // words_pushed is always 0 so we don't use it.
+      int ld_off = (r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace /* + word_pushed * wordSize */);
       if (!r_2->is_valid()) {
         // sign extend??
         __ ldrw(rscratch1, Address(sp, ld_off));
-        __ str(rscratch1, Address(sp, st_off));
+        __ str(rscratch1, to);
 
       } else {
-
-        __ ldr(rscratch1, Address(sp, ld_off));
-
-        // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG
-        // T_DOUBLE and T_LONG use two slots in the interpreter
-        if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
-          // ld_off == LSW, ld_off+wordSize == MSW
-          // st_off == MSW, next_off == LSW
-          __ str(rscratch1, Address(sp, next_off));
-#ifdef ASSERT
-          // Overwrite the unused slot with known junk
-          __ mov(rscratch1, 0xdeadffffdeadaaaaul);
-          __ str(rscratch1, Address(sp, st_off));
-#endif /* ASSERT */
-        } else {
-          __ str(rscratch1, Address(sp, st_off));
+        __ ldr(rscratch1, Address(sp, ld_off));
         }
       }
     } else if (r_1->is_Register()) {
       Register r = r_1->as_Register();
-      if (!r_2->is_valid()) {
-        // must be only an int (or less ) so move only 32bits to slot
-        // why not sign extend??
-        __ str(r, Address(sp, st_off));
-      } else {
-        // Two VMREgs|OptoRegs can be T_OBJECT, T_ADDRESS, T_DOUBLE, T_LONG
-        // T_DOUBLE and T_LONG use two slots in the interpreter
-        if ( sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
-          // long/double in gpr
-#ifdef ASSERT
-          // Overwrite the unused slot with known junk
-          __ mov(rscratch1, 0xdeadffffdeadaaabul);
-          __ str(rscratch1, Address(sp, st_off));
-#endif /* ASSERT */
-          __ str(r, Address(sp, next_off));
-        } else {
-          __ str(r, Address(sp, st_off));
-        }
-      }
+      __ str(r, to);
     } else {
       assert(r_1->is_FloatRegister(), "");
       if (!r_2->is_valid()) {
         // only a float use just part of the slot
-        __ strs(r_1->as_FloatRegister(), Address(sp, st_off));
+        __ strs(r_1->as_FloatRegister(), to);
       } else {
-#ifdef ASSERT
-        // Overwrite the unused slot with known junk
-        __ mov(rscratch1, 0xdeadffffdeadaaacul);
-        __ str(rscratch1, Address(sp, st_off));
-#endif /* ASSERT */
-        __ strd(r_1->as_FloatRegister(), Address(sp, next_off));
+        __ strd(r_1->as_FloatRegister(), to);
       }
+   }
+}
+
+static void gen_c2i_adapter(MacroAssembler *masm,
+                            const GrowableArray<SigEntry>* sig_extended,
+                            const VMRegPair *regs,
+                            Label& skip_fixup,
+                            address start,
+                            OopMapSet* oop_maps,
+                            int& frame_complete,
+                            int& frame_size_in_words,
+                            bool alloc_inline_receiver) {
+
+  // Before we get into the guts of the C2I adapter, see if we should be here
+  // at all.  We've come from compiled code and are attempting to jump to the
+  // interpreter, which means the caller made a static call to get here
+  // (vcalls always get a compiled target if there is one).  Check for a
+  // compiled target.  If there is one, we need to patch the caller's call.
+  patch_callers_callsite(masm);
+
+  __ bind(skip_fixup);
+
+  bool has_inline_argument = false;
+
+  if (InlineTypePassFieldsAsArgs) {
+      // Is there an inline type argument?
+     for (int i = 0; i < sig_extended->length() && !has_inline_argument; i++) {
+       has_inline_argument = (sig_extended->at(i)._bt == T_INLINE_TYPE);
+     }
+     if (has_inline_argument) {
+      // There is at least an inline type argument: we're coming from
+      // compiled code so we have no buffers to back the inline types
+      // Allocate the buffers here with a runtime call.
+      OopMap* map = RegisterSaver::save_live_registers(masm, 0, &frame_size_in_words);
+
+      frame_complete = __ offset();
+      address the_pc = __ pc();
+
+      __ set_last_Java_frame(noreg, noreg, the_pc, rscratch1);
+
+      __ mov(c_rarg0, rthread);
+      __ mov(c_rarg1, r1);
+      __ mov(c_rarg2, (int64_t)alloc_inline_receiver);
+
+      __ lea(rscratch1, RuntimeAddress(CAST_FROM_FN_PTR(address, SharedRuntime::allocate_inline_types)));
+      __ blr(rscratch1);
+
+      oop_maps->add_gc_map((int)(__ pc() - start), map);
+      __ reset_last_Java_frame(false);
+
+      RegisterSaver::restore_live_registers(masm);
+
+      Label no_exception;
+      __ ldr(r0, Address(rthread, Thread::pending_exception_offset()));
+      __ cbz(r0, no_exception);
+
+      __ str(zr, Address(rthread, JavaThread::vm_result_offset()));
+      __ ldr(r0, Address(rthread, Thread::pending_exception_offset()));
+      __ b(RuntimeAddress(StubRoutines::forward_exception_entry()));
+
+      __ bind(no_exception);
+
+      // We get an array of objects from the runtime call
+      __ get_vm_result(r10, rthread);
+      __ get_vm_result_2(r1, rthread); // TODO: required to keep the callee Method live?
+    }
+  }
+
+  int words_pushed = 0;
+
+  // Since all args are passed on the stack, total_args_passed *
+  // Interpreter::stackElementSize is the space we need.
+
+  int total_args_passed = compute_total_args_passed_int(sig_extended);
+  int extraspace = (total_args_passed * Interpreter::stackElementSize) + wordSize;
+
+  // stack is aligned, keep it that way
+  extraspace = align_up(extraspace, 2 * wordSize);
+
+  __ mov(r13, sp);
+
+  if (extraspace)
+    __ sub(sp, sp, extraspace);
+
+  // Now write the args into the outgoing interpreter space
+
+  int ignored = 0, next_vt_arg = 0, next_arg_int = 0;
+  bool has_oop_field = false;
+
+  for (int next_arg_comp = 0; next_arg_comp < total_args_passed; next_arg_comp++) {
+    BasicType bt = sig_extended->at(next_arg_comp)._bt;
+    // offset to start parameters
+    int st_off   = (total_args_passed - next_arg_int - 1) * Interpreter::stackElementSize;
+
+    if (!InlineTypePassFieldsAsArgs || bt != T_INLINE_TYPE) {
+
+            if (SigEntry::is_reserved_entry(sig_extended, next_arg_comp)) {
+               continue; // Ignore reserved entry
+            }
+
+            if (bt == T_VOID) {
+               assert(next_arg_comp > 0 && (sig_extended->at(next_arg_comp - 1)._bt == T_LONG || sig_extended->at(next_arg_comp - 1)._bt == T_DOUBLE), "missing half");
+               next_arg_int ++;
+               continue;
+             }
+
+             int next_off = st_off - Interpreter::stackElementSize;
+             int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off;
+
+             gen_c2i_adapter_helper(masm, bt, regs[next_arg_comp], extraspace, Address(sp, offset));
+             next_arg_int ++;
+   } else {
+       ignored++;
+      // get the buffer from the just allocated pool of buffers
+      int index = arrayOopDesc::base_offset_in_bytes(T_OBJECT) + next_vt_arg * type2aelembytes(T_INLINE_TYPE);
+      __ load_heap_oop(rscratch1, Address(r10, index));
+      next_vt_arg++;
+      next_arg_int++;
+      int vt = 1;
+      // write fields we get from compiled code in registers/stack
+      // slots to the buffer: we know we are done with that inline type
+      // argument when we hit the T_VOID that acts as an end of value
+      // type delimiter for this inline type. Inline types are flattened
+      // so we might encounter embedded inline types. Each entry in
+      // sig_extended contains a field offset in the buffer.
+      do {
+        next_arg_comp++;
+        BasicType bt = sig_extended->at(next_arg_comp)._bt;
+        BasicType prev_bt = sig_extended->at(next_arg_comp - 1)._bt;
+        if (bt == T_INLINE_TYPE) {
+          vt++;
+          ignored++;
+        } else if (bt == T_VOID && prev_bt != T_LONG && prev_bt != T_DOUBLE) {
+          vt--;
+          ignored++;
+        } else if (SigEntry::is_reserved_entry(sig_extended, next_arg_comp)) {
+          // Ignore reserved entry
+        } else {
+          int off = sig_extended->at(next_arg_comp)._offset;
+          assert(off > 0, "offset in object should be positive");
+
+          bool is_oop = (bt == T_OBJECT || bt == T_ARRAY);
+          has_oop_field = has_oop_field || is_oop;
+
+          gen_c2i_adapter_helper(masm, bt, regs[next_arg_comp - ignored], extraspace, Address(r11, off));
+        }
+      } while (vt != 0);
+      // pass the buffer to the interpreter
+      __ str(rscratch1, Address(sp, st_off));
+   }
+
+  }
+
+// If an inline type was allocated and initialized, apply post barrier to all oop fields
+  if (has_inline_argument && has_oop_field) {
+    __ push(r13); // save senderSP
+    __ push(r1); // save callee
+    // Allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ sub(sp, sp, frame::arg_reg_save_area_bytes);
     }
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::apply_post_barriers), rthread, r10);
+    // De-allocate argument register save area
+    if (frame::arg_reg_save_area_bytes != 0) {
+      __ add(sp, sp, frame::arg_reg_save_area_bytes);
+    }
+    __ pop(r1); // restore callee
+    __ pop(r13); // restore sender SP
   }
 
   __ mov(esp, sp); // Interp expects args on caller's expression stack
 
   __ ldr(rscratch1, Address(rmethod, in_bytes(Method::interpreter_entry_offset())));
   __ br(rscratch1);
 }
 
+void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm, int comp_args_on_stack, const GrowableArray<SigEntry>* sig, const VMRegPair *regs) {
 
-void SharedRuntime::gen_i2c_adapter(MacroAssembler *masm,
-                                    int total_args_passed,
-                                    int comp_args_on_stack,
-                                    const BasicType *sig_bt,
-                                    const VMRegPair *regs) {
 
   // Note: r13 contains the senderSP on entry. We must preserve it since
   // we may do a i2c -> c2i transition if we lose a race where compiled
   // code goes non-entrant while we get args ready.
 
@@ -549,14 +773,15 @@
     __ block_comment("} verify_i2ce ");
 #endif
   }
 
   // Cut-out for having no stack args.
-  int comp_words_on_stack = align_up(comp_args_on_stack*VMRegImpl::stack_slot_size, wordSize)>>LogBytesPerWord;
+  int comp_words_on_stack = 0;
   if (comp_args_on_stack) {
-    __ sub(rscratch1, sp, comp_words_on_stack * wordSize);
-    __ andr(sp, rscratch1, -16);
+     comp_words_on_stack = align_up(comp_args_on_stack * VMRegImpl::stack_slot_size, wordSize) >> LogBytesPerWord;
+     __ sub(rscratch1, sp, comp_words_on_stack * wordSize);
+     __ andr(sp, rscratch1, -16);
   }
 
   // Will jump to the compiled code just as if compiled code was doing it.
   // Pre-load the register-jump target early, to schedule it better.
   __ ldr(rscratch1, Address(rmethod, in_bytes(Method::from_compiled_offset())));
@@ -571,22 +796,26 @@
     __ str(zr, Address(rthread, in_bytes(JavaThread::jvmci_alternate_call_target_offset())));
     __ bind(no_alternative_target);
   }
 #endif // INCLUDE_JVMCI
 
+  int total_args_passed = sig->length();
+
   // Now generate the shuffle code.
   for (int i = 0; i < total_args_passed; i++) {
-    if (sig_bt[i] == T_VOID) {
-      assert(i > 0 && (sig_bt[i-1] == T_LONG || sig_bt[i-1] == T_DOUBLE), "missing half");
+    BasicType bt = sig->at(i)._bt;
+
+    assert(bt != T_INLINE_TYPE, "i2c adapter doesn't unpack inline typ args");
+    if (bt == T_VOID) {
+      assert(i > 0 && (sig->at(i - 1)._bt == T_LONG || sig->at(i - 1)._bt == T_DOUBLE), "missing half");
       continue;
     }
 
     // Pick up 0, 1 or 2 words from SP+offset.
+    assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(), "scrambled load targets?");
 
-    assert(!regs[i].second()->is_valid() || regs[i].first()->next() == regs[i].second(),
-            "scrambled load targets?");
-    // Load in argument order going down.
+    // Load in argument order going down.
     int ld_off = (total_args_passed - i - 1)*Interpreter::stackElementSize;
     // Point to interpreter value (vs. tag)
     int next_off = ld_off - Interpreter::stackElementSize;
     //
     //
@@ -597,11 +826,11 @@
       assert(!r_2->is_valid(), "");
       continue;
     }
     if (r_1->is_stack()) {
       // Convert stack slot to an SP offset (+ wordSize to account for return address )
-      int st_off = regs[i].first()->reg2stack()*VMRegImpl::stack_slot_size;
+      int st_off = regs[i].first()->reg2stack() * VMRegImpl::stack_slot_size;
       if (!r_2->is_valid()) {
         // sign extend???
         __ ldrsw(rscratch2, Address(esp, ld_off));
         __ str(rscratch2, Address(sp, st_off));
       } else {
@@ -614,43 +843,42 @@
         //
         // Interpreter local[n] == MSW, local[n+1] == LSW however locals
         // are accessed as negative so LSW is at LOW address
 
         // ld_off is MSW so get LSW
-        const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
-                           next_off : ld_off;
+        const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
         __ ldr(rscratch2, Address(esp, offset));
         // st_off is LSW (i.e. reg.first())
-        __ str(rscratch2, Address(sp, st_off));
-      }
-    } else if (r_1->is_Register()) {  // Register argument
-      Register r = r_1->as_Register();
-      if (r_2->is_valid()) {
-        //
-        // We are using two VMRegs. This can be either T_OBJECT,
-        // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates
-        // two slots but only uses one for thr T_LONG or T_DOUBLE case
-        // So we must adjust where to pick up the data to match the
-        // interpreter.
+         __ str(rscratch2, Address(sp, st_off));
+       }
+     } else if (r_1->is_Register()) {  // Register argument
+       Register r = r_1->as_Register();
+       if (r_2->is_valid()) {
+         //
+         // We are using two VMRegs. This can be either T_OBJECT,
+         // T_ADDRESS, T_LONG, or T_DOUBLE the interpreter allocates
+         // two slots but only uses one for thr T_LONG or T_DOUBLE case
+         // So we must adjust where to pick up the data to match the
+         // interpreter.
+
+        const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
+
+         // this can be a misaligned move
+         __ ldr(r, Address(esp, offset));
+       } else {
+         // sign extend and use a full word?
+         __ ldrw(r, Address(esp, ld_off));
+       }
+     } else {
+       if (!r_2->is_valid()) {
+         __ ldrs(r_1->as_FloatRegister(), Address(esp, ld_off));
+       } else {
+         __ ldrd(r_1->as_FloatRegister(), Address(esp, next_off));
+       }
+     }
+   }
 
-        const int offset = (sig_bt[i]==T_LONG||sig_bt[i]==T_DOUBLE)?
-                           next_off : ld_off;
-
-        // this can be a misaligned move
-        __ ldr(r, Address(esp, offset));
-      } else {
-        // sign extend and use a full word?
-        __ ldrw(r, Address(esp, ld_off));
-      }
-    } else {
-      if (!r_2->is_valid()) {
-        __ ldrs(r_1->as_FloatRegister(), Address(esp, ld_off));
-      } else {
-        __ ldrd(r_1->as_FloatRegister(), Address(esp, next_off));
-      }
-    }
-  }
 
   // 6243940 We might end up in handle_wrong_method if
   // the callee is deoptimized as we race thru here. If that
   // happens we don't want to take a safepoint because the
   // caller frame will look interpreted and arguments are now
@@ -659,27 +887,14 @@
   // we try and find the callee by normal means a safepoint
   // is possible. So we stash the desired callee in the thread
   // and the vm will find there should this case occur.
 
   __ str(rmethod, Address(rthread, JavaThread::callee_target_offset()));
-
   __ br(rscratch1);
 }
 
-// ---------------------------------------------------------------
-AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
-                                                            int total_args_passed,
-                                                            int comp_args_on_stack,
-                                                            const BasicType *sig_bt,
-                                                            const VMRegPair *regs,
-                                                            AdapterFingerPrint* fingerprint) {
-  address i2c_entry = __ pc();
-
-  gen_i2c_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs);
-
-  address c2i_unverified_entry = __ pc();
-  Label skip_fixup;
+static void gen_inline_cache_check(MacroAssembler *masm, Label& skip_fixup) {
 
   Label ok;
 
   Register holder = rscratch2;
   Register receiver = j_rarg0;
@@ -710,39 +925,99 @@
     __ ldr(rscratch1, Address(rmethod, in_bytes(Method::code_offset())));
     __ cbz(rscratch1, skip_fixup);
     __ far_jump(RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
     __ block_comment("} c2i_unverified_entry");
   }
+}
+
+
+// ---------------------------------------------------------------
+AdapterHandlerEntry* SharedRuntime::generate_i2c2i_adapters(MacroAssembler *masm,
+                                                            int comp_args_on_stack,
+                                                            const GrowableArray<SigEntry>* sig,
+                                                            const VMRegPair* regs,
+                                                            const GrowableArray<SigEntry>* sig_cc,
+                                                            const VMRegPair* regs_cc,
+                                                            const GrowableArray<SigEntry>* sig_cc_ro,
+                                                            const VMRegPair* regs_cc_ro,
+                                                            AdapterFingerPrint* fingerprint,
+                                                            AdapterBlob*& new_adapter) {
+
+  address i2c_entry = __ pc();
+  gen_i2c_adapter(masm, comp_args_on_stack, sig, regs);
+
+  address c2i_unverified_entry = __ pc();
+  Label skip_fixup;
+
+  gen_inline_cache_check(masm, skip_fixup);
+
+  OopMapSet* oop_maps = new OopMapSet();
+  int frame_complete = CodeOffsets::frame_never_safe;
+  int frame_size_in_words = 0;
+
+  // Scalarized c2i adapter with non-scalarized receiver (i.e., don't pack receiver)
+  address c2i_inline_ro_entry = __ pc();
+  if (regs_cc != regs_cc_ro) {
+    Label unused;
+    gen_c2i_adapter(masm, sig_cc_ro, regs_cc_ro, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words, false);
+    skip_fixup = unused;
+  }
 
+  // Scalarized c2i adapter
   address c2i_entry = __ pc();
 
   // Class initialization barrier for static methods
   address c2i_no_clinit_check_entry = NULL;
+
   if (VM_Version::supports_fast_class_init_checks()) {
     Label L_skip_barrier;
-
-    { // Bypass the barrier for non-static methods
-      __ ldrw(rscratch1, Address(rmethod, Method::access_flags_offset()));
-      __ andsw(zr, rscratch1, JVM_ACC_STATIC);
+    { // Bypass the barrier for non-static methods
+        Register flags  = rscratch1;
+      __ ldrw(flags, Address(rmethod, Method::access_flags_offset()));
+      __ tst(flags, JVM_ACC_STATIC);
       __ br(Assembler::EQ, L_skip_barrier); // non-static
     }
 
-    __ load_method_holder(rscratch2, rmethod);
-    __ clinit_barrier(rscratch2, rscratch1, &L_skip_barrier);
-    __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub()));
+    Register klass = rscratch1;
+    __ load_method_holder(klass, rmethod);
+    // We pass rthread to this function on x86
+    __ clinit_barrier(klass, rscratch2, &L_skip_barrier /*L_fast_path*/);
+
+    __ far_jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
 
     __ bind(L_skip_barrier);
     c2i_no_clinit_check_entry = __ pc();
   }
 
   BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
   bs->c2i_entry_barrier(masm);
 
   gen_c2i_adapter(masm, total_args_passed, comp_args_on_stack, sig_bt, regs, skip_fixup);
 
+  address c2i_unverified_inline_entry = c2i_unverified_entry;
+
+ // Non-scalarized c2i adapter
+  address c2i_inline_entry = c2i_entry;
+  if (regs != regs_cc) {
+    Label inline_entry_skip_fixup;
+    c2i_unverified_inline_entry = __ pc();
+    gen_inline_cache_check(masm, inline_entry_skip_fixup);
+
+    c2i_inline_entry = __ pc();
+    Label unused;
+    gen_c2i_adapter(masm, sig, regs, inline_entry_skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words, false);
+  }
+
   __ flush();
-  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry);
+
+  // The c2i adapter might safepoint and trigger a GC. The caller must make sure that
+  // the GC knows about the location of oop argument locations passed to the c2i adapter.
+
+  bool caller_must_gc_arguments = (regs != regs_cc);
+  new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words + 10, oop_maps, caller_must_gc_arguments);
+
+  return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_inline_entry, c2i_inline_ro_entry, c2i_unverified_entry, c2i_unverified_inline_entry, c2i_no_clinit_check_entry);
 }
 
 int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
                                          VMRegPair *regs,
                                          VMRegPair *regs2,
@@ -781,10 +1056,11 @@
       case T_LONG:
         assert((i + 1) < total_args_passed && sig_bt[i + 1] == T_VOID, "expecting half");
         // fall through
       case T_OBJECT:
       case T_ARRAY:
+      case T_INLINE_TYPE:
       case T_ADDRESS:
       case T_METADATA:
         if (int_args < Argument::n_int_register_parameters_c) {
           regs[i].set2(INT_ArgReg[int_args++]->as_VMReg());
         } else {
@@ -1632,10 +1908,11 @@
           }
 #endif
           int_args++;
           break;
         }
+      case T_INLINE_TYPE:
       case T_OBJECT:
         assert(!is_critical_native, "no oop arguments");
         object_move(masm, map, oop_handle_offset, stack_slots, in_regs[i], out_regs[c_arg],
                     ((i == 0) && (!is_static)),
                     &receiver_offset);
@@ -1819,10 +2096,11 @@
   case T_DOUBLE :
   case T_FLOAT  :
     // Result is in v0 we'll save as needed
     break;
   case T_ARRAY:                 // Really a handle
+  case T_INLINE_TYPE:
   case T_OBJECT:                // Really a handle
       break; // can't de-handlize until after safepoint check
   case T_VOID: break;
   case T_LONG: break;
   default       : ShouldNotReachHere();
@@ -3044,6 +3322,111 @@
   masm->flush();
 
   // Set exception blob
   _exception_blob =  ExceptionBlob::create(&buffer, oop_maps, SimpleRuntimeFrame::framesize >> 1);
 }
+
+BufferedInlineTypeBlob* SharedRuntime::generate_buffered_inline_type_adapter(const InlineKlass* vk) {
+  BufferBlob* buf = BufferBlob::create("inline types pack/unpack", 16 * K);
+  CodeBuffer buffer(buf);
+  short buffer_locs[20];
+  buffer.insts()->initialize_shared_locs((relocInfo*)buffer_locs,
+                                         sizeof(buffer_locs)/sizeof(relocInfo));
+
+  MacroAssembler _masm(&buffer);
+  MacroAssembler* masm = &_masm;
+
+  const Array<SigEntry>* sig_vk = vk->extended_sig();
+  const Array<VMRegPair>* regs = vk->return_regs();
+
+  int pack_fields_off = __ offset();
+
+  int j = 1;
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_INLINE_TYPE) {
+      continue;
+    }
+    if (bt == T_VOID) {
+      if (sig_vk->at(i-1)._bt == T_LONG ||
+          sig_vk->at(i-1)._bt == T_DOUBLE) {
+        j++;
+      }
+      continue;
+    }
+    int off = sig_vk->at(i)._offset;
+    VMRegPair pair = regs->at(j);
+    VMReg r_1 = pair.first();
+    VMReg r_2 = pair.second();
+    Address to(r0, off);
+    if (bt == T_FLOAT) {
+      __ strs(r_1->as_FloatRegister(), to);
+    } else if (bt == T_DOUBLE) {
+      __ strd(r_1->as_FloatRegister(), to);
+    } else if (bt == T_OBJECT || bt == T_ARRAY) {
+      Register val = r_1->as_Register();
+      assert_different_registers(r0, val);
+      // We don't need barriers because the destination is a newly allocated object.
+      // Also, we cannot use store_heap_oop(to, val) because it uses r8 as tmp.
+      if (UseCompressedOops) {
+        __ encode_heap_oop(val);
+        __ str(val, to);
+      } else {
+        __ str(val, to);
+      }
+    } else {
+      assert(is_java_primitive(bt), "unexpected basic type");
+      assert_different_registers(r0, r_1->as_Register());
+      size_t size_in_bytes = type2aelembytes(bt);
+      __ store_sized_value(to, r_1->as_Register(), size_in_bytes);
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+
+  __ ret(lr);
+
+  int unpack_fields_off = __ offset();
+
+  j = 1;
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_INLINE_TYPE) {
+      continue;
+    }
+    if (bt == T_VOID) {
+      if (sig_vk->at(i-1)._bt == T_LONG ||
+          sig_vk->at(i-1)._bt == T_DOUBLE) {
+        j++;
+      }
+      continue;
+    }
+    int off = sig_vk->at(i)._offset;
+    VMRegPair pair = regs->at(j);
+    VMReg r_1 = pair.first();
+    VMReg r_2 = pair.second();
+    Address from(r0, off);
+    if (bt == T_FLOAT) {
+      __ ldrs(r_1->as_FloatRegister(), from);
+    } else if (bt == T_DOUBLE) {
+      __ ldrd(r_1->as_FloatRegister(), from);
+    } else if (bt == T_OBJECT || bt == T_ARRAY) {
+       assert_different_registers(r0, r_1->as_Register());
+       __ load_heap_oop(r_1->as_Register(), from);
+    } else {
+      assert(is_java_primitive(bt), "unexpected basic type");
+      assert_different_registers(r0, r_1->as_Register());
+
+      size_t size_in_bytes = type2aelembytes(bt);
+      __ load_sized_value(r_1->as_Register(), from, size_in_bytes, bt != T_CHAR && bt != T_BOOLEAN);
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+
+  __ ret(lr);
+
+  __ flush();
+
+  return BufferedInlineTypeBlob::create(&buffer, pack_fields_off, unpack_fields_off);
+}
 #endif // COMPILER2
diff a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
@@ -146,11 +146,11 @@
 static void do_oop_store(InterpreterMacroAssembler* _masm,
                          Address dst,
                          Register val,
                          DecoratorSet decorators) {
   assert(val == noreg || val == r0, "parameter is just for looks");
-  __ store_heap_oop(dst, val, r10, r1, decorators);
+  __ store_heap_oop(dst, val, r10, r1, noreg, decorators);
 }
 
 static void do_oop_load(InterpreterMacroAssembler* _masm,
                         Address src,
                         Register dst,
@@ -169,10 +169,11 @@
 {
   if (!RewriteBytecodes)  return;
   Label L_patch_done;
 
   switch (bc) {
+  case Bytecodes::_fast_qputfield:
   case Bytecodes::_fast_aputfield:
   case Bytecodes::_fast_bputfield:
   case Bytecodes::_fast_zputfield:
   case Bytecodes::_fast_cputfield:
   case Bytecodes::_fast_dputfield:
@@ -744,14 +745,14 @@
     assert(r1 != array, "different registers");
     __ mov(r1, index);
   }
   Label ok;
   __ br(Assembler::LO, ok);
-    // ??? convention: move array into r3 for exception message
-  __ mov(r3, array);
-  __ mov(rscratch1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
-  __ br(rscratch1);
+  // ??? convention: move array into r3 for exception message
+   __ mov(r3, array);
+   __ mov(rscratch1, Interpreter::_throw_ArrayIndexOutOfBoundsException_entry);
+   __ br(rscratch1);
   __ bind(ok);
 }
 
 void TemplateTable::iaload()
 {
@@ -807,15 +808,25 @@
   __ mov(r1, r0);
   __ pop_ptr(r0);
   // r0: array
   // r1: index
   index_check(r0, r1); // leaves index in r1, kills rscratch1
-  __ add(r1, r1, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
-  do_oop_load(_masm,
-              Address(r0, r1, Address::uxtw(LogBytesPerHeapOop)),
-              r0,
-              IS_ARRAY);
+  if (UseFlatArray) {
+    Label is_flat_array, done;
+
+    __ test_flattened_array_oop(r0, r8 /*temp*/, is_flat_array);
+    __ add(r1, r1, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
+    do_oop_load(_masm, Address(r0, r1, Address::uxtw(LogBytesPerHeapOop)), r0, IS_ARRAY);
+
+    __ b(done);
+    __ bind(is_flat_array);
+    __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_load), r0, r1);
+    __ bind(done);
+  } else {
+    __ add(r1, r1, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
+    do_oop_load(_masm, Address(r0, r1, Address::uxtw(LogBytesPerHeapOop)), r0, IS_ARRAY);
+  }
 }
 
 void TemplateTable::baload()
 {
   transition(itos, itos);
@@ -1108,46 +1119,109 @@
   __ ldr(r3, at_tos_p2()); // array
 
   Address element_address(r3, r4, Address::uxtw(LogBytesPerHeapOop));
 
   index_check(r3, r2);     // kills r1
+
+  // FIXME: Could we remove the line below?
   __ add(r4, r2, arrayOopDesc::base_offset_in_bytes(T_OBJECT) >> LogBytesPerHeapOop);
 
   // do array store check - check for NULL value first
   __ cbz(r0, is_null);
 
+  Label  is_flat_array;
+  if (UseFlatArray) {
+    __ test_flattened_array_oop(r3, r8 /*temp*/, is_flat_array);
+  }
+
   // Move subklass into r1
   __ load_klass(r1, r0);
+
   // Move superklass into r0
   __ load_klass(r0, r3);
-  __ ldr(r0, Address(r0,
-                     ObjArrayKlass::element_klass_offset()));
+  __ ldr(r0, Address(r0, ObjArrayKlass::element_klass_offset()));
   // Compress array + index*oopSize + 12 into a single register.  Frees r2.
 
   // Generate subtype check.  Blows r2, r5
   // Superklass in r0.  Subklass in r1.
+
   __ gen_subtype_check(r1, ok_is_subtype);
 
   // Come here on failure
   // object is at TOS
   __ b(Interpreter::_throw_ArrayStoreException_entry);
 
+
   // Come here on success
   __ bind(ok_is_subtype);
 
+
   // Get the value we will store
   __ ldr(r0, at_tos());
   // Now store using the appropriate barrier
   do_oop_store(_masm, element_address, r0, IS_ARRAY);
   __ b(done);
 
   // Have a NULL in r0, r3=array, r2=index.  Store NULL at ary[idx]
   __ bind(is_null);
   __ profile_null_seen(r2);
 
+  if (EnableValhalla) {
+    Label is_null_into_value_array_npe, store_null;
+
+    // No way to store null in flat array
+    __ test_null_free_array_oop(r3, r8, is_null_into_value_array_npe);
+    __ b(store_null);
+
+    __ bind(is_null_into_value_array_npe);
+    __ b(ExternalAddress(Interpreter::_throw_NullPointerException_entry));
+
+    __ bind(store_null);
+  }
+
   // Store a NULL
   do_oop_store(_masm, element_address, noreg, IS_ARRAY);
+  __ b(done);
+
+  if (EnableValhalla) {
+     Label is_type_ok;
+
+    // store non-null value
+    __ bind(is_flat_array);
+
+    // Simplistic type check...
+    // r0 - value, r2 - index, r3 - array.
+
+    // Profile the not-null value's klass.
+    // Load value class
+     __ load_klass(r1, r0);
+     __ profile_typecheck(r2, r1, r0); // blows r2, and r0
+
+    // flat value array needs exact type match
+    // is "r8 == r0" (value subclass == array element superclass)
+
+    // Move element klass into r0
+
+     __ load_klass(r0, r3);
+
+     __ ldr(r0, Address(r0, ArrayKlass::element_klass_offset()));
+     __ cmp(r0, r1);
+     __ br(Assembler::EQ, is_type_ok);
+
+     __ profile_typecheck_failed(r2);
+     __ b(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry));
+
+     __ bind(is_type_ok);
+
+    // Reload from TOS to be safe, because of profile_typecheck that blows r2 and r0.
+    // FIXME: Should we really do it?
+     __ ldr(r1, at_tos());  // value
+     __ mov(r2, r3); // array, ldr(r2, at_tos_p2());
+     __ ldr(r3, at_tos_p1()); // index
+     __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_store), r1, r2, r3);
+  }
+
 
   // Pop stack arguments
   __ bind(done);
   __ add(esp, esp, 3 * Interpreter::stackElementSize);
 }
@@ -2014,23 +2088,69 @@
   branch(false, false);
   __ bind(not_taken);
   __ profile_not_taken_branch(r0);
 }
 
-void TemplateTable::if_acmp(Condition cc)
-{
+void TemplateTable::if_acmp(Condition cc) {
   transition(atos, vtos);
   // assume branch is more often taken than not (loops use backward branches)
-  Label not_taken;
+  Label taken, not_taken;
   __ pop_ptr(r1);
+
+  Register is_value_mask = rscratch1;
+  __ mov(is_value_mask, markWord::always_locked_pattern);
+
+  if (EnableValhalla) {
+    __ cmp(r1, r0);
+    __ br(Assembler::EQ, (cc == equal) ? taken : not_taken);
+
+    // might be substitutable, test if either r0 or r1 is null
+    __ andr(r2, r0, r1);
+    __ cbz(r2, (cc == equal) ? not_taken : taken);
+
+    // and both are values ?
+    __ ldr(r2, Address(r1, oopDesc::mark_offset_in_bytes()));
+    __ andr(r2, r2, is_value_mask);
+    __ ldr(r4, Address(r0, oopDesc::mark_offset_in_bytes()));
+    __ andr(r4, r4, is_value_mask);
+    __ andr(r2, r2, r4);
+    __ cmp(r2,  is_value_mask);
+    __ br(Assembler::NE, (cc == equal) ? not_taken : taken);
+
+    // same value klass ?
+    __ load_metadata(r2, r1);
+    __ load_metadata(r4, r0);
+    __ cmp(r2, r4);
+    __ br(Assembler::NE, (cc == equal) ? not_taken : taken);
+
+    // Know both are the same type, let's test for substitutability...
+    if (cc == equal) {
+      invoke_is_substitutable(r0, r1, taken, not_taken);
+    } else {
+      invoke_is_substitutable(r0, r1, not_taken, taken);
+    }
+    __ stop("Not reachable");
+  }
+
   __ cmpoop(r1, r0);
   __ br(j_not(cc), not_taken);
+  __ bind(taken);
   branch(false, false);
   __ bind(not_taken);
   __ profile_not_taken_branch(r0);
 }
 
+void TemplateTable::invoke_is_substitutable(Register aobj, Register bobj,
+                                            Label& is_subst, Label& not_subst) {
+
+  __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::is_substitutable), aobj, bobj);
+  // Restored... r0 answer, jmp to outcome...
+  __ cbz(r0, not_subst);
+  __ b(is_subst);
+}
+
+
 void TemplateTable::ret() {
   transition(vtos, vtos);
   // We might be moving to a safepoint.  The thread which calls
   // Interpreter::notice_safepoints() will effectively flush its cache
   // when it makes a system call, but we need to do something to
@@ -2499,12 +2619,11 @@
   Label Done, notByte, notBool, notInt, notShort, notChar,
               notLong, notFloat, notObj, notDouble;
 
   // x86 uses a shift and mask or wings it with a shift plus assert
   // the mask is not needed. aarch64 just uses bitfield extract
-  __ ubfxw(flags, raw_flags, ConstantPoolCacheEntry::tos_state_shift,
-           ConstantPoolCacheEntry::tos_state_bits);
+  __ ubfxw(flags, raw_flags, ConstantPoolCacheEntry::tos_state_shift, ConstantPoolCacheEntry::tos_state_bits);
 
   assert(btos == 0, "change code, btos != 0");
   __ cbnz(flags, notByte);
 
   // Don't rewrite getstatic, only getfield
@@ -2535,16 +2654,72 @@
 
   __ bind(notBool);
   __ cmp(flags, (u1)atos);
   __ br(Assembler::NE, notObj);
   // atos
-  do_oop_load(_masm, field, r0, IN_HEAP);
-  __ push(atos);
-  if (rc == may_rewrite) {
-    patch_bytecode(Bytecodes::_fast_agetfield, bc, r1);
+  if (!EnableValhalla) {
+    do_oop_load(_masm, field, r0, IN_HEAP);
+    __ push(atos);
+    if (rc == may_rewrite) {
+      patch_bytecode(Bytecodes::_fast_agetfield, bc, r1);
+    }
+    __ b(Done);
+  } else { // Valhalla
+
+    if (is_static) {
+      __ load_heap_oop(r0, field);
+      Label is_inline, isUninitialized;
+      // Issue below if the static field has not been initialized yet
+      __ test_field_is_inline_type(raw_flags, r8 /*temp*/, is_inline);
+        // Not inline case
+        __ push(atos);
+        __ b(Done);
+      // Inline case, must not return null even if uninitialized
+      __ bind(is_inline);
+        __ cbz(r0, isUninitialized);
+          __ push(atos);
+          __ b(Done);
+        __ bind(isUninitialized);
+          __ andw(raw_flags, raw_flags, ConstantPoolCacheEntry::field_index_mask);
+          __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::uninitialized_static_inline_type_field), obj, raw_flags);
+          __ verify_oop(r0);
+          __ push(atos);
+          __ b(Done);
+    } else {
+      Label isFlattened, isInitialized, is_inline, rewrite_inline;
+        __ test_field_is_inline_type(raw_flags, r8 /*temp*/, is_inline);
+        // Non-inline field case
+        __ load_heap_oop(r0, field);
+        __ push(atos);
+        if (rc == may_rewrite) {
+          patch_bytecode(Bytecodes::_fast_agetfield, bc, r1);
+        }
+        __ b(Done);
+      __ bind(is_inline);
+        __ test_field_is_inlined(raw_flags, r8 /* temp */, isFlattened);
+         // Non-inline field case
+          __ load_heap_oop(r0, field);
+          __ cbnz(r0, isInitialized);
+            __ andw(raw_flags, raw_flags, ConstantPoolCacheEntry::field_index_mask);
+            __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::uninitialized_instance_inline_type_field), obj, raw_flags);
+          __ bind(isInitialized);
+          __ verify_oop(r0);
+          __ push(atos);
+          __ b(rewrite_inline);
+        __ bind(isFlattened);
+          __ ldr(r10, Address(cache, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f1_offset())));
+          __ andw(raw_flags, raw_flags, ConstantPoolCacheEntry::field_index_mask);
+          call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::read_flattened_field), obj, raw_flags, r10);
+          __ verify_oop(r0);
+          __ push(atos);
+      __ bind(rewrite_inline);
+      if (rc == may_rewrite) {
+         patch_bytecode(Bytecodes::_fast_qgetfield, bc, r1);
+      }
+      __ b(Done);
+    }
   }
-  __ b(Done);
 
   __ bind(notObj);
   __ cmp(flags, (u1)itos);
   __ br(Assembler::NE, notInt);
   // itos
@@ -2710,10 +2885,11 @@
   const Register cache = r2;
   const Register index = r3;
   const Register obj   = r2;
   const Register off   = r19;
   const Register flags = r0;
+  const Register flags2 = r6;
   const Register bc    = r4;
 
   resolve_cache_and_index(byte_no, cache, index, sizeof(u2));
   jvmti_post_field_mod(cache, index, is_static);
   load_field_cp_cache_entry(obj, cache, index, off, flags, is_static);
@@ -2732,10 +2908,12 @@
   const Address field(obj, off);
 
   Label notByte, notBool, notInt, notShort, notChar,
         notLong, notFloat, notObj, notDouble;
 
+  __ mov(flags2, flags);
+
   // x86 uses a shift and mask or wings it with a shift plus assert
   // the mask is not needed. aarch64 just uses bitfield extract
   __ ubfxw(flags, flags, ConstantPoolCacheEntry::tos_state_shift,  ConstantPoolCacheEntry::tos_state_bits);
 
   assert(btos == 0, "change code, btos != 0");
@@ -2774,18 +2952,60 @@
   __ cmp(flags, (u1)atos);
   __ br(Assembler::NE, notObj);
 
   // atos
   {
-    __ pop(atos);
-    if (!is_static) pop_and_check_object(obj);
-    // Store into the field
-    do_oop_store(_masm, field, r0, IN_HEAP);
-    if (rc == may_rewrite) {
-      patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no);
-    }
-    __ b(Done);
+     if (!EnableValhalla) {
+      __ pop(atos);
+      if (!is_static) pop_and_check_object(obj);
+      // Store into the field
+      do_oop_store(_masm, field, r0, IN_HEAP);
+      if (rc == may_rewrite) {
+        patch_bytecode(Bytecodes::_fast_aputfield, bc, r1, true, byte_no);
+      }
+      __ b(Done);
+     } else { // Valhalla
+
+      __ pop(atos);
+      if (is_static) {
+        Label not_inline;
+         __ test_field_is_not_inline_type(flags2, r8 /* temp */, not_inline);
+         __ null_check(r0);
+         __ bind(not_inline);
+         do_oop_store(_masm, field, r0, IN_HEAP);
+         __ b(Done);
+      } else {
+        Label is_inline, isFlattened, rewrite_not_inline, rewrite_inline;
+        __ test_field_is_inline_type(flags2, r8 /*temp*/, is_inline);
+        // Not inline case
+        pop_and_check_object(obj);
+        // Store into the field
+        do_oop_store(_masm, field, r0, IN_HEAP);
+        __ bind(rewrite_not_inline);
+        if (rc == may_rewrite) {
+          patch_bytecode(Bytecodes::_fast_aputfield, bc, r19, true, byte_no);
+        }
+        __ b(Done);
+        // Implementation of the inline semantic
+        __ bind(is_inline);
+        __ null_check(r0);
+        __ test_field_is_inlined(flags2, r8 /*temp*/, isFlattened);
+        // Not inline case
+        pop_and_check_object(obj);
+        // Store into the field
+        do_oop_store(_masm, field, r0, IN_HEAP);
+        __ b(rewrite_inline);
+        __ bind(isFlattened);
+        pop_and_check_object(obj);
+        call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::write_flattened_value), r0, off, obj);
+        __ bind(rewrite_inline);
+        if (rc == may_rewrite) {
+          patch_bytecode(Bytecodes::_fast_qputfield, bc, r19, true, byte_no);
+        }
+        __ b(Done);
+      }
+     }  // Valhalla
   }
 
   __ bind(notObj);
   __ cmp(flags, (u1)itos);
   __ br(Assembler::NE, notInt);
@@ -2921,10 +3141,11 @@
     __ push_ptr(r19);                 // put the object pointer back on tos
     // Save tos values before call_VM() clobbers them. Since we have
     // to do it for every data type, we use the saved values as the
     // jvalue object.
     switch (bytecode()) {          // load values into the jvalue object
+    case Bytecodes::_fast_qputfield: //fall through
     case Bytecodes::_fast_aputfield: __ push_ptr(r0); break;
     case Bytecodes::_fast_bputfield: // fall through
     case Bytecodes::_fast_zputfield: // fall through
     case Bytecodes::_fast_sputfield: // fall through
     case Bytecodes::_fast_cputfield: // fall through
@@ -2947,10 +3168,11 @@
                CAST_FROM_FN_PTR(address,
                                 InterpreterRuntime::post_field_modification),
                r19, c_rarg2, c_rarg3);
 
     switch (bytecode()) {             // restore tos values
+    case Bytecodes::_fast_qputfield: //fall through
     case Bytecodes::_fast_aputfield: __ pop_ptr(r0); break;
     case Bytecodes::_fast_bputfield: // fall through
     case Bytecodes::_fast_zputfield: // fall through
     case Bytecodes::_fast_sputfield: // fall through
     case Bytecodes::_fast_cputfield: // fall through
@@ -3000,10 +3222,23 @@
   // field address
   const Address field(r2, r1);
 
   // access field
   switch (bytecode()) {
+  case Bytecodes::_fast_qputfield: //fall through
+   {
+      Label isFlattened, done;
+      __ null_check(r0);
+      __ test_field_is_flattened(r3, r8 /* temp */, isFlattened);
+      // No Flattened case
+      do_oop_store(_masm, field, r0, IN_HEAP);
+      __ b(done);
+      __ bind(isFlattened);
+      call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::write_flattened_value), r0, r1, r2);
+      __ bind(done);
+    }
+    break;
   case Bytecodes::_fast_aputfield:
     do_oop_store(_masm, field, r0, IN_HEAP);
     break;
   case Bytecodes::_fast_lputfield:
     __ access_store_at(T_LONG, IN_HEAP, field, r0, noreg, noreg);
@@ -3097,10 +3332,36 @@
     __ bind(notVolatile);
   }
 
   // access field
   switch (bytecode()) {
+  case Bytecodes::_fast_qgetfield:
+    {
+       Label isFlattened, isInitialized, Done;
+       // FIXME: We don't need to reload registers multiple times, but stay close to x86 code
+       __ ldrw(r9, Address(r2, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())));
+       __ test_field_is_inlined(r9, r8 /* temp */, isFlattened);
+        // Non-flattened field case
+        __ mov(r9, r0);
+        __ load_heap_oop(r0, field);
+        __ cbnz(r0, isInitialized);
+          __ mov(r0, r9);
+          __ ldrw(r9, Address(r2, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())));
+          __ andw(r9, r9, ConstantPoolCacheEntry::field_index_mask);
+          __ call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::uninitialized_instance_inline_type_field), r0, r9);
+        __ bind(isInitialized);
+        __ verify_oop(r0);
+        __ b(Done);
+      __ bind(isFlattened);
+        __ ldrw(r9, Address(r2, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset())));
+        __ andw(r9, r9, ConstantPoolCacheEntry::field_index_mask);
+        __ ldr(r3, Address(r2, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::f1_offset())));
+        call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::read_flattened_field), r0, r9, r3);
+        __ verify_oop(r0);
+      __ bind(Done);
+    }
+    break;
   case Bytecodes::_fast_agetfield:
     do_oop_load(_masm, field, r0, IN_HEAP);
     __ verify_oop(r0);
     break;
   case Bytecodes::_fast_lgetfield:
@@ -3652,10 +3913,34 @@
   __ bind(done);
   // Must prevent reordering of stores for object initialization with stores that publish the new object.
   __ membar(Assembler::StoreStore);
 }
 
+void TemplateTable::defaultvalue() {
+  transition(vtos, atos);
+  __ get_unsigned_2_byte_index_at_bcp(c_rarg2, 1);
+  __ get_constant_pool(c_rarg1);
+  call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::defaultvalue),
+          c_rarg1, c_rarg2);
+  __ verify_oop(r0);
+  // Must prevent reordering of stores for object initialization with stores that publish the new object.
+  __ membar(Assembler::StoreStore);
+}
+
+void TemplateTable::withfield() {
+  transition(vtos, atos);
+  resolve_cache_and_index(f2_byte, c_rarg1 /*cache*/, c_rarg2 /*index*/, sizeof(u2));
+
+  // n.b. unlike x86 cache is now rcpool plus the indexed offset
+  // so using rcpool to meet shared code expectations
+
+  call_VM(r1, CAST_FROM_FN_PTR(address, InterpreterRuntime::withfield), rcpool);
+  __ verify_oop(r1);
+  __ add(esp, esp, r0);
+  __ mov(r0, r1);
+}
+
 void TemplateTable::newarray() {
   transition(itos, atos);
   __ load_unsigned_byte(c_rarg1, at_bcp(1));
   __ mov(c_rarg2, r0);
   call_VM(r0, CAST_FROM_FN_PTR(address, InterpreterRuntime::newarray),
@@ -3723,16 +4008,31 @@
 
   // Come here on success
   __ bind(ok_is_subtype);
   __ mov(r0, r3); // Restore object in r3
 
+  __ b(done);
+  __ bind(is_null);
+
   // Collect counts on whether this test sees NULLs a lot or not.
   if (ProfileInterpreter) {
-    __ b(done);
-    __ bind(is_null);
-    __ profile_null_seen(r2);
-  } else {
+    __ profile_null_seen(r2);
+  }
+
+  if (EnableValhalla) {
+    // Get cpool & tags index
+    __ get_cpool_and_tags(r2, r3); // r2=cpool, r3=tags array
+    __ get_unsigned_2_byte_index_at_bcp(r19, 1); // r19=index
+     // See if bytecode has already been quicked
+    __ add(rscratch1, r3, Array<u1>::base_offset_in_bytes());
+    __ lea(r1, Address(rscratch1, r19));
+    __ ldarb(r1, r1);
+    // See if CP entry is a Q-descriptor
+    __ andr (r1, r1, JVM_CONSTANT_QDescBit);
+    __ cmp(r1, (u1) JVM_CONSTANT_QDescBit);
+    __ br(Assembler::NE, done);
+    __ b(ExternalAddress(Interpreter::_throw_NullPointerException_entry));
     __ bind(is_null);   // same as 'done'
   }
   __ bind(done);
 }
 
diff a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
--- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
+++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp
@@ -28,10 +28,11 @@
 #include "c1/c1_LIRAssembler.hpp"
 #include "c1/c1_MacroAssembler.hpp"
 #include "c1/c1_Runtime1.hpp"
 #include "classfile/javaClasses.hpp"
 #include "nativeInst_x86.hpp"
+#include "oops/objArrayKlass.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "utilities/align.hpp"
 #include "utilities/macros.hpp"
 #include "vmreg_x86.inline.hpp"
 
@@ -154,10 +155,83 @@
   ce->add_call_info_here(_info);
   debug_only(__ should_not_reach_here());
 }
 
 
+// Implementation of LoadFlattenedArrayStub
+
+LoadFlattenedArrayStub::LoadFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr result, CodeEmitInfo* info) {
+  _array = array;
+  _index = index;
+  _result = result;
+  // Tell the register allocator that the runtime call will scratch rax.
+  _scratch_reg = FrameMap::rax_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+void LoadFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_array->as_register(), 1);
+  ce->store_parameter(_index->as_register(), 0);
+  __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::load_flattened_array_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  if (_result->as_register() != rax) {
+    __ movptr(_result->as_register(), rax);
+  }
+  __ jmp(_continuation);
+}
+
+
+// Implementation of StoreFlattenedArrayStub
+
+StoreFlattenedArrayStub::StoreFlattenedArrayStub(LIR_Opr array, LIR_Opr index, LIR_Opr value, CodeEmitInfo* info) {
+  _array = array;
+  _index = index;
+  _value = value;
+  // Tell the register allocator that the runtime call will scratch rax.
+  _scratch_reg = FrameMap::rax_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+
+void StoreFlattenedArrayStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_array->as_register(), 2);
+  ce->store_parameter(_index->as_register(), 1);
+  ce->store_parameter(_value->as_register(), 0);
+  __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::store_flattened_array_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ jmp(_continuation);
+}
+
+
+// Implementation of SubstitutabilityCheckStub
+
+SubstitutabilityCheckStub::SubstitutabilityCheckStub(LIR_Opr left, LIR_Opr right, CodeEmitInfo* info) {
+  _left = left;
+  _right = right;
+  // Tell the register allocator that the runtime call will scratch rax.
+  _scratch_reg = FrameMap::rax_oop_opr;
+  _info = new CodeEmitInfo(info);
+}
+
+void SubstitutabilityCheckStub::emit_code(LIR_Assembler* ce) {
+  assert(__ rsp_offset() == 0, "frame size should be fixed");
+  __ bind(_entry);
+  ce->store_parameter(_left->as_register(), 1);
+  ce->store_parameter(_right->as_register(), 0);
+  __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::substitutability_check_id)));
+  ce->add_call_info_here(_info);
+  ce->verify_oop_map(_info);
+  __ jmp(_continuation);
+}
+
+
 // Implementation of NewInstanceStub
 
 NewInstanceStub::NewInstanceStub(LIR_Opr klass_reg, LIR_Opr result, ciInstanceKlass* klass, CodeEmitInfo* info, Runtime1::StubID stub_id) {
   _result = result;
   _klass = klass;
@@ -206,43 +280,63 @@
 }
 
 
 // Implementation of NewObjectArrayStub
 
-NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) {
+NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result,
+                                       CodeEmitInfo* info, bool is_inline_type) {
   _klass_reg = klass_reg;
   _result = result;
   _length = length;
   _info = new CodeEmitInfo(info);
+  _is_inline_type = is_inline_type;
 }
 
 
 void NewObjectArrayStub::emit_code(LIR_Assembler* ce) {
   assert(__ rsp_offset() == 0, "frame size should be fixed");
   __ bind(_entry);
   assert(_length->as_register() == rbx, "length must in rbx,");
   assert(_klass_reg->as_register() == rdx, "klass_reg must in rdx");
-  __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+  if (_is_inline_type) {
+    __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_flat_array_id)));
+  } else {
+    __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id)));
+  }
   ce->add_call_info_here(_info);
   ce->verify_oop_map(_info);
   assert(_result->as_register() == rax, "result must in rax,");
   __ jmp(_continuation);
 }
 
 
 // Implementation of MonitorAccessStubs
 
-MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info)
+MonitorEnterStub::MonitorEnterStub(LIR_Opr obj_reg, LIR_Opr lock_reg, CodeEmitInfo* info, CodeStub* throw_imse_stub, LIR_Opr scratch_reg)
 : MonitorAccessStub(obj_reg, lock_reg)
 {
   _info = new CodeEmitInfo(info);
+  _throw_imse_stub = throw_imse_stub;
+  _scratch_reg = scratch_reg;
+  if (_throw_imse_stub != NULL) {
+    assert(_scratch_reg != LIR_OprFact::illegalOpr, "must be");
+  }
 }
 
 
 void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
   assert(__ rsp_offset() == 0, "frame size should be fixed");
   __ bind(_entry);
+  if (_throw_imse_stub != NULL) {
+    // When we come here, _obj_reg has already been checked to be non-null.
+    const int is_value_mask = markWord::always_locked_pattern;
+    Register mark = _scratch_reg->as_register();
+    __ movptr(mark, Address(_obj_reg->as_register(), oopDesc::mark_offset_in_bytes()));
+    __ andptr(mark, is_value_mask);
+    __ cmpl(mark, is_value_mask);
+    __ jcc(Assembler::equal, *_throw_imse_stub->entry());
+  }
   ce->store_parameter(_obj_reg->as_register(),  1);
   ce->store_parameter(_lock_reg->as_register(), 0);
   Runtime1::StubID enter_id;
   if (ce->compilation()->has_fpu_code()) {
     enter_id = Runtime1::monitorenter_id;
diff a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -865,13 +865,10 @@
 
 void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
   Compile* C = ra_->C;
   MacroAssembler _masm(&cbuf);
 
-  int framesize = C->output()->frame_size_in_bytes();
-  int bangsize = C->output()->bang_size_in_bytes();
-
   if (C->clinit_barrier_on_entry()) {
     assert(VM_Version::supports_fast_class_init_checks(), "sanity");
     assert(!C->method()->holder()->is_not_initialized(), "initialization should have been started");
 
     Label L_skip_barrier;
@@ -883,11 +880,17 @@
     __ jump(RuntimeAddress(SharedRuntime::get_handle_wrong_method_stub())); // slow path
 
     __ bind(L_skip_barrier);
   }
 
-  __ verified_entry(framesize, C->output()->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL);
+  __ verified_entry(C);
+  __ bind(*_verified_entry);
+
+  if (C->stub_function() == NULL) {
+    BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+    bs->nmethod_entry_barrier(&_masm);
+  }
 
   C->output()->set_frame_complete(cbuf.insts_size());
 
   if (C->has_mach_constant_base_node()) {
     // NOTE: We set the table base offset here because users might be
@@ -895,16 +898,10 @@
     ConstantTable& constant_table = C->output()->constant_table();
     constant_table.set_table_base_offset(constant_table.calculate_table_base_offset());
   }
 }
 
-uint MachPrologNode::size(PhaseRegAlloc* ra_) const
-{
-  return MachNode::size(ra_); // too many variables; just compute it
-                              // the hard way
-}
-
 int MachPrologNode::reloc() const
 {
   return 0; // a large enough number
 }
 
@@ -948,33 +945,13 @@
     // Clear upper bits of YMM registers when current compiled code uses
     // wide vectors to avoid AVX <-> SSE transition penalty during call.
     __ vzeroupper();
   }
 
-  int framesize = C->output()->frame_size_in_bytes();
-  assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
-  // Remove word for return adr already pushed
-  // and RBP
-  framesize -= 2*wordSize;
-
-  // Note that VerifyStackAtCalls' Majik cookie does not change the frame size popped here
-
-  if (framesize) {
-    emit_opcode(cbuf, Assembler::REX_W);
-    if (framesize < 0x80) {
-      emit_opcode(cbuf, 0x83); // addq rsp, #framesize
-      emit_rm(cbuf, 0x3, 0x00, RSP_enc);
-      emit_d8(cbuf, framesize);
-    } else {
-      emit_opcode(cbuf, 0x81); // addq rsp, #framesize
-      emit_rm(cbuf, 0x3, 0x00, RSP_enc);
-      emit_d32(cbuf, framesize);
-    }
-  }
-
-  // popq rbp
-  emit_opcode(cbuf, 0x58 | RBP_enc);
+  // Subtract two words to account for return address and rbp
+  int initial_framesize = C->output()->frame_size_in_bytes() - 2*wordSize;
+  __ remove_frame(initial_framesize, C->needs_stack_repair(), C->output()->sp_inc_offset());
 
   if (StackReservedPages > 0 && C->has_reserved_stack_access()) {
     __ reserved_stack_check();
   }
 
@@ -984,16 +961,10 @@
     __ relocate(relocInfo::poll_return_type);
     __ testl(rax, Address(rscratch1, 0));
   }
 }
 
-uint MachEpilogNode::size(PhaseRegAlloc* ra_) const
-{
-  return MachNode::size(ra_); // too many variables; just compute it
-                              // the hard way
-}
-
 int MachEpilogNode::reloc() const
 {
   return 2; // a large enough number
 }
 
@@ -1525,10 +1496,38 @@
 {
   int offset = ra_->reg2offset(in_RegMask(0).find_first_elem());
   return (offset < 0x80) ? 5 : 8; // REX
 }
 
+//=============================================================================
+#ifndef PRODUCT
+void MachVEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
+{
+  st->print_cr("MachVEPNode");
+}
+#endif
+
+void MachVEPNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const
+{
+  MacroAssembler masm(&cbuf);
+  if (!_verified) {  
+    uint insts_size = cbuf.insts_size();
+    if (UseCompressedClassPointers) {
+      masm.load_klass(rscratch1, j_rarg0, rscratch2);
+      masm.cmpptr(rax, rscratch1);
+    } else {
+      masm.cmpptr(rax, Address(j_rarg0, oopDesc::klass_offset_in_bytes()));
+    }
+    masm.jump_cc(Assembler::notEqual, RuntimeAddress(SharedRuntime::get_ic_miss_stub()));
+  } else {
+    // Unpack inline type args passed as oop and then jump to
+    // the verified entry point (skipping the unverified entry).
+    masm.unpack_inline_args(ra_->C, _receiver_only);
+    masm.jmp(*_verified_entry);
+  }
+}
+
 //=============================================================================
 #ifndef PRODUCT
 void MachUEPNode::format(PhaseRegAlloc* ra_, outputStream* st) const
 {
   if (UseCompressedClassPointers) {
@@ -1567,17 +1566,10 @@
   nops_cnt &= 0x3; // Do not add nops if code is aligned.
   if (nops_cnt > 0)
     masm.nop(nops_cnt);
 }
 
-uint MachUEPNode::size(PhaseRegAlloc* ra_) const
-{
-  return MachNode::size(ra_); // too many variables; just compute it
-                              // the hard way
-}
-
-
 //=============================================================================
 
 int Matcher::regnum_to_fpu_offset(int regnum)
 {
   return regnum - 32; // The FP registers are in the second chunk
@@ -3856,10 +3848,26 @@
     scale($scale);
     disp($off);
   %}
 %}
 
+// Indirect Narrow Oop Operand
+operand indCompressedOop(rRegN reg) %{
+  predicate(UseCompressedOops && (CompressedOops::shift() == Address::times_8));
+  constraint(ALLOC_IN_RC(ptr_reg));
+  match(DecodeN reg);
+
+  op_cost(10);
+  format %{"[R12 + $reg << 3] (compressed oop addressing)" %}
+  interface(MEMORY_INTER) %{
+    base(0xc); // R12
+    index($reg);
+    scale(0x3);
+    disp(0x0);
+  %}
+%}
+
 // Indirect Narrow Oop Plus Offset Operand
 // Note: x86 architecture doesn't support "scale * index + offset" without a base
 // we can't free r12 even with CompressedOops::base() == NULL.
 operand indCompressedOopOffset(rRegN reg, immL32 off) %{
   predicate(UseCompressedOops && (CompressedOops::shift() == Address::times_8));
@@ -4198,11 +4206,11 @@
 // multiple operand types with the same basic encoding and format.  The classic
 // case of this is memory operands.
 
 opclass memory(indirect, indOffset8, indOffset32, indIndexOffset, indIndex,
                indIndexScale, indPosIndexScale, indIndexScaleOffset, indPosIndexOffset, indPosIndexScaleOffset,
-               indCompressedOopOffset,
+               indCompressedOop, indCompressedOopOffset,
                indirectNarrow, indOffset8Narrow, indOffset32Narrow,
                indIndexOffsetNarrow, indIndexNarrow, indIndexScaleNarrow,
                indIndexScaleOffsetNarrow, indPosIndexOffsetNarrow, indPosIndexScaleOffsetNarrow);
 
 //----------PIPELINE-----------------------------------------------------------
@@ -6682,10 +6690,23 @@
     }
   %}
   ins_pipe(ialu_reg_reg); // XXX
 %}
 
+instruct castN2X(rRegL dst, rRegN src)
+%{
+  match(Set dst (CastP2X src));
+
+  format %{ "movq    $dst, $src\t# ptr -> long" %}
+  ins_encode %{
+    if ($dst$$reg != $src$$reg) {
+      __ movptr($dst$$Register, $src$$Register);
+    }
+  %}
+  ins_pipe(ialu_reg_reg); // XXX
+%}
+
 instruct castP2X(rRegL dst, rRegP src)
 %{
   match(Set dst (CastP2X src));
 
   format %{ "movq    $dst, $src\t# ptr -> long" %}
@@ -6695,10 +6716,37 @@
     }
   %}
   ins_pipe(ialu_reg_reg); // XXX
 %}
 
+instruct castN2I(rRegI dst, rRegN src)
+%{
+  match(Set dst (CastN2I src));
+
+  format %{ "movl    $dst, $src\t# compressed ptr -> int" %}
+  ins_encode %{
+    if ($dst$$reg != $src$$reg) {
+      __ movl($dst$$Register, $src$$Register);
+    }
+  %}
+  ins_pipe(ialu_reg_reg); // XXX
+%}
+
+instruct castI2N(rRegN dst, rRegI src)
+%{
+  match(Set dst (CastI2N src));
+
+  format %{ "movl    $dst, $src\t# int -> compressed ptr" %}
+  ins_encode %{
+    if ($dst$$reg != $src$$reg) {
+      __ movl($dst$$Register, $src$$Register);
+    }
+  %}
+  ins_pipe(ialu_reg_reg); // XXX
+%}
+
+
 // Convert oop into int for vectors alignment masking
 instruct convP2I(rRegI dst, rRegP src)
 %{
   match(Set dst (ConvL2I (CastP2X src)));
 
@@ -10908,19 +10956,18 @@
 %}
 
 
 // =======================================================================
 // fast clearing of an array
-instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
+instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegL val,
                   Universe dummy, rFlagsReg cr)
 %{
-  predicate(!((ClearArrayNode*)n)->is_large());
-  match(Set dummy (ClearArray cnt base));
-  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr);
+  predicate(!((ClearArrayNode*)n)->is_large() && !((ClearArrayNode*)n)->word_copy_only());
+  match(Set dummy (ClearArray (Binary cnt base) val));
+  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL cr);
 
   format %{ $$template
-    $$emit$$"xorq    rax, rax\t# ClearArray:\n\t"
     $$emit$$"cmp     InitArrayShortSize,rcx\n\t"
     $$emit$$"jg      LARGE\n\t"
     $$emit$$"dec     rcx\n\t"
     $$emit$$"js      DONE\t# Zero length\n\t"
     $$emit$$"mov     rax,(rdi,rcx,8)\t# LOOP\n\t"
@@ -10930,23 +10977,24 @@
     $$emit$$"# LARGE:\n\t"
     if (UseFastStosb) {
        $$emit$$"shlq    rcx,3\t# Convert doublewords to bytes\n\t"
        $$emit$$"rep     stosb\t# Store rax to *rdi++ while rcx--\n\t"
     } else if (UseXMMForObjInit) {
-       $$emit$$"mov     rdi,rax\n\t"
-       $$emit$$"vpxor   ymm0,ymm0,ymm0\n\t"
+       $$emit$$"movdq   $tmp, $val\n\t"
+       $$emit$$"punpcklqdq $tmp, $tmp\n\t"
+       $$emit$$"vinserti128_high $tmp, $tmp\n\t"
        $$emit$$"jmpq    L_zero_64_bytes\n\t"
        $$emit$$"# L_loop:\t# 64-byte LOOP\n\t"
-       $$emit$$"vmovdqu ymm0,(rax)\n\t"
-       $$emit$$"vmovdqu ymm0,0x20(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,0x20(rax)\n\t"
        $$emit$$"add     0x40,rax\n\t"
        $$emit$$"# L_zero_64_bytes:\n\t"
        $$emit$$"sub     0x8,rcx\n\t"
        $$emit$$"jge     L_loop\n\t"
        $$emit$$"add     0x4,rcx\n\t"
        $$emit$$"jl      L_tail\n\t"
-       $$emit$$"vmovdqu ymm0,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
        $$emit$$"add     0x20,rax\n\t"
        $$emit$$"sub     0x4,rcx\n\t"
        $$emit$$"# L_tail:\t# Clearing tail bytes\n\t"
        $$emit$$"add     0x4,rcx\n\t"
        $$emit$$"jle     L_end\n\t"
@@ -10961,42 +11009,98 @@
        $$emit$$"rep     stosq\t# Store rax to *rdi++ while rcx--\n\t"
     }
     $$emit$$"# DONE"
   %}
   ins_encode %{
-    __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register,
-                 $tmp$$XMMRegister, false);
+    __ clear_mem($base$$Register, $cnt$$Register, $val$$Register,
+                 $tmp$$XMMRegister, false, false);
   %}
   ins_pipe(pipe_slow);
 %}
 
-instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero,
+instruct rep_stos_word_copy(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegL val,
+                  Universe dummy, rFlagsReg cr)
+%{
+  predicate(!((ClearArrayNode*)n)->is_large() && ((ClearArrayNode*)n)->word_copy_only());
+  match(Set dummy (ClearArray (Binary cnt base) val));
+  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL cr);
+
+  format %{ $$template
+    $$emit$$"cmp     InitArrayShortSize,rcx\n\t"
+    $$emit$$"jg      LARGE\n\t"
+    $$emit$$"dec     rcx\n\t"
+    $$emit$$"js      DONE\t# Zero length\n\t"
+    $$emit$$"mov     rax,(rdi,rcx,8)\t# LOOP\n\t"
+    $$emit$$"dec     rcx\n\t"
+    $$emit$$"jge     LOOP\n\t"
+    $$emit$$"jmp     DONE\n\t"
+    $$emit$$"# LARGE:\n\t"
+    if (UseXMMForObjInit) {
+       $$emit$$"movdq   $tmp, $val\n\t"
+       $$emit$$"punpcklqdq $tmp, $tmp\n\t"
+       $$emit$$"vinserti128_high $tmp, $tmp\n\t"
+       $$emit$$"jmpq    L_zero_64_bytes\n\t"
+       $$emit$$"# L_loop:\t# 64-byte LOOP\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,0x20(rax)\n\t"
+       $$emit$$"add     0x40,rax\n\t"
+       $$emit$$"# L_zero_64_bytes:\n\t"
+       $$emit$$"sub     0x8,rcx\n\t"
+       $$emit$$"jge     L_loop\n\t"
+       $$emit$$"add     0x4,rcx\n\t"
+       $$emit$$"jl      L_tail\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"add     0x20,rax\n\t"
+       $$emit$$"sub     0x4,rcx\n\t"
+       $$emit$$"# L_tail:\t# Clearing tail bytes\n\t"
+       $$emit$$"add     0x4,rcx\n\t"
+       $$emit$$"jle     L_end\n\t"
+       $$emit$$"dec     rcx\n\t"
+       $$emit$$"# L_sloop:\t# 8-byte short loop\n\t"
+       $$emit$$"vmovq   xmm0,(rax)\n\t"
+       $$emit$$"add     0x8,rax\n\t"
+       $$emit$$"dec     rcx\n\t"
+       $$emit$$"jge     L_sloop\n\t"
+       $$emit$$"# L_end:\n\t"
+    } else {
+       $$emit$$"rep     stosq\t# Store rax to *rdi++ while rcx--\n\t"
+    }
+    $$emit$$"# DONE"
+  %}
+  ins_encode %{
+    __ clear_mem($base$$Register, $cnt$$Register, $val$$Register,
+                 $tmp$$XMMRegister, false, true);
+  %}
+  ins_pipe(pipe_slow);
+%}
+
+instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegL val,
                         Universe dummy, rFlagsReg cr)
 %{
-  predicate(((ClearArrayNode*)n)->is_large());
-  match(Set dummy (ClearArray cnt base));
-  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL zero, KILL cr);
+  predicate(((ClearArrayNode*)n)->is_large() && !((ClearArrayNode*)n)->word_copy_only());
+  match(Set dummy (ClearArray (Binary cnt base) val));
+  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL cr);
 
   format %{ $$template
     if (UseFastStosb) {
-       $$emit$$"xorq    rax, rax\t# ClearArray:\n\t"
        $$emit$$"shlq    rcx,3\t# Convert doublewords to bytes\n\t"
        $$emit$$"rep     stosb\t# Store rax to *rdi++ while rcx--"
     } else if (UseXMMForObjInit) {
-       $$emit$$"mov     rdi,rax\t# ClearArray:\n\t"
-       $$emit$$"vpxor   ymm0,ymm0,ymm0\n\t"
+       $$emit$$"movdq   $tmp, $val\n\t"
+       $$emit$$"punpcklqdq $tmp, $tmp\n\t"
+       $$emit$$"vinserti128_high $tmp, $tmp\n\t"
        $$emit$$"jmpq    L_zero_64_bytes\n\t"
        $$emit$$"# L_loop:\t# 64-byte LOOP\n\t"
-       $$emit$$"vmovdqu ymm0,(rax)\n\t"
-       $$emit$$"vmovdqu ymm0,0x20(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,0x20(rax)\n\t"
        $$emit$$"add     0x40,rax\n\t"
        $$emit$$"# L_zero_64_bytes:\n\t"
        $$emit$$"sub     0x8,rcx\n\t"
        $$emit$$"jge     L_loop\n\t"
        $$emit$$"add     0x4,rcx\n\t"
        $$emit$$"jl      L_tail\n\t"
-       $$emit$$"vmovdqu ymm0,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
        $$emit$$"add     0x20,rax\n\t"
        $$emit$$"sub     0x4,rcx\n\t"
        $$emit$$"# L_tail:\t# Clearing tail bytes\n\t"
        $$emit$$"add     0x4,rcx\n\t"
        $$emit$$"jle     L_end\n\t"
@@ -11006,17 +11110,62 @@
        $$emit$$"add     0x8,rax\n\t"
        $$emit$$"dec     rcx\n\t"
        $$emit$$"jge     L_sloop\n\t"
        $$emit$$"# L_end:\n\t"
     } else {
-       $$emit$$"xorq    rax, rax\t# ClearArray:\n\t"
        $$emit$$"rep     stosq\t# Store rax to *rdi++ while rcx--"
     }
   %}
   ins_encode %{
-    __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register,
-                 $tmp$$XMMRegister, true);
+    __ clear_mem($base$$Register, $cnt$$Register, $val$$Register,
+                 $tmp$$XMMRegister, true, false);
+  %}
+  ins_pipe(pipe_slow);
+%}
+
+instruct rep_stos_large_word_copy(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegL val, 
+                        Universe dummy, rFlagsReg cr)
+%{
+  predicate(((ClearArrayNode*)n)->is_large() && ((ClearArrayNode*)n)->word_copy_only());
+  match(Set dummy (ClearArray (Binary cnt base) val));
+  effect(USE_KILL cnt, USE_KILL base, TEMP tmp, KILL cr);
+
+  format %{ $$template
+    if (UseXMMForObjInit) {
+       $$emit$$"movdq   $tmp, $val\n\t"
+       $$emit$$"punpcklqdq $tmp, $tmp\n\t"
+       $$emit$$"vinserti128_high $tmp, $tmp\n\t"
+       $$emit$$"jmpq    L_zero_64_bytes\n\t"
+       $$emit$$"# L_loop:\t# 64-byte LOOP\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"vmovdqu $tmp,0x20(rax)\n\t"
+       $$emit$$"add     0x40,rax\n\t"
+       $$emit$$"# L_zero_64_bytes:\n\t"
+       $$emit$$"sub     0x8,rcx\n\t"
+       $$emit$$"jge     L_loop\n\t"
+       $$emit$$"add     0x4,rcx\n\t"
+       $$emit$$"jl      L_tail\n\t"
+       $$emit$$"vmovdqu $tmp,(rax)\n\t"
+       $$emit$$"add     0x20,rax\n\t"
+       $$emit$$"sub     0x4,rcx\n\t"
+       $$emit$$"# L_tail:\t# Clearing tail bytes\n\t"
+       $$emit$$"add     0x4,rcx\n\t"
+       $$emit$$"jle     L_end\n\t"
+       $$emit$$"dec     rcx\n\t"
+       $$emit$$"# L_sloop:\t# 8-byte short loop\n\t"
+       $$emit$$"vmovq   xmm0,(rax)\n\t"
+       $$emit$$"add     0x8,rax\n\t"
+       $$emit$$"dec     rcx\n\t"
+       $$emit$$"jge     L_sloop\n\t"
+       $$emit$$"# L_end:\n\t"
+    } else {
+       $$emit$$"rep     stosq\t# Store rax to *rdi++ while rcx--"
+    }
+  %}
+  ins_encode %{
+    __ clear_mem($base$$Register, $cnt$$Register, $val$$Register, 
+                 $tmp$$XMMRegister, true, true);
   %}
   ins_pipe(pipe_slow);
 %}
 
 instruct string_compareL(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
@@ -11577,10 +11726,21 @@
   opcode(0x85);
   ins_encode(REX_reg_mem(src, mem), OpcP, reg_mem(src, mem));
   ins_pipe(ialu_cr_reg_mem);
 %}
 
+// Fold array properties check
+instruct testI_mem_imm(rFlagsReg cr, memory mem, immI con, immI0 zero)
+%{
+  match(Set cr (CmpI (AndI (CastN2I (LoadNKlass mem)) con) zero));
+
+  format %{ "testl   $mem, $con" %}
+  opcode(0xF7, 0x00);
+  ins_encode(REX_mem(mem), OpcP, RM_opc_mem(0x00, mem), Con32(con));
+  ins_pipe(ialu_mem_imm);
+%}
+
 // Unsigned compare Instructions; really, same as signed except they
 // produce an rFlagsRegU instead of rFlagsReg.
 instruct compU_rReg(rFlagsRegU cr, rRegI op1, rRegI op2)
 %{
   match(Set cr (CmpU op1 op2));
@@ -11889,10 +12049,21 @@
   opcode(0x85);
   ins_encode(REX_reg_mem_wide(src, mem), OpcP, reg_mem(src, mem));
   ins_pipe(ialu_cr_reg_mem);
 %}
 
+// Fold array properties check
+instruct testL_reg_mem3(rFlagsReg cr, memory mem, rRegL src, immL0 zero)
+%{
+  match(Set cr (CmpL (AndL (CastP2X (LoadKlass mem)) src) zero));
+
+  format %{ "testq   $src, $mem\t# test array properties" %}
+  opcode(0x85);
+  ins_encode(REX_reg_mem_wide(src, mem), OpcP, reg_mem(src, mem));
+  ins_pipe(ialu_cr_reg_mem);
+%}
+
 // Manifest a CmpL result in an integer register.  Very painful.
 // This is the test to avoid.
 instruct cmpL3_reg_reg(rRegI dst, rRegL src1, rRegL src2, rFlagsReg flags)
 %{
   match(Set dst (CmpL3 src1 src2));
@@ -12556,12 +12727,28 @@
   ins_encode(clear_avx, Java_To_Runtime(meth));
   ins_pipe(pipe_slow);
 %}
 
 // Call runtime without safepoint
+// entry point is null, target holds the address to call
+instruct CallLeafNoFPInDirect(rRegP target)
+%{
+  predicate(n->as_Call()->entry_point() == NULL);
+  match(CallLeafNoFP target);
+
+  ins_cost(300);
+  format %{ "call_leaf_nofp,runtime indirect " %}
+  ins_encode %{
+     __ call($target$$Register);
+  %}
+
+  ins_pipe(pipe_slow);
+%}
+
 instruct CallLeafNoFPDirect(method meth)
 %{
+  predicate(n->as_Call()->entry_point() != NULL);
   match(CallLeafNoFP);
   effect(USE meth);
 
   ins_cost(300);
   format %{ "call_leaf_nofp,runtime " %}
diff a/src/hotspot/share/adlc/main.cpp b/src/hotspot/share/adlc/main.cpp
--- a/src/hotspot/share/adlc/main.cpp
+++ b/src/hotspot/share/adlc/main.cpp
@@ -213,10 +213,11 @@
   AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp");
   AD.addInclude(AD._CPP_file, "code/codeCache.hpp");
   AD.addInclude(AD._CPP_file, "code/compiledIC.hpp");
   AD.addInclude(AD._CPP_file, "code/nativeInst.hpp");
   AD.addInclude(AD._CPP_file, "code/vmreg.inline.hpp");
+  AD.addInclude(AD._CPP_file, "gc/shared/barrierSetAssembler.hpp");
   AD.addInclude(AD._CPP_file, "gc/shared/collectedHeap.inline.hpp");
   AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp");
   AD.addInclude(AD._CPP_file, "oops/compressedOops.hpp");
   AD.addInclude(AD._CPP_file, "oops/markWord.hpp");
   AD.addInclude(AD._CPP_file, "oops/method.hpp");
diff a/src/hotspot/share/c1/c1_Compilation.cpp b/src/hotspot/share/c1/c1_Compilation.cpp
--- a/src/hotspot/share/c1/c1_Compilation.cpp
+++ b/src/hotspot/share/c1/c1_Compilation.cpp
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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.
@@ -563,10 +563,11 @@
 , _exception_info_list(NULL)
 , _allocator(NULL)
 , _code(buffer_blob)
 , _has_access_indexed(false)
 , _interpreter_frame_size(0)
+, _compiled_entry_signature(method->get_Method())
 , _current_instruction(NULL)
 #ifndef PRODUCT
 , _last_instruction_printed(NULL)
 , _cfg_printer_output(NULL)
 #endif // PRODUCT
@@ -579,10 +580,14 @@
 #ifndef PRODUCT
   if (PrintCFGToFile) {
     _cfg_printer_output = new CFGPrinterOutput(this);
   }
 #endif
+  {
+    ResetNoHandleMark rnhm; // Huh? Required when doing class lookup of the Q-types
+    _compiled_entry_signature.compute_calling_conventions();
+  }
   compile_method();
   if (bailed_out()) {
     _env->record_method_not_compilable(bailout_msg(), !TieredCompilation);
     if (is_profiling()) {
       // Compilation failed, create MDO, which would signal the interpreter
diff a/src/hotspot/share/c1/c1_Compilation.hpp b/src/hotspot/share/c1/c1_Compilation.hpp
--- a/src/hotspot/share/c1/c1_Compilation.hpp
+++ b/src/hotspot/share/c1/c1_Compilation.hpp
@@ -29,10 +29,11 @@
 #include "ci/ciMethodData.hpp"
 #include "code/exceptionHandlerTable.hpp"
 #include "compiler/compilerDirectives.hpp"
 #include "memory/resourceArea.hpp"
 #include "runtime/deoptimization.hpp"
+#include "runtime/sharedRuntime.hpp"
 
 class CompilationResourceObj;
 class XHandlers;
 class ExceptionInfo;
 class DebugInformationRecorder;
@@ -89,10 +90,11 @@
   LinearScan*        _allocator;
   CodeOffsets        _offsets;
   CodeBuffer         _code;
   bool               _has_access_indexed;
   int                _interpreter_frame_size; // Stack space needed in case of a deoptimization
+  CompiledEntrySignature _compiled_entry_signature;
 
   // compilation helpers
   void initialize();
   void build_hir();
   void emit_lir();
@@ -256,10 +258,14 @@
   }
   bool profile_return() {
     return env()->comp_level() == CompLevel_full_profile &&
       C1UpdateMethodData && MethodData::profile_return();
   }
+  bool profile_array_accesses() {
+    return env()->comp_level() == CompLevel_full_profile &&
+      C1UpdateMethodData;
+  }
   bool age_code() const {
     return _method->profile_aging();
   }
 
   // will compilation make optimistic assumptions that might lead to
@@ -284,10 +290,17 @@
   }
 
   int interpreter_frame_size() const {
     return _interpreter_frame_size;
   }
+
+  const CompiledEntrySignature* compiled_entry_signature() const {
+    return &_compiled_entry_signature;
+  }
+  bool needs_stack_repair() const {
+    return compiled_entry_signature()->c1_needs_stack_repair();
+  }
 };
 
 
 // Macro definitions for unified bailout-support
 // The methods bailout() and bailed_out() are present in all classes
diff a/src/hotspot/share/ci/ciEnv.hpp b/src/hotspot/share/ci/ciEnv.hpp
--- a/src/hotspot/share/ci/ciEnv.hpp
+++ b/src/hotspot/share/ci/ciEnv.hpp
@@ -131,10 +131,12 @@
   ciField*   get_field_by_index(ciInstanceKlass* loading_klass,
                                 int field_index);
   ciMethod*  get_method_by_index(const constantPoolHandle& cpool,
                                  int method_index, Bytecodes::Code bc,
                                  ciInstanceKlass* loading_klass);
+  bool       is_inline_klass(const constantPoolHandle& cpool,
+                             int klass_index);
 
   // Implementation methods for loading and constant pool access.
   ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
                                   const constantPoolHandle& cpool,
                                   ciSymbol* klass_name,
@@ -195,10 +197,14 @@
 
   ciInstance* get_instance(oop o) {
     if (o == NULL) return NULL;
     return get_object(o)->as_instance();
   }
+  ciFlatArrayKlass* get_flat_array_klass(Klass* o) {
+    if (o == NULL) return NULL;
+    return get_metadata(o)->as_flat_array_klass();
+  }
   ciObjArrayKlass* get_obj_array_klass(Klass* o) {
     if (o == NULL) return NULL;
     return get_metadata(o)->as_obj_array_klass();
   }
   ciTypeArrayKlass* get_type_array_klass(Klass* o) {
diff a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp
--- a/src/hotspot/share/ci/ciMethod.hpp
+++ b/src/hotspot/share/ci/ciMethod.hpp
@@ -197,11 +197,11 @@
 
   bool caller_sensitive()      const { return get_Method()->caller_sensitive();      }
   bool force_inline()          const { return get_Method()->force_inline();          }
   bool dont_inline()           const { return get_Method()->dont_inline();           }
   bool intrinsic_candidate()   const { return get_Method()->intrinsic_candidate();   }
-  bool is_static_initializer() const { return get_Method()->is_static_initializer(); }
+  bool is_class_initializer()  const { return get_Method()->is_class_initializer(); }
 
   int comp_level();
   int highest_osr_comp_level();
 
   Bytecodes::Code java_code_at_bci(int bci) {
@@ -262,10 +262,11 @@
 
   // Does type profiling provide any useful information at this point?
   bool          argument_profiled_type(int bci, int i, ciKlass*& type, ProfilePtrKind& ptr_kind);
   bool          parameter_profiled_type(int i, ciKlass*& type, ProfilePtrKind& ptr_kind);
   bool          return_profiled_type(int bci, ciKlass*& type, ProfilePtrKind& ptr_kind);
+  bool          array_access_profiled_type(int bci, ciKlass*& array_type, ciKlass*& element_type, ProfilePtrKind& element_ptr, bool &flat_array, bool &null_free);
 
   ciField*      get_field_at_bci( int bci, bool &will_link);
   ciMethod*     get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
   ciMethod*     get_method_at_bci(int bci) {
     bool ignored_will_link;
@@ -336,10 +337,11 @@
   bool is_synchronized() const                   { return flags().is_synchronized(); }
   bool is_native      () const                   { return flags().is_native(); }
   bool is_interface   () const                   { return flags().is_interface(); }
   bool is_abstract    () const                   { return flags().is_abstract(); }
   bool is_strict      () const                   { return flags().is_strict(); }
+  bool has_vararg     () const                   { return flags().has_vararg(); }
 
   // Other flags
   bool is_empty_method() const;
   bool is_vanilla_constructor() const;
   bool is_final_method() const                   { return is_final() || holder()->is_final(); }
@@ -349,16 +351,17 @@
   bool has_loops      () const;
   bool has_jsrs       () const;
   bool is_getter      () const;
   bool is_setter      () const;
   bool is_accessor    () const;
-  bool is_initializer () const;
   bool can_be_statically_bound() const           { return _can_be_statically_bound; }
   bool has_reserved_stack_access() const         { return _has_reserved_stack_access; }
   bool is_boxing_method() const;
   bool is_unboxing_method() const;
-  bool is_object_initializer() const;
+  bool is_object_constructor() const;
+  bool is_static_init_factory() const;
+  bool is_object_constructor_or_class_initializer() const;
 
   bool can_be_statically_bound(ciInstanceKlass* context) const;
 
   // Replay data methods
   void dump_name_as_ascii(outputStream* st);
@@ -374,8 +377,12 @@
   // Print the name of this method in various incarnations.
   void print_name(outputStream* st = tty);
   void print_short_name(outputStream* st = tty);
 
   static bool is_consistent_info(ciMethod* declared_method, ciMethod* resolved_method);
+
+  // Support for the inline type calling convention
+  bool has_scalarized_args() const;
+  const GrowableArray<SigEntry>* get_sig_cc();
 };
 
 #endif // SHARE_CI_CIMETHOD_HPP
diff a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -1181,11 +1181,11 @@
 
       if (!UseJVMCINativeLibrary) {
         // Don't allow blocking compiles if inside a class initializer or while performing class loading
         vframeStream vfst((JavaThread*) thread);
         for (; !vfst.at_end(); vfst.next()) {
-          if (vfst.method()->is_static_initializer() ||
+        if (vfst.method()->is_class_initializer() ||
               (vfst.method()->method_holder()->is_subclass_of(SystemDictionary::ClassLoader_klass()) &&
                   vfst.method()->name() == vmSymbols::loadClass_name())) {
             blocking = false;
             break;
           }
diff a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
--- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
+++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
@@ -206,11 +206,11 @@
     assert(pre_val != NULL, "must be loaded already");
     // Nothing to be done if pre_val is null.
     if (pre_val->bottom_type() == TypePtr::NULL_PTR) return;
     assert(pre_val->bottom_type()->basic_type() == T_OBJECT, "or we shouldn't be here");
   }
-  assert(bt == T_OBJECT, "or we shouldn't be here");
+  assert(bt == T_OBJECT || bt == T_INLINE_TYPE, "or we shouldn't be here");
 
   IdealKit ideal(kit, true);
 
   Node* tls = __ thread(); // ThreadLocalStorage
 
diff a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp
@@ -1041,11 +1041,11 @@
 }
 #endif
 
 Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const {
   if (is_shenandoah_wb_pre_call(n)) {
-    uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt();
+    uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain_sig()->cnt();
     if (n->req() > cnt) {
       Node* addp = n->in(cnt);
       if (has_only_shenandoah_wb_pre_uses(addp)) {
         n->del_req(cnt);
         if (can_reshape) {
@@ -1128,11 +1128,11 @@
     case Op_CallLeaf:
     case Op_CallLeafNoFP: {
       assert (n->is_Call(), "");
       CallNode *call = n->as_Call();
       if (ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(call)) {
-        uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain()->cnt();
+        uint cnt = ShenandoahBarrierSetC2::write_ref_field_pre_entry_Type()->domain_sig()->cnt();
         if (call->req() > cnt) {
           assert(call->req() == cnt + 1, "only one extra input");
           Node *addp = call->in(cnt);
           assert(!ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(addp), "useless address computation?");
           call->del_req(cnt);
diff a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
@@ -458,11 +458,11 @@
           { -1,  ShenandoahNone},                 { -1,  ShenandoahNone},                 { -1,  ShenandoahNone} },
       };
 
       if (call->is_call_to_arraycopystub()) {
         Node* dest = NULL;
-        const TypeTuple* args = n->as_Call()->_tf->domain();
+        const TypeTuple* args = n->as_Call()->_tf->domain_sig();
         for (uint i = TypeFunc::Parms, j = 0; i < args->cnt(); i++) {
           if (args->field_at(i)->isa_ptr()) {
             j++;
             if (j == 2) {
               dest = n->in(i);
@@ -577,11 +577,11 @@
       for (; i < others_len; i++) {
         if (others[i].opcode == n->Opcode()) {
           break;
         }
       }
-      uint stop = n->is_Call() ? n->as_Call()->tf()->domain()->cnt() : n->req();
+      uint stop = n->is_Call() ? n->as_Call()->tf()->domain_sig()->cnt() : n->req();
       if (i != others_len) {
         const uint inputs_len = sizeof(others[0].inputs) / sizeof(others[0].inputs[0]);
         for (uint j = 0; j < inputs_len; j++) {
           int pos = others[i].inputs[j].pos;
           if (pos == -1) {
@@ -797,22 +797,21 @@
           }
         }
       }
     } else {
       if (c->is_Call() && c->as_Call()->adr_type() != NULL) {
-        CallProjections projs;
-        c->as_Call()->extract_projections(&projs, true, false);
-        if (projs.fallthrough_memproj != NULL) {
-          if (projs.fallthrough_memproj->adr_type() == TypePtr::BOTTOM) {
-            if (projs.catchall_memproj == NULL) {
-              mem = projs.fallthrough_memproj;
+        CallProjections* projs = c->as_Call()->extract_projections(true, false);
+        if (projs->fallthrough_memproj != NULL) {
+          if (projs->fallthrough_memproj->adr_type() == TypePtr::BOTTOM) {
+            if (projs->catchall_memproj == NULL) {
+              mem = projs->fallthrough_memproj;
             } else {
-              if (phase->is_dominator(projs.fallthrough_catchproj, ctrl)) {
-                mem = projs.fallthrough_memproj;
+              if (phase->is_dominator(projs->fallthrough_catchproj, ctrl)) {
+                mem = projs->fallthrough_memproj;
               } else {
-                assert(phase->is_dominator(projs.catchall_catchproj, ctrl), "one proj must dominate barrier");
-                mem = projs.catchall_memproj;
+                assert(phase->is_dominator(projs->catchall_catchproj, ctrl), "one proj must dominate barrier");
+                mem = projs->catchall_memproj;
               }
             }
           }
         } else {
           Node* proj = c->as_Call()->proj_out(TypeFunc::Memory);
@@ -1050,11 +1049,11 @@
       }
     }
   }
 }
 
-static Node* create_phis_on_call_return(Node* ctrl, Node* c, Node* n, Node* n_clone, const CallProjections& projs, PhaseIdealLoop* phase) {
+static Node* create_phis_on_call_return(Node* ctrl, Node* c, Node* n, Node* n_clone, const CallProjections* projs, PhaseIdealLoop* phase) {
   Node* region = NULL;
   while (c != ctrl) {
     if (c->is_Region()) {
       region = c;
     }
@@ -1062,13 +1061,13 @@
   }
   assert(region != NULL, "");
   Node* phi = new PhiNode(region, n->bottom_type());
   for (uint j = 1; j < region->req(); j++) {
     Node* in = region->in(j);
-    if (phase->is_dominator(projs.fallthrough_catchproj, in)) {
+    if (phase->is_dominator(projs->fallthrough_catchproj, in)) {
       phi->init_req(j, n);
-    } else if (phase->is_dominator(projs.catchall_catchproj, in)) {
+    } else if (phase->is_dominator(projs->catchall_catchproj, in)) {
       phi->init_req(j, n_clone);
     } else {
       phi->init_req(j, create_phis_on_call_return(ctrl, in, n, n_clone, projs, phase));
     }
   }
@@ -1180,19 +1179,17 @@
             stack.pop();
           }
         } while(stack.size() > 0);
         continue;
       }
-      CallProjections projs;
-      call->extract_projections(&projs, false, false);
-
+      CallProjections* projs = call->extract_projections(false, false);
 #ifdef ASSERT
       VectorSet cloned;
 #endif
       Node* lrb_clone = lrb->clone();
-      phase->register_new_node(lrb_clone, projs.catchall_catchproj);
-      phase->set_ctrl(lrb, projs.fallthrough_catchproj);
+      phase->register_new_node(lrb_clone, projs->catchall_catchproj);
+      phase->set_ctrl(lrb, projs->fallthrough_catchproj);
 
       stack.push(lrb, 0);
       clones.push(lrb_clone);
 
       do {
@@ -1210,42 +1207,42 @@
         uint idx = stack.index();
         Node* n_clone = clones.at(clones.size()-1);
         if (idx < n->outcnt()) {
           Node* u = n->raw_out(idx);
           Node* c = phase->ctrl_or_self(u);
-          if (phase->is_dominator(call, c) && phase->is_dominator(c, projs.fallthrough_proj)) {
+          if (phase->is_dominator(call, c) && phase->is_dominator(c, projs->fallthrough_proj)) {
             stack.set_index(idx+1);
             assert(!u->is_CFG(), "");
             stack.push(u, 0);
             assert(!cloned.test_set(u->_idx), "only one clone");
             Node* u_clone = u->clone();
             int nb = u_clone->replace_edge(n, n_clone);
             assert(nb > 0, "should have replaced some uses");
-            phase->register_new_node(u_clone, projs.catchall_catchproj);
+            phase->register_new_node(u_clone, projs->catchall_catchproj);
             clones.push(u_clone);
-            phase->set_ctrl(u, projs.fallthrough_catchproj);
+            phase->set_ctrl(u, projs->fallthrough_catchproj);
           } else {
             bool replaced = false;
             if (u->is_Phi()) {
               for (uint k = 1; k < u->req(); k++) {
                 if (u->in(k) == n) {
-                  if (phase->is_dominator(projs.catchall_catchproj, u->in(0)->in(k))) {
+                  if (phase->is_dominator(projs->catchall_catchproj, u->in(0)->in(k))) {
                     phase->igvn().replace_input_of(u, k, n_clone);
                     replaced = true;
-                  } else if (!phase->is_dominator(projs.fallthrough_catchproj, u->in(0)->in(k))) {
+                  } else if (!phase->is_dominator(projs->fallthrough_catchproj, u->in(0)->in(k))) {
                     phase->igvn().replace_input_of(u, k, create_phis_on_call_return(ctrl, u->in(0)->in(k), n, n_clone, projs, phase));
                     replaced = true;
                   }
                 }
               }
             } else {
-              if (phase->is_dominator(projs.catchall_catchproj, c)) {
+              if (phase->is_dominator(projs->catchall_catchproj, c)) {
                 phase->igvn().rehash_node_delayed(u);
                 int nb = u->replace_edge(n, n_clone);
                 assert(nb > 0, "should have replaced some uses");
                 replaced = true;
-              } else if (!phase->is_dominator(projs.fallthrough_catchproj, c)) {
+              } else if (!phase->is_dominator(projs->fallthrough_catchproj, c)) {
                 if (u->is_If()) {
                   // Can't break If/Bool/Cmp chain
                   assert(n->is_Bool(), "unexpected If shape");
                   assert(stack.node_at(stack.size()-2)->is_Cmp(), "unexpected If shape");
                   assert(n_clone->is_Bool(), "unexpected clone");
@@ -2390,18 +2387,17 @@
 Node* MemoryGraphFixer::get_ctrl(Node* n) const {
   Node* c = _phase->get_ctrl(n);
   if (n->is_Proj() && n->in(0) != NULL && n->in(0)->is_Call()) {
     assert(c == n->in(0), "");
     CallNode* call = c->as_Call();
-    CallProjections projs;
-    call->extract_projections(&projs, true, false);
-    if (projs.catchall_memproj != NULL) {
-      if (projs.fallthrough_memproj == n) {
-        c = projs.fallthrough_catchproj;
+    CallProjections* projs = call->extract_projections(true, false);
+    if (projs->catchall_memproj != NULL) {
+      if (projs->fallthrough_memproj == n) {
+        c = projs->fallthrough_catchproj;
       } else {
-        assert(projs.catchall_memproj == n, "");
-        c = projs.catchall_catchproj;
+        assert(projs->catchall_memproj == n, "");
+        c = projs->catchall_catchproj;
       }
     }
   }
   return c;
 }
diff a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
--- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
+++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp
@@ -1179,11 +1179,11 @@
     monitors_token = _debug_recorder->create_monitor_values(monitors);
 
     throw_exception = jvmci_env()->get_BytecodeFrame_rethrowException(frame) == JNI_TRUE;
   }
 
-  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, return_oop,
+  _debug_recorder->describe_scope(pc_offset, method, NULL, bci, reexecute, throw_exception, false, return_oop, false,
                                   locals_token, expressions_token, monitors_token);
 }
 
 void CodeInstaller::site_Safepoint(CodeBuffer& buffer, jint pc_offset, JVMCIObject site, JVMCI_TRAPS) {
   JVMCIObject debug_info = jvmci_env()->get_site_Infopoint_debugInfo(site);
@@ -1335,10 +1335,12 @@
       case UNVERIFIED_ENTRY:
         _offsets.set_value(CodeOffsets::Entry, pc_offset);
         break;
       case VERIFIED_ENTRY:
         _offsets.set_value(CodeOffsets::Verified_Entry, pc_offset);
+        _offsets.set_value(CodeOffsets::Verified_Inline_Entry, pc_offset);
+        _offsets.set_value(CodeOffsets::Verified_Inline_Entry_RO, pc_offset);
         break;
       case OSR_ENTRY:
         _offsets.set_value(CodeOffsets::OSR_Entry, pc_offset);
         break;
       case EXCEPTION_HANDLER_ENTRY:
diff a/src/hotspot/share/jvmci/jvmciCompiler.cpp b/src/hotspot/share/jvmci/jvmciCompiler.cpp
--- a/src/hotspot/share/jvmci/jvmciCompiler.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompiler.cpp
@@ -67,11 +67,14 @@
   Array<Method*>* objectMethods = SystemDictionary::Object_klass()->methods();
   // Initialize compile queue with a selected set of methods.
   int len = objectMethods->length();
   for (int i = 0; i < len; i++) {
     methodHandle mh(THREAD, objectMethods->at(i));
-    if (!mh->is_native() && !mh->is_static() && !mh->is_initializer()) {
+    if (!mh->is_native() &&
+        !mh->is_static() &&
+        !mh->is_object_constructor() &&
+        !mh->is_class_initializer()) {
       ResourceMark rm;
       int hot_count = 10; // TODO: what's the appropriate value?
       CompileBroker::compile_method(mh, InvocationEntryBci, CompLevel_full_optimization, mh, hot_count, CompileTask::Reason_Bootstrap, THREAD);
     }
   }
diff a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
@@ -1255,11 +1255,11 @@
                     objects->append(sv);
                   }
                 }
               }
               bool realloc_failures = Deoptimization::realloc_objects(thread, fst.current(), fst.register_map(), objects, CHECK_NULL);
-              Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false);
+              Deoptimization::reassign_fields(fst.current(), fst.register_map(), objects, realloc_failures, false, CHECK_NULL);
               realloc_called = true;
 
               GrowableArray<ScopeValue*>* local_values = scope->locals();
               assert(local_values != NULL, "NULL locals");
               typeArrayOop array_oop = oopFactory::new_boolArray(local_values->length(), CHECK_NULL);
@@ -1515,11 +1515,11 @@
     // no objects to materialize
     return;
   }
 
   bool realloc_failures = Deoptimization::realloc_objects(thread, fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, CHECK);
-  Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false);
+  Deoptimization::reassign_fields(fstAfterDeopt.current(), fstAfterDeopt.register_map(), objects, realloc_failures, false, THREAD);
 
   for (int frame_index = 0; frame_index < virtualFrames->length(); frame_index++) {
     compiledVFrame* cvf = virtualFrames->at(frame_index);
 
     GrowableArray<ScopeValue*>* scopeLocals = cvf->scope()->locals();
@@ -1914,11 +1914,11 @@
   iklass->link_class(CHECK_NULL);
 
   GrowableArray<Method*> constructors_array;
   for (int i = 0; i < iklass->methods()->length(); i++) {
     Method* m = iklass->methods()->at(i);
-    if (m->is_initializer() && !m->is_static()) {
+    if (m->is_object_constructor()) {
       constructors_array.append(m);
     }
   }
   JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(constructors_array.length(), JVMCI_CHECK_NULL);
   for (int i = 0; i < constructors_array.length(); i++) {
@@ -1944,11 +1944,11 @@
   iklass->link_class(CHECK_NULL);
 
   GrowableArray<Method*> methods_array;
   for (int i = 0; i < iklass->methods()->length(); i++) {
     Method* m = iklass->methods()->at(i);
-    if (!m->is_initializer() && !m->is_overpass()) {
+    if (!(m->is_object_constructor() || m->is_class_initializer()) && !m->is_overpass()) {
       methods_array.append(m);
     }
   }
   JVMCIObjectArray methods = JVMCIENV->new_ResolvedJavaMethod_array(methods_array.length(), JVMCI_CHECK_NULL);
   for (int i = 0; i < methods_array.length(); i++) {
@@ -2536,15 +2536,15 @@
 
 C2V_VMENTRY_NULL(jobject, asReflectionExecutable, (JNIEnv* env, jobject, jobject jvmci_method))
   requireInHotSpot("asReflectionExecutable", JVMCI_CHECK_NULL);
   methodHandle m(THREAD, JVMCIENV->asMethod(jvmci_method));
   oop executable;
-  if (m->is_initializer()) {
-    if (m->is_static_initializer()) {
+  if (m->is_class_initializer()) {
       JVMCI_THROW_MSG_NULL(IllegalArgumentException,
           "Cannot create java.lang.reflect.Method for class initializer");
-    }
+  }
+  else if (m->is_object_constructor() || m->is_static_init_factory()) {
     executable = Reflection::new_constructor(m, CHECK_NULL);
   } else {
     executable = Reflection::new_method(m, false, CHECK_NULL);
   }
   return JNIHandles::make_local(THREAD, executable);
diff a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp
@@ -157,11 +157,11 @@
                                                                                                                                      \
   nonstatic_field(InstanceKlass,               _fields,                                       Array<u2>*)                            \
   nonstatic_field(InstanceKlass,               _constants,                                    ConstantPool*)                         \
   nonstatic_field(InstanceKlass,               _init_state,                                   u1)                                    \
   nonstatic_field(InstanceKlass,               _init_thread,                                  Thread*)                               \
-  nonstatic_field(InstanceKlass,               _misc_flags,                                   u2)                                    \
+  nonstatic_field(InstanceKlass,               _misc_flags,                                   u4)                                    \
   nonstatic_field(InstanceKlass,               _annotations,                                  Annotations*)                          \
                                                                                                                                      \
   volatile_nonstatic_field(JavaFrameAnchor,    _last_Java_sp,                                 intptr_t*)                             \
   volatile_nonstatic_field(JavaFrameAnchor,    _last_Java_pc,                                 address)                               \
                                                                                                                                      \
@@ -504,10 +504,11 @@
   declare_constant(DataLayout::arg_info_data_tag)                         \
   declare_constant(DataLayout::call_type_data_tag)                        \
   declare_constant(DataLayout::virtual_call_type_data_tag)                \
   declare_constant(DataLayout::parameters_type_data_tag)                  \
   declare_constant(DataLayout::speculative_trap_data_tag)                 \
+  declare_constant(DataLayout::array_load_store_data_tag)                 \
                                                                           \
   declare_constant(Deoptimization::Unpack_deopt)                          \
   declare_constant(Deoptimization::Unpack_exception)                      \
   declare_constant(Deoptimization::Unpack_uncommon_trap)                  \
   declare_constant(Deoptimization::Unpack_reexecute)                      \
diff a/src/hotspot/share/memory/dynamicArchive.cpp b/src/hotspot/share/memory/dynamicArchive.cpp
--- a/src/hotspot/share/memory/dynamicArchive.cpp
+++ b/src/hotspot/share/memory/dynamicArchive.cpp
@@ -259,16 +259,30 @@
 
       return true; // keep recursing until every object is visited exactly once.
     }
 
     virtual void push_special(SpecialRef type, Ref* ref, intptr_t* p) {
-      assert(type == _method_entry_ref, "only special type allowed for now");
+      // TODO:CDS - JDK-8234693 will consolidate this with an almost identical method in metaspaceShared.cpp
+      assert_valid(type);
       address obj = ref->obj();
       address new_obj = _builder->get_new_loc(ref);
       size_t offset = pointer_delta(p, obj,  sizeof(u1));
       intptr_t* new_p = (intptr_t*)(new_obj + offset);
-      assert(*p == *new_p, "must be a copy");
+      switch (type) {
+      case _method_entry_ref:
+        assert(*p == *new_p, "must be a copy");
+        break;
+      case _internal_pointer_ref:
+        {
+          size_t off = pointer_delta(*((address*)p), obj, sizeof(u1));
+          assert(0 <= intx(off) && intx(off) < ref->size() * BytesPerWord, "must point to internal address");
+          *((address*)new_p) = new_obj + off;
+        }
+        break;
+      default:
+        ShouldNotReachHere();
+      }
       ArchivePtrMarker::mark_pointer((address*)new_p);
     }
   };
 
   class EmbeddedRefUpdater: public MetaspaceClosure {
@@ -791,11 +805,11 @@
 }
 
 size_t DynamicArchiveBuilder::estimate_trampoline_size() {
   size_t total = 0;
   size_t each_method_bytes =
-    align_up(SharedRuntime::trampoline_size(), BytesPerWord) +
+    align_up(SharedRuntime::trampoline_size(), BytesPerWord) * 3 +
     align_up(sizeof(AdapterHandlerEntry*), BytesPerWord);
 
   for (int i = 0; i < _klasses->length(); i++) {
     InstanceKlass* ik = _klasses->at(i);
     Array<Method*>* methods = ik->methods();
@@ -814,15 +828,27 @@
   for (int i = 0; i < _klasses->length(); i++) {
     InstanceKlass* ik = _klasses->at(i);
     Array<Method*>* methods = ik->methods();
     for (int j = 0; j < methods->length(); j++) {
       Method* m = methods->at(j);
+
+      // TODO:CDS - JDK-8234693 will consolidate this with Method::unlink()
       address c2i_entry_trampoline = (address)p;
       p += SharedRuntime::trampoline_size();
       assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
       m->set_from_compiled_entry(to_target(c2i_entry_trampoline));
 
+      address c2i_inline_ro_entry_trampoline = (address)p;
+      p += SharedRuntime::trampoline_size();
+      assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
+      m->set_from_compiled_inline_ro_entry(to_target(c2i_inline_ro_entry_trampoline));
+
+      address c2i_inline_entry_trampoline = (address)p;
+      p +=  SharedRuntime::trampoline_size();
+      assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
+      m->set_from_compiled_inline_entry(to_target(c2i_inline_entry_trampoline));
+
       AdapterHandlerEntry** adapter_trampoline =(AdapterHandlerEntry**)p;
       p += sizeof(AdapterHandlerEntry*);
       assert(p >= mc_space->base() && p <= mc_space->top(), "must be");
       *adapter_trampoline = NULL;
       m->set_adapter_trampoline(to_target(adapter_trampoline));
diff a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp
--- a/src/hotspot/share/memory/metaspaceShared.cpp
+++ b/src/hotspot/share/memory/metaspaceShared.cpp
@@ -49,10 +49,12 @@
 #include "memory/metaspaceClosure.hpp"
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/compressedOops.inline.hpp"
+#include "oops/flatArrayKlass.hpp"
+#include "oops/inlineKlass.hpp"
 #include "oops/instanceClassLoaderKlass.hpp"
 #include "oops/instanceMirrorKlass.hpp"
 #include "oops/instanceRefKlass.hpp"
 #include "oops/methodData.hpp"
 #include "oops/objArrayKlass.hpp"
@@ -785,17 +787,19 @@
 //                  into our own tables.
 
 // Currently, the archive contain ONLY the following types of objects that have C++ vtables.
 #define CPP_VTABLE_PATCH_TYPES_DO(f) \
   f(ConstantPool) \
-  f(InstanceKlass) \
+  f(InstanceClassLoaderKlass) \
   f(InstanceClassLoaderKlass) \
   f(InstanceMirrorKlass) \
   f(InstanceRefKlass) \
   f(Method) \
   f(ObjArrayKlass) \
-  f(TypeArrayKlass)
+  f(TypeArrayKlass) \
+  f(FlatArrayKlass) \
+  f(InlineKlass)
 
 class CppVtableInfo {
   intptr_t _vtable_size;
   intptr_t _cloned_vtable[1];
 public:
@@ -1369,16 +1373,30 @@
       RefRelocator refer;
       ref->metaspace_pointers_do_at(&refer, new_loc);
       return true; // recurse into ref.obj()
     }
     virtual void push_special(SpecialRef type, Ref* ref, intptr_t* p) {
-      assert(type == _method_entry_ref, "only special type allowed for now");
+      assert_valid(type);
+
       address obj = ref->obj();
       address new_obj = get_new_loc(ref);
       size_t offset = pointer_delta(p, obj,  sizeof(u1));
       intptr_t* new_p = (intptr_t*)(new_obj + offset);
-      assert(*p == *new_p, "must be a copy");
+      switch (type) {
+      case _method_entry_ref:
+        assert(*p == *new_p, "must be a copy");
+        break;
+      case _internal_pointer_ref:
+        {
+          size_t off = pointer_delta(*((address*)p), obj, sizeof(u1));
+          assert(0 <= intx(off) && intx(off) < ref->size() * BytesPerWord, "must point to internal address");
+          *((address*)new_p) = new_obj + off;
+        }
+        break;
+      default:
+        ShouldNotReachHere();
+      }
       ArchivePtrMarker::mark_pointer((address*)new_p);
     }
   };
 
   // Relocate a reference to point to its shallow copy
diff a/src/hotspot/share/oops/inlineKlass.cpp b/src/hotspot/share/oops/inlineKlass.cpp
--- /dev/null
+++ b/src/hotspot/share/oops/inlineKlass.cpp
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2017, 2020, 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.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "code/codeCache.hpp"
+#include "gc/shared/barrierSet.hpp"
+#include "gc/shared/collectedHeap.inline.hpp"
+#include "gc/shared/gcLocker.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
+#include "memory/metaspaceClosure.hpp"
+#include "memory/metadataFactory.hpp"
+#include "oops/access.hpp"
+#include "oops/compressedOops.inline.hpp"
+#include "oops/fieldStreams.inline.hpp"
+#include "oops/flatArrayKlass.hpp"
+#include "oops/inlineKlass.inline.hpp"
+#include "oops/instanceKlass.inline.hpp"
+#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/objArrayKlass.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/safepointVerifiers.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/signature.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/copy.hpp"
+
+  // Constructor
+InlineKlass::InlineKlass(const ClassFileParser& parser)
+    : InstanceKlass(parser, InstanceKlass::_kind_inline_type, InstanceKlass::ID) {
+  _adr_inlineklass_fixed_block = inlineklass_static_block();
+  // Addresses used for inline type calling convention
+  *((Array<SigEntry>**)adr_extended_sig()) = NULL;
+  *((Array<VMRegPair>**)adr_return_regs()) = NULL;
+  *((address*)adr_pack_handler()) = NULL;
+  *((address*)adr_pack_handler_jobject()) = NULL;
+  *((address*)adr_unpack_handler()) = NULL;
+  assert(pack_handler() == NULL, "pack handler not null");
+  *((int*)adr_default_value_offset()) = 0;
+  *((Klass**)adr_flat_array_klass()) = NULL;
+  set_prototype_header(markWord::always_locked_prototype());
+  assert(is_inline_type_klass(), "invariant");
+}
+
+oop InlineKlass::default_value() {
+  oop val = java_mirror()->obj_field_acquire(default_value_offset());
+  assert(oopDesc::is_oop(val), "Sanity check");
+  assert(val->is_inline_type(), "Sanity check");
+  assert(val->klass() == this, "sanity check");
+  return val;
+}
+
+int InlineKlass::first_field_offset_old() {
+#ifdef ASSERT
+  int first_offset = INT_MAX;
+  for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+    if (fs.offset() < first_offset) first_offset= fs.offset();
+  }
+#endif
+  int base_offset = instanceOopDesc::base_offset_in_bytes();
+  // The first field of line types is aligned on a long boundary
+  base_offset = align_up(base_offset, BytesPerLong);
+  assert(base_offset == first_offset, "inconsistent offsets");
+  return base_offset;
+}
+
+int InlineKlass::raw_value_byte_size() {
+  int heapOopAlignedSize = nonstatic_field_size() << LogBytesPerHeapOop;
+  // If bigger than 64 bits or needs oop alignment, then use jlong aligned
+  // which for values should be jlong aligned, asserts in raw_field_copy otherwise
+  if (heapOopAlignedSize >= longSize || contains_oops()) {
+    return heapOopAlignedSize;
+  }
+  // Small primitives...
+  // If a few small basic type fields, return the actual size, i.e.
+  // 1 byte = 1
+  // 2 byte = 2
+  // 3 byte = 4, because pow2 needed for element stores
+  int first_offset = first_field_offset();
+  int last_offset  = 0; // find the last offset, add basic type size
+  int last_tsz     = 0;
+  for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+    if (fs.access_flags().is_static()) {
+      continue;
+    } else if (fs.offset() > last_offset) {
+      BasicType type = Signature::basic_type(fs.signature());
+      if (is_java_primitive(type)) {
+        last_tsz = type2aelembytes(type);
+      } else if (type == T_INLINE_TYPE) {
+        // Not just primitives. Layout aligns embedded value, so use jlong aligned it is
+        return heapOopAlignedSize;
+      } else {
+        guarantee(0, "Unknown type %d", type);
+      }
+      assert(last_tsz != 0, "Invariant");
+      last_offset = fs.offset();
+    }
+  }
+  // Assumes VT with no fields are meaningless and illegal
+  last_offset += last_tsz;
+  assert(last_offset > first_offset && last_tsz, "Invariant");
+  return 1 << upper_log2(last_offset - first_offset);
+}
+
+instanceOop InlineKlass::allocate_instance(TRAPS) {
+  int size = size_helper();  // Query before forming handle.
+
+  instanceOop oop = (instanceOop)Universe::heap()->obj_allocate(this, size, CHECK_NULL);
+  assert(oop->mark().is_always_locked(), "Unlocked inline type");
+  return oop;
+}
+
+instanceOop InlineKlass::allocate_instance_buffer(TRAPS) {
+  int size = size_helper();  // Query before forming handle.
+
+  instanceOop oop = (instanceOop)Universe::heap()->obj_buffer_allocate(this, size, CHECK_NULL);
+  assert(oop->mark().is_always_locked(), "Unlocked inline type");
+  return oop;
+}
+
+int InlineKlass::nonstatic_oop_count() {
+  int oops = 0;
+  int map_count = nonstatic_oop_map_count();
+  OopMapBlock* block = start_of_nonstatic_oop_maps();
+  OopMapBlock* end = block + map_count;
+  while (block != end) {
+    oops += block->count();
+    block++;
+  }
+  return oops;
+}
+
+oop InlineKlass::read_inlined_field(oop obj, int offset, TRAPS) {
+  oop res = NULL;
+  this->initialize(CHECK_NULL); // will throw an exception if in error state
+  if (is_empty_inline_type()) {
+    res = (instanceOop)default_value();
+  } else {
+    Handle obj_h(THREAD, obj);
+    res = allocate_instance_buffer(CHECK_NULL);
+    inline_copy_payload_to_new_oop(((char*)(oopDesc*)obj_h()) + offset, res);
+  }
+  assert(res != NULL, "Must be set in one of two paths above");
+  return res;
+}
+
+void InlineKlass::write_inlined_field(oop obj, int offset, oop value, TRAPS) {
+  if (value == NULL) {
+    THROW(vmSymbols::java_lang_NullPointerException());
+  }
+  if (!is_empty_inline_type()) {
+    inline_copy_oop_to_payload(value, ((char*)(oopDesc*)obj) + offset);
+  }
+}
+
+// Arrays of...
+
+bool InlineKlass::flatten_array() {
+  if (!UseFlatArray) {
+    return false;
+  }
+  // Too big
+  int elem_bytes = raw_value_byte_size();
+  if ((FlatArrayElementMaxSize >= 0) && (elem_bytes > FlatArrayElementMaxSize)) {
+    return false;
+  }
+  // Too many embedded oops
+  if ((FlatArrayElementMaxOops >= 0) && (nonstatic_oop_count() > FlatArrayElementMaxOops)) {
+    return false;
+  }
+  // Declared atomic but not naturally atomic.
+  if (is_declared_atomic() && !is_naturally_atomic()) {
+    return false;
+  }
+  // VM enforcing InlineArrayAtomicAccess only...
+  if (InlineArrayAtomicAccess && (!is_naturally_atomic())) {
+    return false;
+  }
+  return true;
+}
+
+void InlineKlass::remove_unshareable_info() {
+  InstanceKlass::remove_unshareable_info();
+
+  *((Array<SigEntry>**)adr_extended_sig()) = NULL;
+  *((Array<VMRegPair>**)adr_return_regs()) = NULL;
+  *((address*)adr_pack_handler()) = NULL;
+  *((address*)adr_pack_handler_jobject()) = NULL;
+  *((address*)adr_unpack_handler()) = NULL;
+  assert(pack_handler() == NULL, "pack handler not null");
+  *((Klass**)adr_flat_array_klass()) = NULL;
+}
+
+void InlineKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, PackageEntry* pkg_entry, TRAPS) {
+  InstanceKlass::restore_unshareable_info(loader_data, protection_domain, pkg_entry, CHECK);
+}
+
+
+Klass* InlineKlass::array_klass_impl(bool or_null, int n, TRAPS) {
+  if (flatten_array()) {
+    return flat_array_klass(or_null, n, THREAD);
+  } else {
+    return InstanceKlass::array_klass_impl(or_null, n, THREAD);
+  }
+}
+
+Klass* InlineKlass::array_klass_impl(bool or_null, TRAPS) {
+  return array_klass_impl(or_null, 1, THREAD);
+}
+
+Klass* InlineKlass::flat_array_klass(bool or_null, int rank, TRAPS) {
+  Klass* vak = acquire_flat_array_klass();
+  if (vak == NULL) {
+    if (or_null) return NULL;
+    ResourceMark rm;
+    {
+      // Atomic creation of array_klasses
+      MutexLocker ma(THREAD, MultiArray_lock);
+      if (get_flat_array_klass() == NULL) {
+        vak = allocate_flat_array_klass(CHECK_NULL);
+        Atomic::release_store((Klass**)adr_flat_array_klass(), vak);
+      }
+    }
+  }
+  if (or_null) {
+    return vak->array_klass_or_null(rank);
+  }
+  return vak->array_klass(rank, THREAD);
+}
+
+Klass* InlineKlass::allocate_flat_array_klass(TRAPS) {
+  if (flatten_array()) {
+    return FlatArrayKlass::allocate_klass(this, THREAD);
+  }
+  return ObjArrayKlass::allocate_objArray_klass(class_loader_data(), 1, this, THREAD);
+}
+
+void InlineKlass::array_klasses_do(void f(Klass* k, TRAPS), TRAPS) {
+  InstanceKlass::array_klasses_do(f, THREAD);
+  if (get_flat_array_klass() != NULL)
+    ArrayKlass::cast(get_flat_array_klass())->array_klasses_do(f, THREAD);
+}
+
+void InlineKlass::array_klasses_do(void f(Klass* k)) {
+  InstanceKlass::array_klasses_do(f);
+  if (get_flat_array_klass() != NULL)
+    ArrayKlass::cast(get_flat_array_klass())->array_klasses_do(f);
+}
+
+// Inline type arguments are not passed by reference, instead each
+// field of the inline type is passed as an argument. This helper
+// function collects the inlined field (recursively)
+// in a list. Included with the field's type is
+// the offset of each field in the inline type: i2c and c2i adapters
+// need that to load or store fields. Finally, the list of fields is
+// sorted in order of increasing offsets: the adapters and the
+// compiled code need to agree upon the order of fields.
+//
+// The list of basic types that is returned starts with a T_INLINE_TYPE
+// and ends with an extra T_VOID. T_INLINE_TYPE/T_VOID pairs are used as
+// delimiters. Every entry between the two is a field of the inline
+// type. If there's an embedded inline type in the list, it also starts
+// with a T_INLINE_TYPE and ends with a T_VOID. This is so we can
+// generate a unique fingerprint for the method's adapters and we can
+// generate the list of basic types from the interpreter point of view
+// (inline types passed as reference: iterate on the list until a
+// T_INLINE_TYPE, drop everything until and including the closing
+// T_VOID) or the compiler point of view (each field of the inline
+// types is an argument: drop all T_INLINE_TYPE/T_VOID from the list).
+int InlineKlass::collect_fields(GrowableArray<SigEntry>* sig, int base_off) {
+  int count = 0;
+  SigEntry::add_entry(sig, T_INLINE_TYPE, base_off);
+  for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+    if (fs.access_flags().is_static()) continue;
+    int offset = base_off + fs.offset() - (base_off > 0 ? first_field_offset() : 0);
+    if (fs.is_inlined()) {
+      // Resolve klass of inlined field and recursively collect fields
+      Klass* vk = get_inline_type_field_klass(fs.index());
+      count += InlineKlass::cast(vk)->collect_fields(sig, offset);
+    } else {
+      BasicType bt = Signature::basic_type(fs.signature());
+      if (bt == T_INLINE_TYPE) {
+        bt = T_OBJECT;
+      }
+      SigEntry::add_entry(sig, bt, offset);
+      count += type2size[bt];
+    }
+  }
+  int offset = base_off + size_helper()*HeapWordSize - (base_off > 0 ? first_field_offset() : 0);
+  SigEntry::add_entry(sig, T_VOID, offset);
+  if (base_off == 0) {
+    sig->sort(SigEntry::compare);
+  }
+  assert(sig->at(0)._bt == T_INLINE_TYPE && sig->at(sig->length()-1)._bt == T_VOID, "broken structure");
+  return count;
+}
+
+void InlineKlass::initialize_calling_convention(TRAPS) {
+  // Because the pack and unpack handler addresses need to be loadable from generated code,
+  // they are stored at a fixed offset in the klass metadata. Since inline type klasses do
+  // not have a vtable, the vtable offset is used to store these addresses.
+  if (InlineTypeReturnedAsFields || InlineTypePassFieldsAsArgs) {
+    ResourceMark rm;
+    GrowableArray<SigEntry> sig_vk;
+    int nb_fields = collect_fields(&sig_vk);
+    Array<SigEntry>* extended_sig = MetadataFactory::new_array<SigEntry>(class_loader_data(), sig_vk.length(), CHECK);
+    *((Array<SigEntry>**)adr_extended_sig()) = extended_sig;
+    for (int i = 0; i < sig_vk.length(); i++) {
+      extended_sig->at_put(i, sig_vk.at(i));
+    }
+    if (can_be_returned_as_fields(/* init= */ true)) {
+      nb_fields++;
+      BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, nb_fields);
+      sig_bt[0] = T_METADATA;
+      SigEntry::fill_sig_bt(&sig_vk, sig_bt+1);
+      VMRegPair* regs = NEW_RESOURCE_ARRAY(VMRegPair, nb_fields);
+      int total = SharedRuntime::java_return_convention(sig_bt, regs, nb_fields);
+
+      if (total > 0) {
+        Array<VMRegPair>* return_regs = MetadataFactory::new_array<VMRegPair>(class_loader_data(), nb_fields, CHECK);
+        *((Array<VMRegPair>**)adr_return_regs()) = return_regs;
+        for (int i = 0; i < nb_fields; i++) {
+          return_regs->at_put(i, regs[i]);
+        }
+
+        BufferedInlineTypeBlob* buffered_blob = SharedRuntime::generate_buffered_inline_type_adapter(this);
+        *((address*)adr_pack_handler()) = buffered_blob->pack_fields();
+        *((address*)adr_pack_handler_jobject()) = buffered_blob->pack_fields_jobject();
+        *((address*)adr_unpack_handler()) = buffered_blob->unpack_fields();
+        assert(CodeCache::find_blob(pack_handler()) == buffered_blob, "lost track of blob");
+        assert(can_be_returned_as_fields(), "sanity");
+      }
+    }
+    if (!can_be_returned_as_fields() && !can_be_passed_as_fields()) {
+      MetadataFactory::free_array<SigEntry>(class_loader_data(), extended_sig);
+      assert(return_regs() == NULL, "sanity");
+    }
+  }
+}
+
+void InlineKlass::deallocate_contents(ClassLoaderData* loader_data) {
+  if (extended_sig() != NULL) {
+    MetadataFactory::free_array<SigEntry>(loader_data, extended_sig());
+  }
+  if (return_regs() != NULL) {
+    MetadataFactory::free_array<VMRegPair>(loader_data, return_regs());
+  }
+  cleanup_blobs();
+  InstanceKlass::deallocate_contents(loader_data);
+}
+
+void InlineKlass::cleanup(InlineKlass* ik) {
+  ik->cleanup_blobs();
+}
+
+void InlineKlass::cleanup_blobs() {
+  if (pack_handler() != NULL) {
+    CodeBlob* buffered_blob = CodeCache::find_blob(pack_handler());
+    assert(buffered_blob->is_buffered_inline_type_blob(), "bad blob type");
+    BufferBlob::free((BufferBlob*)buffered_blob);
+    *((address*)adr_pack_handler()) = NULL;
+    *((address*)adr_pack_handler_jobject()) = NULL;
+    *((address*)adr_unpack_handler()) = NULL;
+  }
+}
+
+// Can this inline type be scalarized?
+bool InlineKlass::is_scalarizable() const {
+  return ScalarizeInlineTypes;
+}
+
+// Can this inline type be passed as multiple values?
+bool InlineKlass::can_be_passed_as_fields() const {
+  return InlineTypePassFieldsAsArgs && is_scalarizable() && !is_empty_inline_type();
+}
+
+// Can this inline type be returned as multiple values?
+bool InlineKlass::can_be_returned_as_fields(bool init) const {
+  return InlineTypeReturnedAsFields && is_scalarizable() && !is_empty_inline_type() && (init || return_regs() != NULL);
+}
+
+// Create handles for all oop fields returned in registers that are going to be live across a safepoint
+void InlineKlass::save_oop_fields(const RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
+  Thread* thread = Thread::current();
+  const Array<SigEntry>* sig_vk = extended_sig();
+  const Array<VMRegPair>* regs = return_regs();
+  int j = 1;
+
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_OBJECT || bt == T_ARRAY) {
+      VMRegPair pair = regs->at(j);
+      address loc = reg_map.location(pair.first());
+      oop v = *(oop*)loc;
+      assert(v == NULL || oopDesc::is_oop(v), "not an oop?");
+      assert(Universe::heap()->is_in_or_null(v), "must be heap pointer");
+      handles.push(Handle(thread, v));
+    }
+    if (bt == T_INLINE_TYPE) {
+      continue;
+    }
+    if (bt == T_VOID &&
+        sig_vk->at(i-1)._bt != T_LONG &&
+        sig_vk->at(i-1)._bt != T_DOUBLE) {
+      continue;
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+}
+
+// Update oop fields in registers from handles after a safepoint
+void InlineKlass::restore_oop_results(RegisterMap& reg_map, GrowableArray<Handle>& handles) const {
+  assert(InlineTypeReturnedAsFields, "inconsistent");
+  const Array<SigEntry>* sig_vk = extended_sig();
+  const Array<VMRegPair>* regs = return_regs();
+  assert(regs != NULL, "inconsistent");
+
+  int j = 1;
+  for (int i = 0, k = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_OBJECT || bt == T_ARRAY) {
+      VMRegPair pair = regs->at(j);
+      address loc = reg_map.location(pair.first());
+      *(oop*)loc = handles.at(k++)();
+    }
+    if (bt == T_INLINE_TYPE) {
+      continue;
+    }
+    if (bt == T_VOID &&
+        sig_vk->at(i-1)._bt != T_LONG &&
+        sig_vk->at(i-1)._bt != T_DOUBLE) {
+      continue;
+    }
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+}
+
+// Fields are in registers. Create an instance of the inline type and
+// initialize it with the values of the fields.
+oop InlineKlass::realloc_result(const RegisterMap& reg_map, const GrowableArray<Handle>& handles, TRAPS) {
+  oop new_vt = allocate_instance(CHECK_NULL);
+  const Array<SigEntry>* sig_vk = extended_sig();
+  const Array<VMRegPair>* regs = return_regs();
+
+  int j = 1;
+  int k = 0;
+  for (int i = 0; i < sig_vk->length(); i++) {
+    BasicType bt = sig_vk->at(i)._bt;
+    if (bt == T_INLINE_TYPE) {
+      continue;
+    }
+    if (bt == T_VOID) {
+      if (sig_vk->at(i-1)._bt == T_LONG ||
+          sig_vk->at(i-1)._bt == T_DOUBLE) {
+        j++;
+      }
+      continue;
+    }
+    int off = sig_vk->at(i)._offset;
+    assert(off > 0, "offset in object should be positive");
+    VMRegPair pair = regs->at(j);
+    address loc = reg_map.location(pair.first());
+    switch(bt) {
+    case T_BOOLEAN: {
+      new_vt->bool_field_put(off, *(jboolean*)loc);
+      break;
+    }
+    case T_CHAR: {
+      new_vt->char_field_put(off, *(jchar*)loc);
+      break;
+    }
+    case T_BYTE: {
+      new_vt->byte_field_put(off, *(jbyte*)loc);
+      break;
+    }
+    case T_SHORT: {
+      new_vt->short_field_put(off, *(jshort*)loc);
+      break;
+    }
+    case T_INT: {
+      new_vt->int_field_put(off, *(jint*)loc);
+      break;
+    }
+    case T_LONG: {
+#ifdef _LP64
+      new_vt->double_field_put(off,  *(jdouble*)loc);
+#else
+      Unimplemented();
+#endif
+      break;
+    }
+    case T_OBJECT:
+    case T_ARRAY: {
+      Handle handle = handles.at(k++);
+      new_vt->obj_field_put(off, handle());
+      break;
+    }
+    case T_FLOAT: {
+      new_vt->float_field_put(off,  *(jfloat*)loc);
+      break;
+    }
+    case T_DOUBLE: {
+      new_vt->double_field_put(off, *(jdouble*)loc);
+      break;
+    }
+    default:
+      ShouldNotReachHere();
+    }
+    *(intptr_t*)loc = 0xDEAD;
+    j++;
+  }
+  assert(j == regs->length(), "missed a field?");
+  assert(k == handles.length(), "missed an oop?");
+  return new_vt;
+}
+
+// Check the return register for an InlineKlass oop
+InlineKlass* InlineKlass::returned_inline_klass(const RegisterMap& map) {
+  BasicType bt = T_METADATA;
+  VMRegPair pair;
+  int nb = SharedRuntime::java_return_convention(&bt, &pair, 1);
+  assert(nb == 1, "broken");
+
+  address loc = map.location(pair.first());
+  intptr_t ptr = *(intptr_t*)loc;
+  if (is_set_nth_bit(ptr, 0)) {
+    // Oop is tagged, must be an InlineKlass oop
+    clear_nth_bit(ptr, 0);
+    assert(Metaspace::contains((void*)ptr), "should be klass");
+    InlineKlass* vk = (InlineKlass*)ptr;
+    assert(vk->can_be_returned_as_fields(), "must be able to return as fields");
+    return vk;
+  }
+#ifdef ASSERT
+  // Oop is not tagged, must be a valid oop
+  if (VerifyOops) {
+    oopDesc::verify(oop((HeapWord*)ptr));
+  }
+#endif
+  return NULL;
+}
+
+void InlineKlass::verify_on(outputStream* st) {
+  InstanceKlass::verify_on(st);
+  guarantee(prototype_header().is_always_locked(), "Prototype header is not always locked");
+}
+
+void InlineKlass::oop_verify_on(oop obj, outputStream* st) {
+  InstanceKlass::oop_verify_on(obj, st);
+  guarantee(obj->mark().is_always_locked(), "Header is not always locked");
+}
+
+void InlineKlass::metaspace_pointers_do(MetaspaceClosure* it) {
+  InstanceKlass::metaspace_pointers_do(it);
+
+  InlineKlass* this_ptr = this;
+  it->push_internal_pointer(&this_ptr, (intptr_t*)&_adr_inlineklass_fixed_block);
+}
diff a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -63,10 +63,11 @@
 #include "oops/klass.inline.hpp"
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/recordComponent.hpp"
 #include "oops/symbol.hpp"
+#include "oops/inlineKlass.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "prims/methodComparator.hpp"
 #include "runtime/atomic.hpp"
@@ -153,10 +154,12 @@
     }
   }
   return false;
 }
 
+bool InstanceKlass::field_is_inline_type(int index) const { return Signature::basic_type(field(index)->signature(constants())) == T_INLINE_TYPE; }
+
 // private: called to verify that k is a static member of this nest.
 // We know that k is an instance class in the same package and hence the
 // same classloader.
 bool InstanceKlass::has_nest_member(InstanceKlass* k, TRAPS) const {
   assert(!is_hidden(), "unexpected hidden class");
@@ -471,11 +474,13 @@
   const int size = InstanceKlass::size(parser.vtable_size(),
                                        parser.itable_size(),
                                        nonstatic_oop_map_size(parser.total_oop_map_count()),
                                        parser.is_interface(),
                                        parser.is_unsafe_anonymous(),
-                                       should_store_fingerprint(is_hidden_or_anonymous));
+                                       should_store_fingerprint(is_hidden_or_anonymous),
+                                       parser.has_inline_fields() ? parser.java_fields_count() : 0,
+                                       parser.is_inline_type());
 
   const Symbol* const class_name = parser.class_name();
   assert(class_name != NULL, "invariant");
   ClassLoaderData* loader_data = parser.loader_data();
   assert(loader_data != NULL, "invariant");
@@ -485,14 +490,16 @@
   // Allocation
   if (REF_NONE == parser.reference_type()) {
     if (class_name == vmSymbols::java_lang_Class()) {
       // mirror
       ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
-    }
-    else if (is_class_loader(class_name, parser)) {
+    } else if (is_class_loader(class_name, parser)) {
       // class loader
       ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
+    } else if (parser.is_inline_type()) {
+      // inline type
+      ik = new (loader_data, size, THREAD) InlineKlass(parser);
     } else {
       // normal
       ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_kind_other);
     }
   } else {
@@ -504,13 +511,43 @@
   // class count.  Can get OOM here.
   if (HAS_PENDING_EXCEPTION) {
     return NULL;
   }
 
+#ifdef ASSERT
+  assert(ik->size() == size, "");
+  ik->bounds_check((address) ik->start_of_vtable(), false, size);
+  ik->bounds_check((address) ik->start_of_itable(), false, size);
+  ik->bounds_check((address) ik->end_of_itable(), true, size);
+  ik->bounds_check((address) ik->end_of_nonstatic_oop_maps(), true, size);
+#endif //ASSERT
   return ik;
 }
 
+#ifndef PRODUCT
+bool InstanceKlass::bounds_check(address addr, bool edge_ok, intptr_t size_in_bytes) const {
+  const char* bad = NULL;
+  address end = NULL;
+  if (addr < (address)this) {
+    bad = "before";
+  } else if (addr == (address)this) {
+    if (edge_ok)  return true;
+    bad = "just before";
+  } else if (addr == (end = (address)this + sizeof(intptr_t) * (size_in_bytes < 0 ? size() : size_in_bytes))) {
+    if (edge_ok)  return true;
+    bad = "just after";
+  } else if (addr > end) {
+    bad = "after";
+  } else {
+    return true;
+  }
+  tty->print_cr("%s object bounds: " INTPTR_FORMAT " [" INTPTR_FORMAT ".." INTPTR_FORMAT "]",
+      bad, (intptr_t)addr, (intptr_t)this, (intptr_t)end);
+  Verbose = WizardMode = true; this->print(); //@@
+  return false;
+}
+#endif //PRODUCT
 
 // copy method ordering from resource area to Metaspace
 void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
   if (m != NULL) {
     // allocate a new array and copy contents (memcpy?)
@@ -541,29 +578,38 @@
   _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
   _itable_len(parser.itable_size()),
   _nest_host_index(0),
   _init_state(allocated),
   _reference_type(parser.reference_type()),
-  _init_thread(NULL)
+  _init_thread(NULL),
+  _inline_type_field_klasses(NULL),
+  _adr_inlineklass_fixed_block(NULL)
 {
   set_vtable_length(parser.vtable_size());
   set_kind(kind);
   set_access_flags(parser.access_flags());
   if (parser.is_hidden()) set_is_hidden();
   set_is_unsafe_anonymous(parser.is_unsafe_anonymous());
   set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
                                                     false));
+    if (parser.has_inline_fields()) {
+      set_has_inline_type_fields();
+    }
+    _java_fields_count = parser.java_fields_count();
 
-  assert(NULL == _methods, "underlying memory not zeroed?");
-  assert(is_instance_klass(), "is layout incorrect?");
-  assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
+    assert(NULL == _methods, "underlying memory not zeroed?");
+    assert(is_instance_klass(), "is layout incorrect?");
+    assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
 
   // Set biased locking bit for all instances of this class; it will be
   // cleared if revocation occurs too often for this type
   if (UseBiasedLocking && BiasedLocking::enabled()) {
     set_prototype_header(markWord::biased_locking_prototype());
   }
+  if (has_inline_type_fields()) {
+    _inline_type_field_klasses = (const Klass**) adr_inline_type_field_klasses();
+  }
 }
 
 void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
                                        Array<Method*>* methods) {
   if (methods != NULL && methods != Universe::the_empty_method_array() &&
@@ -589,18 +635,20 @@
   Array<InstanceKlass*>* ti = transitive_interfaces;
   if (ti != Universe::the_empty_instance_klass_array() && ti != local_interfaces) {
     // check that the interfaces don't come from super class
     Array<InstanceKlass*>* sti = (super_klass == NULL) ? NULL :
                     InstanceKlass::cast(super_klass)->transitive_interfaces();
-    if (ti != sti && ti != NULL && !ti->is_shared()) {
+    if (ti != sti && ti != NULL && !ti->is_shared() &&
+        ti != Universe::the_single_IdentityObject_klass_array()) {
       MetadataFactory::free_array<InstanceKlass*>(loader_data, ti);
     }
   }
 
   // local interfaces can be empty
   if (local_interfaces != Universe::the_empty_instance_klass_array() &&
-      local_interfaces != NULL && !local_interfaces->is_shared()) {
+      local_interfaces != NULL && !local_interfaces->is_shared() &&
+      local_interfaces != Universe::the_single_IdentityObject_klass_array()) {
     MetadataFactory::free_array<InstanceKlass*>(loader_data, local_interfaces);
   }
 }
 
 void InstanceKlass::deallocate_record_components(ClassLoaderData* loader_data,
@@ -924,10 +972,66 @@
   for (int index = 0; index < num_interfaces; index++) {
     InstanceKlass* interk = interfaces->at(index);
     interk->link_class_impl(CHECK_false);
   }
 
+
+  // If a class declares a method that uses an inline class as an argument
+  // type or return inline type, this inline class must be loaded during the
+  // linking of this class because size and properties of the inline class
+  // must be known in order to be able to perform inline type optimizations.
+  // The implementation below is an approximation of this rule, the code
+  // iterates over all methods of the current class (including overridden
+  // methods), not only the methods declared by this class. This
+  // approximation makes the code simpler, and doesn't change the semantic
+  // because classes declaring methods overridden by the current class are
+  // linked (and have performed their own pre-loading) before the linking
+  // of the current class.
+
+
+  // Note:
+  // Inline class types are loaded during
+  // the loading phase (see ClassFileParser::post_process_parsed_stream()).
+  // Inline class types used as element types for array creation
+  // are not pre-loaded. Their loading is triggered by either anewarray
+  // or multianewarray bytecodes.
+
+  // Could it be possible to do the following processing only if the
+  // class uses inline types?
+  {
+    ResourceMark rm(THREAD);
+    for (int i = 0; i < methods()->length(); i++) {
+      Method* m = methods()->at(i);
+      for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) {
+        if (ss.is_reference()) {
+          if (ss.is_array()) {
+            ss.skip_array_prefix();
+          }
+          if (ss.type() == T_INLINE_TYPE) {
+            Symbol* symb = ss.as_symbol();
+
+            oop loader = class_loader();
+            oop protection_domain = this->protection_domain();
+            Klass* klass = SystemDictionary::resolve_or_fail(symb,
+                                                             Handle(THREAD, loader), Handle(THREAD, protection_domain), true,
+                                                             CHECK_false);
+            if (klass == NULL) {
+              THROW_(vmSymbols::java_lang_LinkageError(), false);
+            }
+            if (!klass->is_inline_klass()) {
+              Exceptions::fthrow(
+                THREAD_AND_LOCATION,
+                vmSymbols::java_lang_IncompatibleClassChangeError(),
+                "class %s is not an inline type",
+                klass->external_name());
+            }
+          }
+        }
+      }
+    }
+  }
+
   // in case the class is linked in the process of linking its superclasses
   if (is_linked()) {
     return true;
   }
 
@@ -995,10 +1099,11 @@
 #ifdef ASSERT
       vtable().verify(tty, true);
       // In case itable verification is ever added.
       // itable().verify(tty, true);
 #endif
+
       set_init_state(linked);
       if (JvmtiExport::should_post_class_prepare()) {
         Thread *thread = THREAD;
         assert(thread->is_Java_thread(), "thread->is_Java_thread()");
         JvmtiExport::post_class_prepare((JavaThread *) thread, this);
@@ -1148,15 +1253,44 @@
       DTRACE_CLASSINIT_PROBE_WAIT(super__failed, -1, wait);
       THROW_OOP(e());
     }
   }
 
+  // Step 8
+  // Initialize classes of inline fields
+  {
+    for (AllFieldStream fs(this); !fs.done(); fs.next()) {
+      if (Signature::basic_type(fs.signature()) == T_INLINE_TYPE) {
+        Klass* klass = get_inline_type_field_klass_or_null(fs.index());
+        if (fs.access_flags().is_static() && klass == NULL) {
+          klass = SystemDictionary::resolve_or_fail(field_signature(fs.index())->fundamental_name(THREAD),
+              Handle(THREAD, class_loader()),
+              Handle(THREAD, protection_domain()),
+              true, CHECK);
+          if (klass == NULL) {
+            THROW(vmSymbols::java_lang_NoClassDefFoundError());
+          }
+          if (!klass->is_inline_klass()) {
+            THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
+          }
+          set_inline_type_field_klass(fs.index(), klass);
+        }
+        InstanceKlass::cast(klass)->initialize(CHECK);
+        if (fs.access_flags().is_static()) {
+          if (java_mirror()->obj_field(fs.offset()) == NULL) {
+            java_mirror()->obj_field_put(fs.offset(), InlineKlass::cast(klass)->default_value());
+          }
+        }
+      }
+    }
+  }
+
 
   // Look for aot compiled methods for this klass, including class initializer.
   AOTLoader::load_for_klass(this, THREAD);
 
-  // Step 8
+  // Step 9
   {
     DTRACE_CLASSINIT_PROBE_WAIT(clinit, -1, wait);
     if (class_initializer() != NULL) {
       // Timer includes any side effects of class initialization (resolution,
       // etc), but not recursive entry into call_class_initializer().
@@ -1174,19 +1308,19 @@
       }
       call_class_initializer(THREAD);
     }
   }
 
-  // Step 9
+  // Step 10
   if (!HAS_PENDING_EXCEPTION) {
     set_initialization_state_and_notify(fully_initialized, CHECK);
     {
       debug_only(vtable().verify(tty, true);)
     }
   }
   else {
-    // Step 10 and 11
+    // Step 11 and 12
     Handle e(THREAD, PENDING_EXCEPTION);
     CLEAR_PENDING_EXCEPTION;
     // JVMTI has already reported the pending exception
     // JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
     JvmtiExport::clear_detected_exception(jt);
@@ -1470,11 +1604,11 @@
 static int call_class_initializer_counter = 0;   // for debugging
 
 Method* InstanceKlass::class_initializer() const {
   Method* clinit = find_method(
       vmSymbols::class_initializer_name(), vmSymbols::void_method_signature());
-  if (clinit != NULL && clinit->has_valid_initializer_flags()) {
+  if (clinit != NULL && clinit->is_class_initializer()) {
     return clinit;
   }
   return NULL;
 }
 
@@ -1508,11 +1642,11 @@
   InterpreterOopMap* entry_for) {
   // Lazily create the _oop_map_cache at first request
   // Lock-free access requires load_acquire.
   OopMapCache* oop_map_cache = Atomic::load_acquire(&_oop_map_cache);
   if (oop_map_cache == NULL) {
-    MutexLocker x(OopMapCacheAlloc_lock);
+    MutexLocker x(OopMapCacheAlloc_lock,  Mutex::_no_safepoint_check_flag);
     // Check if _oop_map_cache was allocated while we were waiting for this lock
     if ((oop_map_cache = _oop_map_cache) == NULL) {
       oop_map_cache = new OopMapCache();
       // Ensure _oop_map_cache is stable, since it is examined without a lock
       Atomic::release_store(&_oop_map_cache, oop_map_cache);
@@ -1520,15 +1654,10 @@
   }
   // _oop_map_cache is constant after init; lookup below does its own locking.
   oop_map_cache->lookup(method, bci, entry_for);
 }
 
-bool InstanceKlass::contains_field_offset(int offset) {
-  fieldDescriptor fd;
-  return find_field_from_offset(offset, false, &fd);
-}
-
 bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
   for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
     Symbol* f_name = fs.name();
     Symbol* f_sig  = fs.signature();
     if (f_name == name && f_sig == sig) {
@@ -1595,10 +1724,19 @@
   }
   // 4) otherwise field lookup fails
   return NULL;
 }
 
+bool InstanceKlass::contains_field_offset(int offset) {
+  if (this->is_inline_klass()) {
+    InlineKlass* vk = InlineKlass::cast(this);
+    return offset >= vk->first_field_offset() && offset < (vk->first_field_offset() + vk->get_exact_size_in_bytes());
+  } else {
+    fieldDescriptor fd;
+    return find_field_from_offset(offset, false, &fd);
+  }
+}
 
 bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
   for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
     if (fs.offset() == offset) {
       fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
@@ -1979,10 +2117,13 @@
                                                                         find_static,
                                                                         private_mode);
     if (method != NULL) {
       return method;
     }
+    if (name == vmSymbols::object_initializer_name()) {
+      break;  // <init> is never inherited, not even as a static factory
+    }
     klass = klass->super();
     overpass_local_mode = skip_overpass;   // Always ignore overpass methods in superclasses
   }
   return NULL;
 }
@@ -2487,10 +2628,16 @@
   }
 
   it->push(&_nest_members);
   it->push(&_permitted_subclasses);
   it->push(&_record_components);
+
+  if (has_inline_type_fields()) {
+    for (int i = 0; i < java_fields_count(); i++) {
+      it->push(&((Klass**)adr_inline_type_field_klasses())[i]);
+    }
+  }
 }
 
 void InstanceKlass::remove_unshareable_info() {
   Klass::remove_unshareable_info();
 
@@ -2522,10 +2669,18 @@
   // do array classes also.
   if (array_klasses() != NULL) {
     array_klasses()->remove_unshareable_info();
   }
 
+  if (has_inline_type_fields()) {
+    for (AllFieldStream fs(fields(), constants()); !fs.done(); fs.next()) {
+      if (Signature::basic_type(fs.signature()) == T_INLINE_TYPE) {
+        reset_inline_type_field_klass(fs.index());
+      }
+    }
+  }
+
   // These are not allocated from metaspace. They are safe to set to NULL.
   _source_debug_extension = NULL;
   _dep_context = NULL;
   _osr_nmethods_head = NULL;
 #if INCLUDE_JVMTI
@@ -2561,10 +2716,14 @@
   // sure the current state is <loaded.
   assert(!is_loaded(), "invalid init state");
   set_package(loader_data, pkg_entry, CHECK);
   Klass::restore_unshareable_info(loader_data, protection_domain, CHECK);
 
+  if (is_inline_klass()) {
+    InlineKlass::cast(this)->initialize_calling_convention(CHECK);
+  }
+
   Array<Method*>* methods = this->methods();
   int num_methods = methods->length();
   for (int index = 0; index < num_methods; ++index) {
     methods->at(index)->restore_unshareable_info(CHECK);
   }
@@ -2586,11 +2745,11 @@
     // --> see ArrayKlass::complete_create_array_klass()
     array_klasses()->restore_unshareable_info(ClassLoaderData::the_null_class_loader_data(), Handle(), CHECK);
   }
 
   // Initialize current biased locking state.
-  if (UseBiasedLocking && BiasedLocking::enabled()) {
+  if (UseBiasedLocking && BiasedLocking::enabled() && !is_inline_klass()) {
     set_prototype_header(markWord::biased_locking_prototype());
   }
 }
 
 void InstanceKlass::set_shared_class_loader_type(s2 loader_type) {
@@ -2751,13 +2910,13 @@
   const char* src = (const char*) (name()->as_C_string());
   const int src_length = (int)strlen(src);
 
   char* dest = NEW_RESOURCE_ARRAY(char, src_length + hash_len + 3);
 
-  // Add L as type indicator
+  // Add L or Q as type indicator
   int dest_index = 0;
-  dest[dest_index++] = JVM_SIGNATURE_CLASS;
+  dest[dest_index++] = is_inline_klass() ? JVM_SIGNATURE_INLINE_TYPE : JVM_SIGNATURE_CLASS;
 
   // Add the actual class name
   for (int src_index = 0; src_index < src_length; ) {
     dest[dest_index++] = src[src_index++];
   }
@@ -3313,33 +3472,69 @@
 
 static const char* state_names[] = {
   "allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
 };
 
-static void print_vtable(intptr_t* start, int len, outputStream* st) {
+static void print_vtable(address self, intptr_t* start, int len, outputStream* st) {
+  ResourceMark rm;
+  int* forward_refs = NEW_RESOURCE_ARRAY(int, len);
+  for (int i = 0; i < len; i++)  forward_refs[i] = 0;
   for (int i = 0; i < len; i++) {
     intptr_t e = start[i];
     st->print("%d : " INTPTR_FORMAT, i, e);
+    if (forward_refs[i] != 0) {
+      int from = forward_refs[i];
+      int off = (int) start[from];
+      st->print(" (offset %d <= [%d])", off, from);
+    }
     if (MetaspaceObj::is_valid((Metadata*)e)) {
       st->print(" ");
       ((Metadata*)e)->print_value_on(st);
+    } else if (self != NULL && e > 0 && e < 0x10000) {
+      address location = self + e;
+      int index = (int)((intptr_t*)location - start);
+      st->print(" (offset %d => [%d])", (int)e, index);
+      if (index >= 0 && index < len)
+        forward_refs[index] = i;
     }
     st->cr();
   }
 }
 
 static void print_vtable(vtableEntry* start, int len, outputStream* st) {
-  return print_vtable(reinterpret_cast<intptr_t*>(start), len, st);
+  return print_vtable(NULL, reinterpret_cast<intptr_t*>(start), len, st);
+}
+
+template<typename T>
+ static void print_array_on(outputStream* st, Array<T>* array) {
+   if (array == NULL) { st->print_cr("NULL"); return; }
+   array->print_value_on(st); st->cr();
+   if (Verbose || WizardMode) {
+     for (int i = 0; i < array->length(); i++) {
+       st->print("%d : ", i); array->at(i)->print_value_on(st); st->cr();
+     }
+   }
+ }
+
+static void print_array_on(outputStream* st, Array<int>* array) {
+  if (array == NULL) { st->print_cr("NULL"); return; }
+  array->print_value_on(st); st->cr();
+  if (Verbose || WizardMode) {
+    for (int i = 0; i < array->length(); i++) {
+      st->print("%d : %d", i, array->at(i)); st->cr();
+    }
+  }
 }
 
 void InstanceKlass::print_on(outputStream* st) const {
   assert(is_klass(), "must be klass");
   Klass::print_on(st);
 
   st->print(BULLET"instance size:     %d", size_helper());                        st->cr();
   st->print(BULLET"klass size:        %d", size());                               st->cr();
   st->print(BULLET"access:            "); access_flags().print_on(st);            st->cr();
+  st->print(BULLET"misc flags:        0x%x", _misc_flags);                        st->cr();
   st->print(BULLET"state:             "); st->print_cr("%s", state_names[_init_state]);
   st->print(BULLET"name:              "); name()->print_value_on(st);             st->cr();
   st->print(BULLET"super:             "); Metadata::print_value_on_maybe_null(st, super()); st->cr();
   st->print(BULLET"sub:               ");
   Klass* sub = subklass();
@@ -3362,30 +3557,18 @@
       st->cr();
     }
   }
 
   st->print(BULLET"arrays:            "); Metadata::print_value_on_maybe_null(st, array_klasses()); st->cr();
-  st->print(BULLET"methods:           "); methods()->print_value_on(st);                  st->cr();
-  if (Verbose || WizardMode) {
-    Array<Method*>* method_array = methods();
-    for (int i = 0; i < method_array->length(); i++) {
-      st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-    }
-  }
-  st->print(BULLET"method ordering:   "); method_ordering()->print_value_on(st);      st->cr();
-  st->print(BULLET"default_methods:   "); default_methods()->print_value_on(st);      st->cr();
-  if (Verbose && default_methods() != NULL) {
-    Array<Method*>* method_array = default_methods();
-    for (int i = 0; i < method_array->length(); i++) {
-      st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
-    }
-  }
+  st->print(BULLET"methods:           "); print_array_on(st, methods());
+  st->print(BULLET"method ordering:   "); print_array_on(st, method_ordering());
+  st->print(BULLET"default_methods:   "); print_array_on(st, default_methods());
   if (default_vtable_indices() != NULL) {
-    st->print(BULLET"default vtable indices:   "); default_vtable_indices()->print_value_on(st);       st->cr();
+    st->print(BULLET"default vtable indices:   "); print_array_on(st, default_vtable_indices());
   }
-  st->print(BULLET"local interfaces:  "); local_interfaces()->print_value_on(st);      st->cr();
-  st->print(BULLET"trans. interfaces: "); transitive_interfaces()->print_value_on(st); st->cr();
+  st->print(BULLET"local interfaces:  "); print_array_on(st, local_interfaces());
+  st->print(BULLET"trans. interfaces: "); print_array_on(st, transitive_interfaces());
   st->print(BULLET"constants:         "); constants()->print_value_on(st);         st->cr();
   if (class_loader_data() != NULL) {
     st->print(BULLET"class loader data:  ");
     class_loader_data()->print_value_on(st);
     st->cr();
@@ -3438,11 +3621,11 @@
     st->print_cr(BULLET"java mirror:       NULL");
   }
   st->print(BULLET"vtable length      %d  (start addr: " INTPTR_FORMAT ")", vtable_length(), p2i(start_of_vtable())); st->cr();
   if (vtable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_vtable(), vtable_length(), st);
   st->print(BULLET"itable length      %d (start addr: " INTPTR_FORMAT ")", itable_length(), p2i(start_of_itable())); st->cr();
-  if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(start_of_itable(), itable_length(), st);
+  if (itable_length() > 0 && (Verbose || WizardMode))  print_vtable(NULL, start_of_itable(), itable_length(), st);
   st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
   FieldPrinter print_static_field(st);
   ((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
   st->print_cr(BULLET"---- non-static fields (%d words):", nonstatic_field_size());
   FieldPrinter print_nonstatic_field(st);
@@ -4174,5 +4357,10 @@
 
 unsigned char * InstanceKlass::get_cached_class_file_bytes() {
   return VM_RedefineClasses::get_cached_class_file_bytes(_cached_class_file);
 }
 #endif
+
+#define THROW_DVT_ERROR(s) \
+  Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IncompatibleClassChangeError(), \
+      "ValueCapableClass class '%s' %s", external_name(),(s)); \
+      return
diff a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp
--- a/src/hotspot/share/oops/symbol.cpp
+++ b/src/hotspot/share/oops/symbol.cpp
@@ -104,10 +104,85 @@
   assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
   _hash_and_refcount =  pack_hash_and_refcount(extract_hash(_hash_and_refcount), PERM_REFCOUNT);
 }
 #endif
 
+bool Symbol::is_Q_signature() const {
+  int len = utf8_length();
+  return len > 2 && char_at(0) == JVM_SIGNATURE_INLINE_TYPE && char_at(len - 1) == JVM_SIGNATURE_ENDCLASS;
+}
+
+bool Symbol::is_Q_array_signature() const {
+  int l = utf8_length();
+  if (l < 2 || char_at(0) != JVM_SIGNATURE_ARRAY || char_at(l - 1) != JVM_SIGNATURE_ENDCLASS) {
+    return false;
+  }
+  for (int i = 1; i < (l - 2); i++) {
+    char c = char_at(i);
+    if (c == JVM_SIGNATURE_INLINE_TYPE) {
+      return true;
+    }
+    if (c != JVM_SIGNATURE_ARRAY) {
+      return false;
+    }
+  }
+  return false;
+}
+
+bool Symbol::is_Q_method_signature() const {
+  assert(SignatureVerifier::is_valid_method_signature(this), "must be");
+  int len = utf8_length();
+  if (len > 4 && char_at(0) == JVM_SIGNATURE_FUNC) {
+    for (int i=1; i<len-3; i++) { // Must end with ")Qx;", where x is at least one character or more.
+      if (char_at(i) == JVM_SIGNATURE_ENDFUNC && char_at(i+1) == JVM_SIGNATURE_INLINE_TYPE) {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+Symbol* Symbol::fundamental_name(TRAPS) {
+  if ((char_at(0) == JVM_SIGNATURE_INLINE_TYPE || char_at(0) == JVM_SIGNATURE_CLASS) && ends_with(JVM_SIGNATURE_ENDCLASS)) {
+    return SymbolTable::new_symbol(this, 1, utf8_length() - 1);
+  } else {
+    // reference count is incremented to be consistent with the behavior with
+    // the SymbolTable::new_symbol() call above
+    this->increment_refcount();
+    return this;
+  }
+}
+
+bool Symbol::is_same_fundamental_type(Symbol* s) const {
+  if (this == s) return true;
+  if (utf8_length() < 3) return false;
+  int offset1, offset2, len;
+  if (ends_with(JVM_SIGNATURE_ENDCLASS)) {
+    if (char_at(0) != JVM_SIGNATURE_INLINE_TYPE && char_at(0) != JVM_SIGNATURE_CLASS) return false;
+    offset1 = 1;
+    len = utf8_length() - 2;
+  } else {
+    offset1 = 0;
+    len = utf8_length();
+  }
+  if (ends_with(JVM_SIGNATURE_ENDCLASS)) {
+    if (s->char_at(0) != JVM_SIGNATURE_INLINE_TYPE && s->char_at(0) != JVM_SIGNATURE_CLASS) return false;
+    offset2 = 1;
+  } else {
+    offset2 = 0;
+  }
+  if ((offset2 + len) > s->utf8_length()) return false;
+  if ((utf8_length() - offset1 * 2) != (s->utf8_length() - offset2 * 2))
+    return false;
+  int l = len;
+  while (l-- > 0) {
+    if (char_at(offset1 + l) != s->char_at(offset2 + l))
+      return false;
+  }
+  return true;
+}
+
 // ------------------------------------------------------------------
 // Symbol::index_of
 //
 // Finds if the given string is a substring of this symbol's utf8 bytes.
 // Return -1 on failure.  Otherwise return the first index where str occurs.
@@ -408,7 +483,19 @@
 
   jbyte* bytes = (jbyte*) s->bytes();
   return os::is_readable_range(bytes, bytes + len);
 }
 
+void Symbol::print_Qvalue_on(outputStream* st) const {
+  if (this == NULL) {
+    st->print("NULL");
+  } else {
+    st->print("'Q");
+    for (int i = 0; i < utf8_length(); i++) {
+      st->print("%c", char_at(i));
+    }
+    st->print(";'");
+  }
+}
+
 // SymbolTable prints this in its statistics
 NOT_PRODUCT(size_t Symbol::_total_count = 0;)
diff a/src/hotspot/share/opto/arraycopynode.hpp b/src/hotspot/share/opto/arraycopynode.hpp
--- a/src/hotspot/share/opto/arraycopynode.hpp
+++ b/src/hotspot/share/opto/arraycopynode.hpp
@@ -88,31 +88,33 @@
 
   ArrayCopyNode(Compile* C, bool alloc_tightly_coupled, bool has_negative_length_guard);
 
   intptr_t get_length_if_constant(PhaseGVN *phase) const;
   int get_count(PhaseGVN *phase) const;
-  static const TypePtr* get_address_type(PhaseGVN* phase, const TypePtr* atp, Node* n);
+  static const TypeAryPtr* get_address_type(PhaseGVN* phase, const TypePtr* atp, Node* n);
 
   Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count);
   bool prepare_array_copy(PhaseGVN *phase, bool can_reshape,
                           Node*& adr_src, Node*& base_src, Node*& adr_dest, Node*& base_dest,
                           BasicType& copy_type, const Type*& value_type, bool& disjoint_bases);
-  void array_copy_test_overlap(PhaseGVN *phase, bool can_reshape,
+  void array_copy_test_overlap(GraphKit& kit,
                                bool disjoint_bases, int count,
-                               Node*& forward_ctl, Node*& backward_ctl);
-  Node* array_copy_forward(PhaseGVN *phase, bool can_reshape, Node*& ctl,
-                           MergeMemNode* mm,
-                           const TypePtr* atp_src, const TypePtr* atp_dest,
+                               Node*& backward_ctl);
+  void array_copy_forward(GraphKit& kit, bool can_reshape,
+                          const TypeAryPtr* atp_src, const TypeAryPtr* atp_dest,
+                          Node* adr_src, Node* base_src, Node* adr_dest, Node* base_dest,
+                          BasicType copy_type, const Type* value_type, int count);
+  void array_copy_backward(GraphKit& kit, bool can_reshape,
+                           const TypeAryPtr* atp_src, const TypeAryPtr* atp_dest,
                            Node* adr_src, Node* base_src, Node* adr_dest, Node* base_dest,
                            BasicType copy_type, const Type* value_type, int count);
-  Node* array_copy_backward(PhaseGVN *phase, bool can_reshape, Node*& ctl,
-                            MergeMemNode* mm,
-                            const TypePtr* atp_src, const TypePtr* atp_dest,
-                            Node* adr_src, Node* base_src, Node* adr_dest, Node* base_dest,
-                            BasicType copy_type, const Type* value_type, int count);
   bool finish_transform(PhaseGVN *phase, bool can_reshape,
                         Node* ctl, Node *mem);
+  void copy(GraphKit& kit, const TypeAryPtr* atp_src, const TypeAryPtr* atp_dest, int i,
+            Node* base_src, Node* base_dest, Node* adr_src, Node* adr_dest,
+            BasicType copy_type, const Type* value_type);
+
   static bool may_modify_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase, CallNode*& call);
 public:
   static Node* load(BarrierSetC2* bs, PhaseGVN *phase, Node*& ctl, MergeMemNode* mem, Node* addr, const TypePtr* adr_type, const Type *type, BasicType bt);
 private:
   void store(BarrierSetC2* bs, PhaseGVN *phase, Node*& ctl, MergeMemNode* mem, Node* addr, const TypePtr* adr_type, Node* val, const Type *type, BasicType bt);
diff a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp
--- a/src/hotspot/share/opto/c2compiler.cpp
+++ b/src/hotspot/share/opto/c2compiler.cpp
@@ -496,28 +496,32 @@
   case vmIntrinsics::_indexOfU_char:
   case vmIntrinsics::_toBytesStringU:
   case vmIntrinsics::_getCharsStringU:
   case vmIntrinsics::_getCharStringU:
   case vmIntrinsics::_putCharStringU:
+  case vmIntrinsics::_makePrivateBuffer:
+  case vmIntrinsics::_finishPrivateBuffer:
   case vmIntrinsics::_getReference:
   case vmIntrinsics::_getBoolean:
   case vmIntrinsics::_getByte:
   case vmIntrinsics::_getShort:
   case vmIntrinsics::_getChar:
   case vmIntrinsics::_getInt:
   case vmIntrinsics::_getLong:
   case vmIntrinsics::_getFloat:
   case vmIntrinsics::_getDouble:
+  case vmIntrinsics::_getValue:
   case vmIntrinsics::_putReference:
   case vmIntrinsics::_putBoolean:
   case vmIntrinsics::_putByte:
   case vmIntrinsics::_putShort:
   case vmIntrinsics::_putChar:
   case vmIntrinsics::_putInt:
   case vmIntrinsics::_putLong:
   case vmIntrinsics::_putFloat:
   case vmIntrinsics::_putDouble:
+  case vmIntrinsics::_putValue:
   case vmIntrinsics::_getReferenceVolatile:
   case vmIntrinsics::_getBooleanVolatile:
   case vmIntrinsics::_getByteVolatile:
   case vmIntrinsics::_getShortVolatile:
   case vmIntrinsics::_getCharVolatile:
diff a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -32,10 +32,11 @@
 #include "opto/addnode.hpp"
 #include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/convertnode.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/machnode.hpp"
 #include "opto/movenode.hpp"
 #include "opto/narrowptrnode.hpp"
 #include "opto/mulnode.hpp"
@@ -369,11 +370,11 @@
   }
 
   return true; // The Region node is unreachable - it is dead.
 }
 
-bool RegionNode::try_clean_mem_phi(PhaseGVN *phase) {
+Node* PhiNode::try_clean_mem_phi(PhaseGVN *phase) {
   // Incremental inlining + PhaseStringOpts sometimes produce:
   //
   // cmpP with 1 top input
   //           |
   //          If
@@ -389,31 +390,30 @@
   // the Region stays in the graph. The top input from the cmpP is
   // propagated forward and a subgraph that is useful goes away. The
   // code below replaces the Phi with the MergeMem so that the Region
   // is simplified.
 
-  PhiNode* phi = has_unique_phi();
-  if (phi && phi->type() == Type::MEMORY && req() == 3 && phi->is_diamond_phi(true)) {
+  if (type() == Type::MEMORY && is_diamond_phi(true)) {
     MergeMemNode* m = NULL;
-    assert(phi->req() == 3, "same as region");
+    assert(req() == 3, "same as region");
+    Node* r = in(0);
     for (uint i = 1; i < 3; ++i) {
-      Node *mem = phi->in(i);
-      if (mem && mem->is_MergeMem() && in(i)->outcnt() == 1) {
+      Node *mem = in(i);
+      if (mem && mem->is_MergeMem() && r->in(i)->outcnt() == 1) {
         // Nothing is control-dependent on path #i except the region itself.
         m = mem->as_MergeMem();
         uint j = 3 - i;
-        Node* other = phi->in(j);
+        Node* other = in(j);
         if (other && other == m->base_memory()) {
           // m is a successor memory to other, and is not pinned inside the diamond, so push it out.
           // This will allow the diamond to collapse completely.
-          phase->is_IterGVN()->replace_node(phi, m);
-          return true;
+          return m;
         }
       }
     }
   }
-  return false;
+  return NULL;
 }
 
 //------------------------------Ideal------------------------------------------
 // Return a node which is more "ideal" than the current node.  Must preserve
 // the CFG, but we can still strip out dead paths.
@@ -424,12 +424,19 @@
   // Check for RegionNode with no Phi users and both inputs come from either
   // arm of the same IF.  If found, then the control-flow split is useless.
   bool has_phis = false;
   if (can_reshape) {            // Need DU info to check for Phi users
     has_phis = (has_phi() != NULL);       // Cache result
-    if (has_phis && try_clean_mem_phi(phase)) {
-      has_phis = false;
+    if (has_phis) {
+      PhiNode* phi = has_unique_phi();
+      if (phi != NULL) {
+        Node* m = phi->try_clean_mem_phi(phase);
+        if (m != NULL) {
+          phase->is_IterGVN()->replace_node(phi, m);
+          has_phis = false;
+        }
+      }
     }
 
     if (!has_phis) {            // No Phi users?  Nothing merging?
       for (uint i = 1; i < req()-1; i++) {
         Node *if1 = in(i);
@@ -893,11 +900,11 @@
 
 //----------------------------make---------------------------------------------
 // create a new phi with edges matching r and set (initially) to x
 PhiNode* PhiNode::make(Node* r, Node* x, const Type *t, const TypePtr* at) {
   uint preds = r->req();   // Number of predecessor paths
-  assert(t != Type::MEMORY || at == flatten_phi_adr_type(at), "flatten at");
+  assert(t != Type::MEMORY || at == flatten_phi_adr_type(at) || (flatten_phi_adr_type(at) == TypeAryPtr::INLINES && Compile::current()->flattened_accesses_share_alias()), "flatten at");
   PhiNode* p = new PhiNode(r, t, at);
   for (uint j = 1; j < preds; j++) {
     // Fill in all inputs, except those which the region does not yet have
     if (r->in(j) != NULL)
       p->init_req(j, x);
@@ -1103,19 +1110,14 @@
   // convert the one to the other.
   const TypePtr* ttp = _type->make_ptr();
   const TypeInstPtr* ttip = (ttp != NULL) ? ttp->isa_instptr() : NULL;
   const TypeKlassPtr* ttkp = (ttp != NULL) ? ttp->isa_klassptr() : NULL;
   bool is_intf = false;
-  if (ttip != NULL) {
-    ciKlass* k = ttip->klass();
-    if (k->is_loaded() && k->is_interface())
-      is_intf = true;
-  }
-  if (ttkp != NULL) {
-    ciKlass* k = ttkp->klass();
-    if (k->is_loaded() && k->is_interface())
-      is_intf = true;
+  if (ttip != NULL && ttip->is_loaded() && ttip->klass()->is_interface()) {
+    is_intf = true;
+  } else if (ttkp != NULL && ttkp->is_loaded() && ttkp->klass()->is_interface()) {
+    is_intf = true;
   }
 
   // Default case: merge all inputs
   const Type *t = Type::TOP;        // Merged type starting value
   for (uint i = 1; i < req(); ++i) {// For all paths in
@@ -1168,13 +1170,13 @@
     // both implement interface I, but their meet is at 'j/l/O' which
     // doesn't implement I, we have no way to tell if the result should
     // be 'I' or 'j/l/O'.  Thus we'll pick 'j/l/O'.  If this then flows
     // into a Phi which "knows" it's an Interface type we'll have to
     // uplift the type.
-    if (!t->empty() && ttip && ttip->is_loaded() && ttip->klass()->is_interface()) {
+    if (!t->empty() && ttip != NULL && ttip->is_loaded() && ttip->klass()->is_interface()) {
       assert(ft == _type, ""); // Uplift to interface
-    } else if (!t->empty() && ttkp && ttkp->is_loaded() && ttkp->klass()->is_interface()) {
+    } else if (!t->empty() && ttkp != NULL && ttkp->is_loaded() && ttkp->klass()->is_interface()) {
       assert(ft == _type, ""); // Uplift to interface
     } else {
       // We also have to handle 'evil cases' of interface- vs. class-arrays
       Type::get_arrays_base_elements(jt, _type, NULL, &ttip);
       if (!t->empty() && ttip != NULL && ttip->is_loaded() && ttip->klass()->is_interface()) {
@@ -1332,10 +1334,18 @@
   if (true_path != 0) {
     Node* id = is_cmove_id(phase, true_path);
     if (id != NULL)  return id;
   }
 
+  if (phase->is_IterGVN()) {
+    Node* m = try_clean_mem_phi(phase);
+    if (m != NULL) {
+      return m;
+    }
+  }
+
+
   // Looking for phis with identical inputs.  If we find one that has
   // type TypePtr::BOTTOM, replace the current phi with the bottom phi.
   if (phase->is_IterGVN() && type() == Type::MEMORY && adr_type() !=
       TypePtr::BOTTOM && !adr_type()->is_known_instance()) {
     uint phi_len = req();
@@ -1878,10 +1888,28 @@
   // Note: During parsing, phis are often transformed before their regions.
   // This means we have to use type_or_null to defend against untyped regions.
   if( phase->type_or_null(r) == Type::TOP ) // Dead code?
     return NULL;                // No change
 
+  // If all inputs are inline types of the same type, push the inline type node down
+  // through the phi because inline type nodes should be merged through their input values.
+  if (req() > 2 && in(1) != NULL && in(1)->is_InlineTypeBase() && (can_reshape || in(1)->is_InlineType())) {
+    int opcode = in(1)->Opcode();
+    uint i = 2;
+    // Check if inputs are values of the same type
+    for (; i < req() && in(i) && in(i)->is_InlineTypeBase() && in(i)->cmp(*in(1)); i++) {
+      assert(in(i)->Opcode() == opcode, "mixing pointers and values?");
+    }
+    if (i == req()) {
+      InlineTypeBaseNode* vt = in(1)->as_InlineTypeBase()->clone_with_phis(phase, in(0));
+      for (uint i = 2; i < req(); ++i) {
+        vt->merge_with(phase, in(i)->as_InlineTypeBase(), i, i == (req()-1));
+      }
+      return vt;
+    }
+  }
+
   Node *top = phase->C->top();
   bool new_phi = (outcnt() == 0); // transforming new Phi
   // No change for igvn if new phi is not hooked
   if (new_phi && can_reshape)
     return NULL;
@@ -2176,10 +2204,12 @@
   // (MergeMemNode is not dead_loop_safe - need to check for dead loop.)
   if (progress == NULL && can_reshape && type() == Type::MEMORY) {
     // see if this phi should be sliced
     uint merge_width = 0;
     bool saw_self = false;
+    // TODO revisit this with JDK-8247216
+    bool mergemem_only = true;
     for( uint i=1; i<req(); ++i ) {// For all paths in
       Node *ii = in(i);
       // TOP inputs should not be counted as safe inputs because if the
       // Phi references itself through all other inputs then splitting the
       // Phi through memory merges would create dead loop at later stage.
@@ -2188,15 +2218,17 @@
       }
       if (ii->is_MergeMem()) {
         MergeMemNode* n = ii->as_MergeMem();
         merge_width = MAX2(merge_width, n->req());
         saw_self = saw_self || phase->eqv(n->base_memory(), this);
+      } else {
+        mergemem_only = false;
       }
     }
 
     // This restriction is temporarily necessary to ensure termination:
-    if (!saw_self && adr_type() == TypePtr::BOTTOM)  merge_width = 0;
+    if (!mergemem_only && !saw_self && adr_type() == TypePtr::BOTTOM)  merge_width = 0;
 
     if (merge_width > Compile::AliasIdxRaw) {
       // found at least one non-empty MergeMem
       const TypePtr* at = adr_type();
       if (at != TypePtr::BOTTOM) {
@@ -2621,10 +2653,16 @@
   if( phase->type(in(1)) == Type::TOP ) return in(1);
   if( phase->type(in(0)) == Type::TOP ) return in(0);
   // We only come from CatchProj, unless the CatchProj goes away.
   // If the CatchProj is optimized away, then we just carry the
   // exception oop through.
+
+  // CheckCastPPNode::Ideal() for inline types reuses the exception
+  // paths of a call to perform an allocation: we can see a Phi here.
+  if (in(1)->is_Phi()) {
+    return this;
+  }
   CallNode *call = in(1)->in(0)->as_Call();
 
   return ( in(0)->is_CatchProj() && in(0)->in(0)->in(1) == in(1) )
     ? this
     : call->in(TypeFunc::Parms);
diff a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp
--- a/src/hotspot/share/opto/compile.cpp
+++ b/src/hotspot/share/opto/compile.cpp
@@ -49,10 +49,11 @@
 #include "opto/connode.hpp"
 #include "opto/convertnode.hpp"
 #include "opto/divnode.hpp"
 #include "opto/escape.hpp"
 #include "opto/idealGraphPrinter.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/machnode.hpp"
 #include "opto/macro.hpp"
 #include "opto/matcher.hpp"
 #include "opto/mathexactnode.hpp"
@@ -403,10 +404,17 @@
     Node* opaq = opaque4_node(i);
     if (!useful.member(opaq)) {
       remove_opaque4_node(opaq);
     }
   }
+  // Remove useless inline type nodes
+  for (int i = _inline_type_nodes->length() - 1; i >= 0; i--) {
+    Node* vt = _inline_type_nodes->at(i);
+    if (!useful.member(vt)) {
+      _inline_type_nodes->remove(vt);
+    }
+  }
   BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
   bs->eliminate_useless_gc_barriers(useful, this);
   // clean up the late inline lists
   remove_useless_late_inlines(&_string_late_inlines, useful);
   remove_useless_late_inlines(&_boxing_late_inlines, useful);
@@ -629,21 +637,19 @@
     initial_gvn()->transform_no_reclaim(top());
 
     // Set up tf(), start(), and find a CallGenerator.
     CallGenerator* cg = NULL;
     if (is_osr_compilation()) {
-      const TypeTuple *domain = StartOSRNode::osr_domain();
-      const TypeTuple *range = TypeTuple::make_range(method()->signature());
-      init_tf(TypeFunc::make(domain, range));
-      StartNode* s = new StartOSRNode(root(), domain);
+      init_tf(TypeFunc::make(method(), /* is_osr_compilation = */ true));
+      StartNode* s = new StartOSRNode(root(), tf()->domain_sig());
       initial_gvn()->set_type_bottom(s);
       init_start(s);
       cg = CallGenerator::for_osr(method(), entry_bci());
     } else {
       // Normal case.
       init_tf(TypeFunc::make(method()));
-      StartNode* s = new StartNode(root(), tf()->domain());
+      StartNode* s = new StartNode(root(), tf()->domain_cc());
       initial_gvn()->set_type_bottom(s);
       init_start(s);
       if (method()->intrinsic_id() == vmIntrinsics::_Reference_get) {
         // With java.lang.ref.reference.get() we must go through the
         // intrinsic - even when get() is the root
@@ -764,10 +770,14 @@
   }
 
   // Now that we know the size of all the monitors we can add a fixed slot
   // for the original deopt pc.
   int next_slot = fixed_slots() + (sizeof(address) / VMRegImpl::stack_slot_size);
+  if (needs_stack_repair()) {
+    // One extra slot for the special stack increment value
+    next_slot += 2;
+  }
   set_fixed_slots(next_slot);
 
   // Compute when to use implicit null checks. Used by matching trap based
   // nodes and NullCheck optimization.
   set_allowed_deopt_reasons();
@@ -918,10 +928,13 @@
   Copy::zero_to_bytes(_trap_hist, sizeof(_trap_hist));
   set_decompile_count(0);
 
   set_do_freq_based_layout(_directive->BlockLayoutByFrequencyOption);
   _loop_opts_cnt = LoopOptsCount;
+  _has_flattened_accesses = false;
+  _flattened_accesses_share_alias = true;
+
   set_do_inlining(Inline);
   set_max_inline_size(MaxInlineSize);
   set_freq_inline_size(FreqInlineSize);
   set_do_scheduling(OptoScheduling);
   set_do_count_invocations(false);
@@ -1001,10 +1014,11 @@
   _macro_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _predicate_opaqs = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _expensive_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _range_check_casts = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   _opaque4_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
+  _inline_type_nodes = new(comp_arena()) GrowableArray<Node*>(comp_arena(), 8,  0, NULL);
   register_library_intrinsics();
 #ifdef ASSERT
   _type_verify_symmetry = true;
   _phase_optimize_finished = false;
 #endif
@@ -1229,11 +1243,12 @@
   bool is_known_inst = tj->isa_oopptr() != NULL &&
                        tj->is_oopptr()->is_known_instance();
 
   // Process weird unsafe references.
   if (offset == Type::OffsetBot && (tj->isa_instptr() /*|| tj->isa_klassptr()*/)) {
-    assert(InlineUnsafeOps, "indeterminate pointers come only from unsafe ops");
+    bool default_value_load = EnableValhalla && tj->is_instptr()->klass() == ciEnv::current()->Class_klass();
+    assert(InlineUnsafeOps || default_value_load, "indeterminate pointers come only from unsafe ops");
     assert(!is_known_inst, "scalarizable allocation should not have unsafe references");
     tj = TypeOopPtr::BOTTOM;
     ptr = tj->ptr();
     offset = tj->offset();
   }
@@ -1242,24 +1257,35 @@
   const TypeAryPtr *ta = tj->isa_aryptr();
   if (ta && ta->is_stable()) {
     // Erase stability property for alias analysis.
     tj = ta = ta->cast_to_stable(false);
   }
+  if (ta && ta->is_not_flat()) {
+    // Erase not flat property for alias analysis.
+    tj = ta = ta->cast_to_not_flat(false);
+  }
+  if (ta && ta->is_not_null_free()) {
+    // Erase not null free property for alias analysis.
+    tj = ta = ta->cast_to_not_null_free(false);
+  }
+
   if( ta && is_known_inst ) {
     if ( offset != Type::OffsetBot &&
          offset > arrayOopDesc::length_offset_in_bytes() ) {
       offset = Type::OffsetBot; // Flatten constant access into array body only
-      tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, offset, ta->instance_id());
+      tj = ta = TypeAryPtr::make(ptr, ta->ary(), ta->klass(), true, Type::Offset(offset), ta->field_offset(), ta->instance_id());
     }
   } else if( ta && _AliasLevel >= 2 ) {
     // For arrays indexed by constant indices, we flatten the alias
     // space to include all of the array body.  Only the header, klass
     // and array length can be accessed un-aliased.
+    // For flattened inline type array, each field has its own slice so
+    // we must include the field offset.
     if( offset != Type::OffsetBot ) {
       if( ta->const_oop() ) { // MethodData* or Method*
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,offset);
+        tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),ta->ary(),ta->klass(),false,Type::Offset(offset), ta->field_offset());
       } else if( offset == arrayOopDesc::length_offset_in_bytes() ) {
         // range is OK as-is.
         tj = ta = TypeAryPtr::RANGE;
       } else if( offset == oopDesc::klass_offset_in_bytes() ) {
         tj = TypeInstPtr::KLASS; // all klass loads look alike
@@ -1269,39 +1295,44 @@
         tj = TypeInstPtr::MARK;
         ta = TypeAryPtr::RANGE; // generic ignored junk
         ptr = TypePtr::BotPTR;
       } else {                  // Random constant offset into array body
         offset = Type::OffsetBot;   // Flatten constant access into array body
-        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,offset);
+        tj = ta = TypeAryPtr::make(ptr,ta->ary(),ta->klass(),false,Type::Offset(offset), ta->field_offset());
       }
     }
     // Arrays of fixed size alias with arrays of unknown size.
     if (ta->size() != TypeInt::POS) {
       const TypeAry *tary = TypeAry::make(ta->elem(), TypeInt::POS);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,ta->klass(),false,Type::Offset(offset), ta->field_offset());
     }
     // Arrays of known objects become arrays of unknown objects.
     if (ta->elem()->isa_narrowoop() && ta->elem() != TypeNarrowOop::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeNarrowOop::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,Type::Offset(offset), ta->field_offset());
     }
     if (ta->elem()->isa_oopptr() && ta->elem() != TypeInstPtr::BOTTOM) {
       const TypeAry *tary = TypeAry::make(TypeInstPtr::BOTTOM, ta->size());
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,Type::Offset(offset), ta->field_offset());
+    }
+    // Initially all flattened array accesses share a single slice
+    if (ta->is_flat() && ta->elem() != TypeInlineType::BOTTOM && _flattened_accesses_share_alias) {
+      const TypeAry *tary = TypeAry::make(TypeInlineType::BOTTOM, ta->size());
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,NULL,false,Type::Offset(offset), Type::Offset(Type::OffsetBot));
     }
     // Arrays of bytes and of booleans both use 'bastore' and 'baload' so
     // cannot be distinguished by bytecode alone.
     if (ta->elem() == TypeInt::BOOL) {
       const TypeAry *tary = TypeAry::make(TypeInt::BYTE, ta->size());
       ciKlass* aklass = ciTypeArrayKlass::make(T_BYTE);
-      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,offset);
+      tj = ta = TypeAryPtr::make(ptr,ta->const_oop(),tary,aklass,false,Type::Offset(offset), ta->field_offset());
     }
     // During the 2nd round of IterGVN, NotNull castings are removed.
     // Make sure the Bottom and NotNull variants alias the same.
     // Also, make sure exact and non-exact variants alias the same.
     if (ptr == TypePtr::NotNull || ta->klass_is_exact() || ta->speculative() != NULL) {
-      tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,offset);
+      tj = ta = TypeAryPtr::make(TypePtr::BotPTR,ta->ary(),ta->klass(),false,Type::Offset(offset), ta->field_offset());
     }
   }
 
   // Oop pointers need some flattening
   const TypeInstPtr *to = tj->isa_instptr();
@@ -1311,29 +1342,29 @@
       if (to->klass() != ciEnv::current()->Class_klass() ||
           offset < k->size_helper() * wordSize) {
         // No constant oop pointers (such as Strings); they alias with
         // unknown strings.
         assert(!is_known_inst, "not scalarizable allocation");
-        tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
+        tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,Type::Offset(offset));
       }
     } else if( is_known_inst ) {
       tj = to; // Keep NotNull and klass_is_exact for instance type
     } else if( ptr == TypePtr::NotNull || to->klass_is_exact() ) {
       // During the 2nd round of IterGVN, NotNull castings are removed.
       // Make sure the Bottom and NotNull variants alias the same.
       // Also, make sure exact and non-exact variants alias the same.
-      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,offset);
+      tj = to = TypeInstPtr::make(TypePtr::BotPTR,to->klass(),false,0,Type::Offset(offset));
     }
     if (to->speculative() != NULL) {
-      tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),to->offset(), to->instance_id());
+      tj = to = TypeInstPtr::make(to->ptr(),to->klass(),to->klass_is_exact(),to->const_oop(),Type::Offset(to->offset()), to->klass()->flatten_array(), to->instance_id());
     }
     // Canonicalize the holder of this field
     if (offset >= 0 && offset < instanceOopDesc::base_offset_in_bytes()) {
       // First handle header references such as a LoadKlassNode, even if the
       // object's klass is unloaded at compile time (4965979).
       if (!is_known_inst) { // Do it only for non-instance types
-        tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, offset);
+        tj = to = TypeInstPtr::make(TypePtr::BotPTR, env()->Object_klass(), false, NULL, Type::Offset(offset));
       }
     } else if (offset < 0 || offset >= k->size_helper() * wordSize) {
       // Static fields are in the space above the normal instance
       // fields in the java.lang.Class instance.
       if (to->klass() != ciEnv::current()->Class_klass()) {
@@ -1343,13 +1374,13 @@
       }
     } else {
       ciInstanceKlass *canonical_holder = k->get_canonical_holder(offset);
       if (!k->equals(canonical_holder) || tj->offset() != offset) {
         if( is_known_inst ) {
-          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, offset, to->instance_id());
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, true, NULL, Type::Offset(offset), canonical_holder->flatten_array(), to->instance_id());
         } else {
-          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, offset);
+          tj = to = TypeInstPtr::make(to->ptr(), canonical_holder, false, NULL, Type::Offset(offset));
         }
       }
     }
   }
 
@@ -1362,19 +1393,19 @@
     // use NotNull as the PTR.
     if ( offset == Type::OffsetBot || (offset >= 0 && (size_t)offset < sizeof(Klass)) ) {
 
       tj = tk = TypeKlassPtr::make(TypePtr::NotNull,
                                    TypeKlassPtr::OBJECT->klass(),
-                                   offset);
+                                   Type::Offset(offset));
     }
 
     ciKlass* klass = tk->klass();
-    if( klass->is_obj_array_klass() ) {
+    if (klass != NULL && klass->is_obj_array_klass()) {
       ciKlass* k = TypeAryPtr::OOPS->klass();
       if( !k || !k->is_loaded() )                  // Only fails for some -Xcomp runs
         k = TypeInstPtr::BOTTOM->klass();
-      tj = tk = TypeKlassPtr::make( TypePtr::NotNull, k, offset );
+      tj = tk = TypeKlassPtr::make(TypePtr::NotNull, k, Type::Offset(offset));
     }
 
     // Check for precise loads from the primary supertype array and force them
     // to the supertype cache alias index.  Check for generic array loads from
     // the primary supertype array and also force them to the supertype cache
@@ -1386,11 +1417,11 @@
     if (offset == Type::OffsetBot ||
         (offset >= primary_supers_offset &&
          offset < (int)(primary_supers_offset + Klass::primary_super_limit() * wordSize)) ||
         offset == (int)in_bytes(Klass::secondary_super_cache_offset())) {
       offset = in_bytes(Klass::secondary_super_cache_offset());
-      tj = tk = TypeKlassPtr::make( TypePtr::NotNull, tk->klass(), offset );
+      tj = tk = TypeKlassPtr::make(TypePtr::NotNull, tk->klass(), Type::Offset(offset));
     }
   }
 
   // Flatten all Raw pointers together.
   if (tj->base() == Type::RawPtr)
@@ -1525,17 +1556,20 @@
   for (int i = 0; i < new_ats; i++)  _alias_types[old_ats+i] = &ats[i];
 }
 
 
 //--------------------------------find_alias_type------------------------------
-Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create, ciField* original_field) {
+Compile::AliasType* Compile::find_alias_type(const TypePtr* adr_type, bool no_create, ciField* original_field, bool uncached) {
   if (_AliasLevel == 0)
     return alias_type(AliasIdxBot);
 
-  AliasCacheEntry* ace = probe_alias_cache(adr_type);
-  if (ace->_adr_type == adr_type) {
-    return alias_type(ace->_index);
+  AliasCacheEntry* ace = NULL;
+  if (!uncached) {
+    ace = probe_alias_cache(adr_type);
+    if (ace->_adr_type == adr_type) {
+      return alias_type(ace->_index);
+    }
   }
 
   // Handle special cases.
   if (adr_type == NULL)             return alias_type(AliasIdxTop);
   if (adr_type == TypePtr::BOTTOM)  return alias_type(AliasIdxBot);
@@ -1581,18 +1615,28 @@
     if (flat->isa_instptr()) {
       if (flat->offset() == java_lang_Class::klass_offset()
           && flat->is_instptr()->klass() == env()->Class_klass())
         alias_type(idx)->set_rewritable(false);
     }
+    ciField* field = NULL;
     if (flat->isa_aryptr()) {
 #ifdef ASSERT
       const int header_size_min  = arrayOopDesc::base_offset_in_bytes(T_BYTE);
       // (T_BYTE has the weakest alignment and size restrictions...)
       assert(flat->offset() < header_size_min, "array body reference must be OffsetBot");
 #endif
+      const Type* elemtype = flat->is_aryptr()->elem();
       if (flat->offset() == TypePtr::OffsetBot) {
-        alias_type(idx)->set_element(flat->is_aryptr()->elem());
+        alias_type(idx)->set_element(elemtype);
+      }
+      int field_offset = flat->is_aryptr()->field_offset().get();
+      if (elemtype->isa_inlinetype() &&
+          elemtype->inline_klass() != NULL &&
+          field_offset != Type::OffsetBot) {
+        ciInlineKlass* vk = elemtype->inline_klass();
+        field_offset += vk->first_field_offset();
+        field = vk->get_field_by_offset(field_offset, false);
       }
     }
     if (flat->isa_klassptr()) {
       if (flat->offset() == in_bytes(Klass::super_check_offset_offset()))
         alias_type(idx)->set_rewritable(false);
@@ -1600,52 +1644,66 @@
         alias_type(idx)->set_rewritable(false);
       if (flat->offset() == in_bytes(Klass::access_flags_offset()))
         alias_type(idx)->set_rewritable(false);
       if (flat->offset() == in_bytes(Klass::java_mirror_offset()))
         alias_type(idx)->set_rewritable(false);
+      if (flat->offset() == in_bytes(Klass::layout_helper_offset()))
+        alias_type(idx)->set_rewritable(false);
       if (flat->offset() == in_bytes(Klass::secondary_super_cache_offset()))
         alias_type(idx)->set_rewritable(false);
     }
     // %%% (We would like to finalize JavaThread::threadObj_offset(),
     // but the base pointer type is not distinctive enough to identify
     // references into JavaThread.)
 
     // Check for final fields.
     const TypeInstPtr* tinst = flat->isa_instptr();
     if (tinst && tinst->offset() >= instanceOopDesc::base_offset_in_bytes()) {
-      ciField* field;
       if (tinst->const_oop() != NULL &&
           tinst->klass() == ciEnv::current()->Class_klass() &&
           tinst->offset() >= (tinst->klass()->as_instance_klass()->size_helper() * wordSize)) {
         // static field
         ciInstanceKlass* k = tinst->const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass();
         field = k->get_field_by_offset(tinst->offset(), true);
+      } else if (tinst->klass()->is_inlinetype()) {
+        // Inline type field
+        ciInlineKlass* vk = tinst->inline_klass();
+        field = vk->get_field_by_offset(tinst->offset(), false);
       } else {
-        ciInstanceKlass *k = tinst->klass()->as_instance_klass();
+        ciInstanceKlass* k = tinst->klass()->as_instance_klass();
         field = k->get_field_by_offset(tinst->offset(), false);
       }
-      assert(field == NULL ||
-             original_field == NULL ||
-             (field->holder() == original_field->holder() &&
-              field->offset() == original_field->offset() &&
-              field->is_static() == original_field->is_static()), "wrong field?");
-      // Set field() and is_rewritable() attributes.
-      if (field != NULL)  alias_type(idx)->set_field(field);
+    }
+    assert(field == NULL ||
+           original_field == NULL ||
+           (field->holder() == original_field->holder() &&
+            field->offset() == original_field->offset() &&
+            field->is_static() == original_field->is_static()), "wrong field?");
+    // Set field() and is_rewritable() attributes.
+    if (field != NULL) {
+      alias_type(idx)->set_field(field);
+      if (flat->isa_aryptr()) {
+        // Fields of flat arrays are rewritable although they are declared final
+        assert(flat->is_aryptr()->is_flat(), "must be a flat array");
+        alias_type(idx)->set_rewritable(true);
+      }
     }
   }
 
   // Fill the cache for next time.
-  ace->_adr_type = adr_type;
-  ace->_index    = idx;
-  assert(alias_type(adr_type) == alias_type(idx),  "type must be installed");
+  if (!uncached) {
+    ace->_adr_type = adr_type;
+    ace->_index    = idx;
+    assert(alias_type(adr_type) == alias_type(idx),  "type must be installed");
 
-  // Might as well try to fill the cache for the flattened version, too.
-  AliasCacheEntry* face = probe_alias_cache(flat);
-  if (face->_adr_type == NULL) {
-    face->_adr_type = flat;
-    face->_index    = idx;
-    assert(alias_type(flat) == alias_type(idx), "flat type must work too");
+    // Might as well try to fill the cache for the flattened version, too.
+    AliasCacheEntry* face = probe_alias_cache(flat);
+    if (face->_adr_type == NULL) {
+      face->_adr_type = flat;
+      face->_index    = idx;
+      assert(alias_type(flat) == alias_type(idx), "flat type must work too");
+    }
   }
 
   return alias_type(idx);
 }
 
@@ -1803,10 +1861,358 @@
     igvn.replace_node(opaq, opaq->in(2));
   }
   assert(opaque4_count() == 0, "should be empty");
 }
 
+void Compile::add_inline_type(Node* n) {
+  assert(n->is_InlineTypeBase(), "unexpected node");
+  if (_inline_type_nodes != NULL) {
+    _inline_type_nodes->push(n);
+  }
+}
+
+void Compile::remove_inline_type(Node* n) {
+  assert(n->is_InlineTypeBase(), "unexpected node");
+  if (_inline_type_nodes != NULL && _inline_type_nodes->contains(n)) {
+    _inline_type_nodes->remove(n);
+  }
+}
+
+// Does the return value keep otherwise useless inline type allocations alive?
+static bool return_val_keeps_allocations_alive(Node* ret_val) {
+  ResourceMark rm;
+  Unique_Node_List wq;
+  wq.push(ret_val);
+  bool some_allocations = false;
+  for (uint i = 0; i < wq.size(); i++) {
+    Node* n = wq.at(i);
+    assert(!n->is_InlineType(), "chain of inline type nodes");
+    if (n->outcnt() > 1) {
+      // Some other use for the allocation
+      return false;
+    } else if (n->is_InlineTypePtr()) {
+      wq.push(n->in(1));
+    } else if (n->is_Phi()) {
+      for (uint j = 1; j < n->req(); j++) {
+        wq.push(n->in(j));
+      }
+    } else if (n->is_CheckCastPP() &&
+               n->in(1)->is_Proj() &&
+               n->in(1)->in(0)->is_Allocate()) {
+      some_allocations = true;
+    }
+  }
+  return some_allocations;
+}
+
+void Compile::process_inline_types(PhaseIterGVN &igvn, bool post_ea) {
+  // Make inline types scalar in safepoints
+  for (int i = _inline_type_nodes->length()-1; i >= 0; i--) {
+    InlineTypeBaseNode* vt = _inline_type_nodes->at(i)->as_InlineTypeBase();
+    vt->make_scalar_in_safepoints(&igvn);
+  }
+  // Remove InlineTypePtr nodes only after EA to give scalar replacement a chance
+  // to remove buffer allocations. InlineType nodes are kept until loop opts and
+  // removed via InlineTypeNode::remove_redundant_allocations.
+  if (post_ea) {
+    while (_inline_type_nodes->length() > 0) {
+      InlineTypeBaseNode* vt = _inline_type_nodes->pop()->as_InlineTypeBase();
+      if (vt->is_InlineTypePtr()) {
+        igvn.replace_node(vt, vt->get_oop());
+      }
+    }
+  }
+  // Make sure that the return value does not keep an unused allocation alive
+  if (tf()->returns_inline_type_as_fields()) {
+    Node* ret = NULL;
+    for (uint i = 1; i < root()->req(); i++){
+      Node* in = root()->in(i);
+      if (in->Opcode() == Op_Return) {
+        assert(ret == NULL, "only one return");
+        ret = in;
+      }
+    }
+    if (ret != NULL) {
+      Node* ret_val = ret->in(TypeFunc::Parms);
+      if (igvn.type(ret_val)->isa_oopptr() &&
+          return_val_keeps_allocations_alive(ret_val)) {
+        igvn.replace_input_of(ret, TypeFunc::Parms, InlineTypeNode::tagged_klass(igvn.type(ret_val)->inline_klass(), igvn));
+        assert(ret_val->outcnt() == 0, "should be dead now");
+        igvn.remove_dead_node(ret_val);
+      }
+    }
+  }
+  igvn.optimize();
+}
+
+void Compile::adjust_flattened_array_access_aliases(PhaseIterGVN& igvn) {
+  if (!_has_flattened_accesses) {
+    return;
+  }
+  // Initially, all flattened array accesses share the same slice to
+  // keep dependencies with Object[] array accesses (that could be
+  // to a flattened array) correct. We're done with parsing so we
+  // now know all flattened array accesses in this compile
+  // unit. Let's move flattened array accesses to their own slice,
+  // one per element field. This should help memory access
+  // optimizations.
+  ResourceMark rm;
+  Unique_Node_List wq;
+  wq.push(root());
+
+  Node_List mergememnodes;
+  Node_List memnodes;
+
+  // Alias index currently shared by all flattened memory accesses
+  int index = get_alias_index(TypeAryPtr::INLINES);
+
+  // Find MergeMem nodes and flattened array accesses
+  for (uint i = 0; i < wq.size(); i++) {
+    Node* n = wq.at(i);
+    if (n->is_Mem()) {
+      const TypePtr* adr_type = NULL;
+      if (n->Opcode() == Op_StoreCM) {
+        adr_type = get_adr_type(get_alias_index(n->in(MemNode::OopStore)->adr_type()));
+      } else {
+        adr_type = get_adr_type(get_alias_index(n->adr_type()));
+      }
+      if (adr_type == TypeAryPtr::INLINES) {
+        memnodes.push(n);
+      }
+    } else if (n->is_MergeMem()) {
+      MergeMemNode* mm = n->as_MergeMem();
+      if (mm->memory_at(index) != mm->base_memory()) {
+        mergememnodes.push(n);
+      }
+    }
+    for (uint j = 0; j < n->req(); j++) {
+      Node* m = n->in(j);
+      if (m != NULL) {
+        wq.push(m);
+      }
+    }
+  }
+
+  if (memnodes.size() > 0) {
+    _flattened_accesses_share_alias = false;
+
+    // We are going to change the slice for the flattened array
+    // accesses so we need to clear the cache entries that refer to
+    // them.
+    for (uint i = 0; i < AliasCacheSize; i++) {
+      AliasCacheEntry* ace = &_alias_cache[i];
+      if (ace->_adr_type != NULL &&
+          ace->_adr_type->isa_aryptr() &&
+          ace->_adr_type->is_aryptr()->is_flat()) {
+        ace->_adr_type = NULL;
+        ace->_index = (i != 0) ? 0 : AliasIdxTop; // Make sure the NULL adr_type resolves to AliasIdxTop
+      }
+    }
+
+    // Find what aliases we are going to add
+    int start_alias = num_alias_types()-1;
+    int stop_alias = 0;
+
+    for (uint i = 0; i < memnodes.size(); i++) {
+      Node* m = memnodes.at(i);
+      const TypePtr* adr_type = NULL;
+      if (m->Opcode() == Op_StoreCM) {
+        adr_type = m->in(MemNode::OopStore)->adr_type();
+        Node* clone = new StoreCMNode(m->in(MemNode::Control), m->in(MemNode::Memory), m->in(MemNode::Address),
+                                      m->adr_type(), m->in(MemNode::ValueIn), m->in(MemNode::OopStore),
+                                      get_alias_index(adr_type));
+        igvn.register_new_node_with_optimizer(clone);
+        igvn.replace_node(m, clone);
+      } else {
+        adr_type = m->adr_type();
+#ifdef ASSERT
+        m->as_Mem()->set_adr_type(adr_type);
+#endif
+      }
+      int idx = get_alias_index(adr_type);
+      start_alias = MIN2(start_alias, idx);
+      stop_alias = MAX2(stop_alias, idx);
+    }
+
+    assert(stop_alias >= start_alias, "should have expanded aliases");
+
+    Node_Stack stack(0);
+#ifdef ASSERT
+    VectorSet seen(Thread::current()->resource_area());
+#endif
+    // Now let's fix the memory graph so each flattened array access
+    // is moved to the right slice. Start from the MergeMem nodes.
+    uint last = unique();
+    for (uint i = 0; i < mergememnodes.size(); i++) {
+      MergeMemNode* current = mergememnodes.at(i)->as_MergeMem();
+      Node* n = current->memory_at(index);
+      MergeMemNode* mm = NULL;
+      do {
+        // Follow memory edges through memory accesses, phis and
+        // narrow membars and push nodes on the stack. Once we hit
+        // bottom memory, we pop element off the stack one at a
+        // time, in reverse order, and move them to the right slice
+        // by changing their memory edges.
+        if ((n->is_Phi() && n->adr_type() != TypePtr::BOTTOM) || n->is_Mem() || n->adr_type() == TypeAryPtr::INLINES) {
+          assert(!seen.test_set(n->_idx), "");
+          // Uses (a load for instance) will need to be moved to the
+          // right slice as well and will get a new memory state
+          // that we don't know yet. The use could also be the
+          // backedge of a loop. We put a place holder node between
+          // the memory node and its uses. We replace that place
+          // holder with the correct memory state once we know it,
+          // i.e. when nodes are popped off the stack. Using the
+          // place holder make the logic work in the presence of
+          // loops.
+          if (n->outcnt() > 1) {
+            Node* place_holder = NULL;
+            assert(!n->has_out_with(Op_Node), "");
+            for (DUIterator k = n->outs(); n->has_out(k); k++) {
+              Node* u = n->out(k);
+              if (u != current && u->_idx < last) {
+                bool success = false;
+                for (uint l = 0; l < u->req(); l++) {
+                  if (!stack.is_empty() && u == stack.node() && l == stack.index()) {
+                    continue;
+                  }
+                  Node* in = u->in(l);
+                  if (in == n) {
+                    if (place_holder == NULL) {
+                      place_holder = new Node(1);
+                      place_holder->init_req(0, n);
+                    }
+                    igvn.replace_input_of(u, l, place_holder);
+                    success = true;
+                  }
+                }
+                if (success) {
+                  --k;
+                }
+              }
+            }
+          }
+          if (n->is_Phi()) {
+            stack.push(n, 1);
+            n = n->in(1);
+          } else if (n->is_Mem()) {
+            stack.push(n, n->req());
+            n = n->in(MemNode::Memory);
+          } else {
+            assert(n->is_Proj() && n->in(0)->Opcode() == Op_MemBarCPUOrder, "");
+            stack.push(n, n->req());
+            n = n->in(0)->in(TypeFunc::Memory);
+          }
+        } else {
+          assert(n->adr_type() == TypePtr::BOTTOM || (n->Opcode() == Op_Node && n->_idx >= last) || (n->is_Proj() && n->in(0)->is_Initialize()), "");
+          // Build a new MergeMem node to carry the new memory state
+          // as we build it. IGVN should fold extraneous MergeMem
+          // nodes.
+          mm = MergeMemNode::make(n);
+          igvn.register_new_node_with_optimizer(mm);
+          while (stack.size() > 0) {
+            Node* m = stack.node();
+            uint idx = stack.index();
+            if (m->is_Mem()) {
+              // Move memory node to its new slice
+              const TypePtr* adr_type = m->adr_type();
+              int alias = get_alias_index(adr_type);
+              Node* prev = mm->memory_at(alias);
+              igvn.replace_input_of(m, MemNode::Memory, prev);
+              mm->set_memory_at(alias, m);
+            } else if (m->is_Phi()) {
+              // We need as many new phis as there are new aliases
+              igvn.replace_input_of(m, idx, mm);
+              if (idx == m->req()-1) {
+                Node* r = m->in(0);
+                for (uint j = (uint)start_alias; j <= (uint)stop_alias; j++) {
+                  const Type* adr_type = get_adr_type(j);
+                  if (!adr_type->isa_aryptr() || !adr_type->is_aryptr()->is_flat()) {
+                    continue;
+                  }
+                  Node* phi = new PhiNode(r, Type::MEMORY, get_adr_type(j));
+                  igvn.register_new_node_with_optimizer(phi);
+                  for (uint k = 1; k < m->req(); k++) {
+                    phi->init_req(k, m->in(k)->as_MergeMem()->memory_at(j));
+                  }
+                  mm->set_memory_at(j, phi);
+                }
+                Node* base_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM);
+                igvn.register_new_node_with_optimizer(base_phi);
+                for (uint k = 1; k < m->req(); k++) {
+                  base_phi->init_req(k, m->in(k)->as_MergeMem()->base_memory());
+                }
+                mm->set_base_memory(base_phi);
+              }
+            } else {
+              // This is a MemBarCPUOrder node from
+              // Parse::array_load()/Parse::array_store(), in the
+              // branch that handles flattened arrays hidden under
+              // an Object[] array. We also need one new membar per
+              // new alias to keep the unknown access that the
+              // membars protect properly ordered with accesses to
+              // known flattened array.
+              assert(m->is_Proj(), "projection expected");
+              Node* ctrl = m->in(0)->in(TypeFunc::Control);
+              igvn.replace_input_of(m->in(0), TypeFunc::Control, top());
+              for (uint j = (uint)start_alias; j <= (uint)stop_alias; j++) {
+                const Type* adr_type = get_adr_type(j);
+                if (!adr_type->isa_aryptr() || !adr_type->is_aryptr()->is_flat()) {
+                  continue;
+                }
+                MemBarNode* mb = new MemBarCPUOrderNode(this, j, NULL);
+                igvn.register_new_node_with_optimizer(mb);
+                Node* mem = mm->memory_at(j);
+                mb->init_req(TypeFunc::Control, ctrl);
+                mb->init_req(TypeFunc::Memory, mem);
+                ctrl = new ProjNode(mb, TypeFunc::Control);
+                igvn.register_new_node_with_optimizer(ctrl);
+                mem = new ProjNode(mb, TypeFunc::Memory);
+                igvn.register_new_node_with_optimizer(mem);
+                mm->set_memory_at(j, mem);
+              }
+              igvn.replace_node(m->in(0)->as_Multi()->proj_out(TypeFunc::Control), ctrl);
+            }
+            if (idx < m->req()-1) {
+              idx += 1;
+              stack.set_index(idx);
+              n = m->in(idx);
+              break;
+            }
+            // Take care of place holder nodes
+            if (m->has_out_with(Op_Node)) {
+              Node* place_holder = m->find_out_with(Op_Node);
+              if (place_holder != NULL) {
+                Node* mm_clone = mm->clone();
+                igvn.register_new_node_with_optimizer(mm_clone);
+                Node* hook = new Node(1);
+                hook->init_req(0, mm);
+                igvn.replace_node(place_holder, mm_clone);
+                hook->destruct();
+              }
+              assert(!m->has_out_with(Op_Node), "place holder should be gone now");
+            }
+            stack.pop();
+          }
+        }
+      } while(stack.size() > 0);
+      // Fix the memory state at the MergeMem we started from
+      igvn.rehash_node_delayed(current);
+      for (uint j = (uint)start_alias; j <= (uint)stop_alias; j++) {
+        const Type* adr_type = get_adr_type(j);
+        if (!adr_type->isa_aryptr() || !adr_type->is_aryptr()->is_flat()) {
+          continue;
+        }
+        current->set_memory_at(j, mm);
+      }
+      current->set_memory_at(index, current->base_memory());
+    }
+    igvn.optimize();
+  }
+  print_method(PHASE_SPLIT_INLINES_ARRAY, 2);
+}
+
+
 // StringOpts and late inlining of string methods
 void Compile::inline_string_calls(bool parse_time) {
   {
     // remove useless nodes to make the usage analysis simpler
     ResourceMark rm;
@@ -2082,10 +2488,17 @@
     set_for_igvn(&new_worklist);
     igvn = PhaseIterGVN(initial_gvn());
     igvn.optimize();
   }
 
+  if (_inline_type_nodes->length() > 0) {
+    // Do this once all inlining is over to avoid getting inconsistent debug info
+    process_inline_types(igvn);
+  }
+
+  adjust_flattened_array_access_aliases(igvn);
+
   // Perform escape analysis
   if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
     if (has_loops()) {
       // Cleanup graph (remove dead nodes).
       TracePhase tp("idealLoop", &timers[_t_idealLoop]);
@@ -2114,10 +2527,15 @@
 
       if (failing())  return;
     }
   }
 
+  if (_inline_type_nodes->length() > 0) {
+    // Process inline types again now that EA might have simplified the graph
+    process_inline_types(igvn, /* post_ea= */ true);
+  }
+
   // Loop transforms on the ideal graph.  Range Check Elimination,
   // peeling, unrolling, etc.
 
   // Set loop opts counter
   if((_loop_opts_cnt > 0) && (has_loops() || has_split_ifs())) {
@@ -2756,10 +3174,11 @@
       mem = prev->in(MemNode::Memory);
     }
   }
 }
 
+
 //------------------------------final_graph_reshaping_impl----------------------
 // Implement items 1-5 from final_graph_reshaping below.
 void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) {
 
   if ( n->outcnt() == 0 ) return; // dead node
@@ -3494,10 +3913,18 @@
       Node* cmp = new CmpLNode(andl, n->in(2));
       n->subsume_by(cmp, this);
     }
     break;
   }
+#ifdef ASSERT
+  case Op_InlineTypePtr:
+  case Op_InlineType: {
+    n->dump(-1);
+    assert(false, "inline type node was not removed");
+    break;
+  }
+#endif
   default:
     assert(!n->is_Call(), "");
     assert(!n->is_Mem(), "");
     assert(nop != Op_ProfileBoolean, "should be eliminated during IGVN");
     break;
@@ -3841,20 +4268,20 @@
   if (holder->is_being_initialized()) {
     if (accessing_method->holder() == holder) {
       // Access inside a class. The barrier can be elided when access happens in <clinit>,
       // <init>, or a static method. In all those cases, there was an initialization
       // barrier on the holder klass passed.
-      if (accessing_method->is_static_initializer() ||
-          accessing_method->is_object_initializer() ||
+      if (accessing_method->is_class_initializer() ||
+          accessing_method->is_object_constructor() ||
           accessing_method->is_static()) {
         return false;
       }
     } else if (accessing_method->holder()->is_subclass_of(holder)) {
       // Access from a subclass. The barrier can be elided only when access happens in <clinit>.
       // In case of <init> or a static method, the barrier is on the subclass is not enough:
       // child class can become fully initialized while its parent class is still being initialized.
-      if (accessing_method->is_static_initializer()) {
+      if (accessing_method->is_class_initializer()) {
         return false;
       }
     }
     ciMethod* root = method(); // the root method of compilation
     if (root != accessing_method) {
@@ -3971,21 +4398,23 @@
 // (0) superklass is java.lang.Object (can occur in reflective code)
 // (1) subklass is already limited to a subtype of superklass => always ok
 // (2) subklass does not overlap with superklass => always fail
 // (3) superklass has NO subtypes and we can check with a simple compare.
 int Compile::static_subtype_check(ciKlass* superk, ciKlass* subk) {
-  if (StressReflectiveCode) {
+  if (StressReflectiveCode || superk == NULL || subk == NULL) {
     return SSC_full_test;       // Let caller generate the general case.
   }
 
   if (superk == env()->Object_klass()) {
     return SSC_always_true;     // (0) this test cannot fail
   }
 
   ciType* superelem = superk;
-  if (superelem->is_array_klass())
+  if (superelem->is_array_klass()) {
+    ciArrayKlass* ak = superelem->as_array_klass();
     superelem = superelem->as_array_klass()->base_element_type();
+  }
 
   if (!subk->is_interface()) {  // cannot trust static interface types yet
     if (subk->is_subtype_of(superk)) {
       return SSC_always_true;   // (1) false path dead; no dynamic test needed
     }
@@ -4442,10 +4871,31 @@
     igvn.check_no_speculative_types();
 #endif
   }
 }
 
+Node* Compile::optimize_acmp(PhaseGVN* phase, Node* a, Node* b) {
+  const TypeInstPtr* ta = phase->type(a)->isa_instptr();
+  const TypeInstPtr* tb = phase->type(b)->isa_instptr();
+  if (!EnableValhalla || ta == NULL || tb == NULL ||
+      ta->is_zero_type() || tb->is_zero_type() ||
+      !ta->can_be_inline_type() || !tb->can_be_inline_type()) {
+    // Use old acmp if one operand is null or not an inline type
+    return new CmpPNode(a, b);
+  } else if (ta->is_inlinetypeptr() || tb->is_inlinetypeptr()) {
+    // We know that one operand is an inline type. Therefore,
+    // new acmp will only return true if both operands are NULL.
+    // Check if both operands are null by or'ing the oops.
+    a = phase->transform(new CastP2XNode(NULL, a));
+    b = phase->transform(new CastP2XNode(NULL, b));
+    a = phase->transform(new OrXNode(a, b));
+    return new CmpXNode(a, phase->MakeConX(0));
+  }
+  // Use new acmp
+  return NULL;
+}
+
 // Auxiliary method to support randomized stressing/fuzzing.
 //
 // This method can be called the arbitrary number of times, with current count
 // as the argument. The logic allows selecting a single candidate from the
 // running list of candidates as follows:
diff a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp
--- a/src/hotspot/share/opto/compile.hpp
+++ b/src/hotspot/share/opto/compile.hpp
@@ -46,10 +46,11 @@
 
 class AddPNode;
 class Block;
 class Bundle;
 class CallGenerator;
+class CallNode;
 class CloneMap;
 class ConnectionGraph;
 class IdealGraphPrinter;
 class InlineTree;
 class Int_Array;
@@ -83,10 +84,11 @@
 class TypePtr;
 class TypeOopPtr;
 class TypeFunc;
 class TypeVect;
 class Unique_Node_List;
+class InlineTypeBaseNode;
 class nmethod;
 class WarmCallInfo;
 class Node_Stack;
 struct Final_Reshape_Counts;
 
@@ -299,10 +301,12 @@
   // JSR 292
   bool                  _has_method_handle_invokes; // True if this method has MethodHandle invokes.
   RTMState              _rtm_state;             // State of Restricted Transactional Memory usage
   int                   _loop_opts_cnt;         // loop opts round
   bool                  _clinit_barrier_on_entry; // True if clinit barrier is needed on nmethod entry
+  bool                  _has_flattened_accesses; // Any known flattened array accesses?
+  bool                  _flattened_accesses_share_alias; // Initially all flattened array share a single slice
 
   // Compilation environment.
   Arena                 _comp_arena;            // Arena with lifetime equivalent to Compile
   void*                 _barrier_set_state;     // Potential GC barrier state for Compile
   ciEnv*                _env;                   // CI interface
@@ -313,10 +317,11 @@
   GrowableArray<Node*>* _macro_nodes;           // List of nodes which need to be expanded before matching.
   GrowableArray<Node*>* _predicate_opaqs;       // List of Opaque1 nodes for the loop predicates.
   GrowableArray<Node*>* _expensive_nodes;       // List of nodes that are expensive to compute and that we'd better not let the GVN freely common
   GrowableArray<Node*>* _range_check_casts;     // List of CastII nodes with a range check dependency
   GrowableArray<Node*>* _opaque4_nodes;         // List of Opaque4 nodes that have a default value
+  GrowableArray<Node*>* _inline_type_nodes;     // List of InlineType nodes
   ConnectionGraph*      _congraph;
 #ifndef PRODUCT
   IdealGraphPrinter*    _printer;
   static IdealGraphPrinter* _debug_file_printer;
   static IdealGraphPrinter* _debug_network_printer;
@@ -592,10 +597,17 @@
   bool          profile_rtm() const              { return _rtm_state == ProfileRTM; }
   uint              max_node_limit() const       { return (uint)_max_node_limit; }
   void          set_max_node_limit(uint n)       { _max_node_limit = n; }
   bool              clinit_barrier_on_entry()       { return _clinit_barrier_on_entry; }
   void          set_clinit_barrier_on_entry(bool z) { _clinit_barrier_on_entry = z; }
+  void          set_flattened_accesses()         { _has_flattened_accesses = true; }
+  bool          flattened_accesses_share_alias() const { return _flattened_accesses_share_alias; }
+  void          set_flattened_accesses_share_alias(bool z) { _flattened_accesses_share_alias = z; }
+
+  // Support for scalarized inline type calling convention
+  bool              has_scalarized_args() const  { return _method != NULL && _method->has_scalarized_args(); }
+  bool              needs_stack_repair()  const  { return _method != NULL && _method->get_Method()->c2_needs_stack_repair(); }
 
   // check the CompilerOracle for special behaviours for this compile
   bool          method_has_option(const char * option) {
     return method() != NULL && method()->has_option(option);
   }
@@ -702,10 +714,17 @@
   }
   Node* opaque4_node(int idx) const { return _opaque4_nodes->at(idx);  }
   int   opaque4_count()       const { return _opaque4_nodes->length(); }
   void  remove_opaque4_nodes(PhaseIterGVN &igvn);
 
+  // Keep track of inline type nodes for later processing
+  void add_inline_type(Node* n);
+  void remove_inline_type(Node* n);
+  void process_inline_types(PhaseIterGVN &igvn, bool post_ea = false);
+
+  void adjust_flattened_array_access_aliases(PhaseIterGVN& igvn);
+
   void sort_macro_nodes();
 
   // remove the opaque nodes that protect the predicates so that the unused checks and
   // uncommon traps will be eliminated from the graph.
   void cleanup_loop_predicates(PhaseIterGVN &igvn);
@@ -842,15 +861,15 @@
     _last_tf_m = m;
     _last_tf = tf;
   }
 
   AliasType*        alias_type(int                idx)  { assert(idx < num_alias_types(), "oob"); return _alias_types[idx]; }
-  AliasType*        alias_type(const TypePtr* adr_type, ciField* field = NULL) { return find_alias_type(adr_type, false, field); }
+  AliasType*        alias_type(const TypePtr* adr_type, ciField* field = NULL, bool uncached = false) { return find_alias_type(adr_type, false, field, uncached); }
   bool         have_alias_type(const TypePtr* adr_type);
   AliasType*        alias_type(ciField*         field);
 
-  int               get_alias_index(const TypePtr* at)  { return alias_type(at)->index(); }
+  int               get_alias_index(const TypePtr* at, bool uncached = false) { return alias_type(at, NULL, uncached)->index(); }
   const TypePtr*    get_adr_type(uint aidx)             { return alias_type(aidx)->adr_type(); }
   int               get_general_index(uint aidx)        { return alias_type(aidx)->general_index(); }
 
   // Building nodes
   void              rethrow_exceptions(JVMState* jvms);
@@ -1070,11 +1089,11 @@
 
   // Management of the AliasType table.
   void grow_alias_types();
   AliasCacheEntry* probe_alias_cache(const TypePtr* adr_type);
   const TypePtr *flatten_alias_type(const TypePtr* adr_type) const;
-  AliasType* find_alias_type(const TypePtr* adr_type, bool no_create, ciField* field);
+  AliasType* find_alias_type(const TypePtr* adr_type, bool no_create, ciField* field, bool uncached = false);
 
   void verify_top(Node*) const PRODUCT_RETURN;
 
   // Intrinsic setup.
   void           register_library_intrinsics();                            // initializer
@@ -1143,10 +1162,12 @@
                               Node* ctrl = NULL);
 
   // Convert integer value to a narrowed long type dependent on ctrl (for example, a range check)
   static Node* constrained_convI2L(PhaseGVN* phase, Node* value, const TypeInt* itype, Node* ctrl);
 
+  Node* optimize_acmp(PhaseGVN* phase, Node* a, Node* b);
+
   // Auxiliary method for randomized fuzzing/stressing
   static bool randomized_select(int count);
 
   // supporting clone_map
   CloneMap&     clone_map();
diff a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -21,10 +21,12 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "ci/ciFlatArrayKlass.hpp"
+#include "ci/ciInlineKlass.hpp"
 #include "ci/ciUtilities.hpp"
 #include "classfile/javaClasses.hpp"
 #include "compiler/compileLog.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/c2/barrierSetC2.hpp"
@@ -33,13 +35,15 @@
 #include "opto/addnode.hpp"
 #include "opto/castnode.hpp"
 #include "opto/convertnode.hpp"
 #include "opto/graphKit.hpp"
 #include "opto/idealKit.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/intrinsicnode.hpp"
 #include "opto/locknode.hpp"
 #include "opto/machnode.hpp"
+#include "opto/narrowptrnode.hpp"
 #include "opto/opaquenode.hpp"
 #include "opto/parse.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/runtime.hpp"
 #include "opto/subtypenode.hpp"
@@ -48,19 +52,27 @@
 #include "utilities/bitMap.inline.hpp"
 #include "utilities/powerOfTwo.hpp"
 
 //----------------------------GraphKit-----------------------------------------
 // Main utility constructor.
-GraphKit::GraphKit(JVMState* jvms)
+GraphKit::GraphKit(JVMState* jvms, PhaseGVN* gvn)
   : Phase(Phase::Parser),
     _env(C->env()),
-    _gvn(*C->initial_gvn()),
+    _gvn((gvn != NULL) ? *gvn : *C->initial_gvn()),
     _barrier_set(BarrierSet::barrier_set()->barrier_set_c2())
 {
+  assert(gvn == NULL || !gvn->is_IterGVN() || gvn->is_IterGVN()->delay_transform(), "delay transform should be enabled");
   _exceptions = jvms->map()->next_exception();
   if (_exceptions != NULL)  jvms->map()->set_next_exception(NULL);
   set_jvms(jvms);
+#ifdef ASSERT
+  if (_gvn.is_IterGVN() != NULL) {
+    assert(_gvn.is_IterGVN()->delay_transform(), "Transformation must be delayed if IterGVN is used");
+    // Save the initial size of _for_igvn worklist for verification (see ~GraphKit)
+    _worklist_size = _gvn.C->for_igvn()->size();
+  }
+#endif
 }
 
 // Private constructor for parser.
 GraphKit::GraphKit()
   : Phase(Phase::Parser),
@@ -825,20 +837,21 @@
   ciMethod* cur_method = jvms->method();
   int       cur_bci   = jvms->bci();
   if (cur_method != NULL && cur_bci != InvocationEntryBci) {
     Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci);
     return Interpreter::bytecode_should_reexecute(code) ||
-           (is_anewarray && code == Bytecodes::_multianewarray);
+           (is_anewarray && (code == Bytecodes::_multianewarray));
     // Reexecute _multianewarray bytecode which was replaced with
     // sequence of [a]newarray. See Parse::do_multianewarray().
     //
     // Note: interpreter should not have it set since this optimization
     // is limited by dimensions and guarded by flag so in some cases
     // multianewarray() runtime calls will be generated and
     // the bytecode should not be reexecutes (stack will not be reset).
-  } else
+  } else {
     return false;
+  }
 }
 
 // Helper function for adding JVMState and debug information to node
 void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
   // Add the safepoint edges to the call (or other safepoint).
@@ -1078,10 +1091,19 @@
       assert(rsize == 1, "");
       depth = rsize - inputs;
     }
     break;
 
+  case Bytecodes::_withfield: {
+    bool ignored_will_link;
+    ciField* field = method()->get_field_at_bci(bci(), ignored_will_link);
+    int      size  = field->type()->size();
+    inputs = size+1;
+    depth = rsize - inputs;
+    break;
+  }
+
   case Bytecodes::_ireturn:
   case Bytecodes::_lreturn:
   case Bytecodes::_freturn:
   case Bytecodes::_dreturn:
   case Bytecodes::_areturn:
@@ -1160,11 +1182,11 @@
 Node* GraphKit::load_object_klass(Node* obj) {
   // Special-case a fresh allocation to avoid building nodes:
   Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
   if (akls != NULL)  return akls;
   Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
-  return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
+  return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
 }
 
 //-------------------------load_array_length-----------------------------------
 Node* GraphKit::load_array_length(Node* array) {
   // Special-case a fresh allocation to avoid building nodes:
@@ -1203,10 +1225,11 @@
   // Construct NULL check
   Node *chk = NULL;
   switch(type) {
     case T_LONG   : chk = new CmpLNode(value, _gvn.zerocon(T_LONG)); break;
     case T_INT    : chk = new CmpINode(value, _gvn.intcon(0)); break;
+    case T_INLINE_TYPE : // fall through
     case T_ARRAY  : // fall through
       type = T_OBJECT;  // simplify further tests
     case T_OBJECT : {
       const Type *t = _gvn.type( value );
 
@@ -1374,23 +1397,47 @@
   }
 
   return value;
 }
 
+Node* GraphKit::null2default(Node* value, ciInlineKlass* vk) {
+  assert(!vk->is_scalarizable(), "Should only be used for non scalarizable inline klasses");
+  Node* null_ctl = top();
+  value = null_check_oop(value, &null_ctl);
+  if (!null_ctl->is_top()) {
+    // Return default value if oop is null
+    Node* region = new RegionNode(3);
+    region->init_req(1, control());
+    region->init_req(2, null_ctl);
+    value = PhiNode::make(region, value, TypeInstPtr::make(TypePtr::BotPTR, vk));
+    value->set_req(2, InlineTypeNode::default_oop(gvn(), vk));
+    set_control(gvn().transform(region));
+    value = gvn().transform(value);
+  }
+  return value;
+}
 
 //------------------------------cast_not_null----------------------------------
 // Cast obj to not-null on this path
 Node* GraphKit::cast_not_null(Node* obj, bool do_replace_in_map) {
+  if (obj->is_InlineType()) {
+    return obj;
+  }
   const Type *t = _gvn.type(obj);
   const Type *t_not_null = t->join_speculative(TypePtr::NOTNULL);
   // Object is already not-null?
   if( t == t_not_null ) return obj;
 
   Node *cast = new CastPPNode(obj,t_not_null);
   cast->init_req(0, control());
   cast = _gvn.transform( cast );
 
+  if (t->is_inlinetypeptr() && t->inline_klass()->is_scalarizable()) {
+    // Scalarize inline type now that we know it's non-null
+    cast = InlineTypeNode::make_from_oop(this, cast, t->inline_klass())->as_ptr(&gvn());
+  }
+
   // Scan for instances of 'obj' in the current JVM mapping.
   // These instances are known to be not-null after the test.
   if (do_replace_in_map)
     replace_in_map(obj, cast);
 
@@ -1510,11 +1557,12 @@
     ld = LoadDNode::make_atomic(ctl, mem, adr, adr_type, t, mo, control_dependency, unaligned, mismatched, unsafe, barrier_data);
   } else {
     ld = LoadNode::make(_gvn, ctl, mem, adr, adr_type, t, bt, mo, control_dependency, unaligned, mismatched, unsafe, barrier_data);
   }
   ld = _gvn.transform(ld);
-  if (((bt == T_OBJECT) && C->do_escape_analysis()) || C->eliminate_boxing()) {
+
+  if (((bt == T_OBJECT || bt == T_INLINE_TYPE) && C->do_escape_analysis()) || C->eliminate_boxing()) {
     // Improve graph before escape analysis and boxing elimination.
     record_for_igvn(ld);
   }
   return ld;
 }
@@ -1561,11 +1609,12 @@
                                 Node* adr,
                                 const TypePtr* adr_type,
                                 Node* val,
                                 const Type* val_type,
                                 BasicType bt,
-                                DecoratorSet decorators) {
+                                DecoratorSet decorators,
+                                bool safe_for_replace) {
   // Transformation of a value which could be NULL pointer (CastPP #NULL)
   // could be delayed during Parse (for example, in adjust_map_after_if()).
   // Execute transformation here to avoid barrier generation in such case.
   if (_gvn.type(val) == TypePtr::NULL_PTR) {
     val = _gvn.makecon(TypePtr::NULL_PTR);
@@ -1574,10 +1623,17 @@
   if (stopped()) {
     return top(); // Dead path ?
   }
 
   assert(val != NULL, "not dead path");
+  if (val->is_InlineType()) {
+    // Store to non-flattened field. Buffer the inline type and make sure
+    // the store is re-executed if the allocation triggers deoptimization.
+    PreserveReexecuteState preexecs(this);
+    jvms()->set_should_reexecute(true);
+    val = val->as_InlineType()->buffer(this, safe_for_replace);
+  }
 
   C2AccessValuePtr addr(adr, adr_type);
   C2AccessValue value(val, val_type);
   C2ParseAccess access(this, decorators | C2_WRITE_ACCESS, bt, obj, addr);
   if (access.is_raw()) {
@@ -1590,17 +1646,18 @@
 Node* GraphKit::access_load_at(Node* obj,   // containing obj
                                Node* adr,   // actual adress to store val at
                                const TypePtr* adr_type,
                                const Type* val_type,
                                BasicType bt,
-                               DecoratorSet decorators) {
+                               DecoratorSet decorators,
+                               Node* ctl) {
   if (stopped()) {
     return top(); // Dead path ?
   }
 
   C2AccessValuePtr addr(adr, adr_type);
-  C2ParseAccess access(this, decorators | C2_READ_ACCESS, bt, obj, addr);
+  C2ParseAccess access(this, decorators | C2_READ_ACCESS, bt, obj, addr, ctl);
   if (access.is_raw()) {
     return _barrier_set->BarrierSetC2::load_at(access, val_type);
   } else {
     return _barrier_set->load_at(access, val_type);
   }
@@ -1694,18 +1751,23 @@
   } else {
     return _barrier_set->atomic_add_at(access, new_val, value_type);
   }
 }
 
-void GraphKit::access_clone(Node* src, Node* dst, Node* size, bool is_array) {
-  return _barrier_set->clone(this, src, dst, size, is_array);
+void GraphKit::access_clone(Node* src_base, Node* dst_base, Node* countx, bool is_array) {
+  return _barrier_set->clone(this, src_base, dst_base, countx, is_array);
 }
 
 //-------------------------array_element_address-------------------------
 Node* GraphKit::array_element_address(Node* ary, Node* idx, BasicType elembt,
                                       const TypeInt* sizetype, Node* ctrl) {
   uint shift  = exact_log2(type2aelembytes(elembt));
+  ciKlass* arytype_klass = _gvn.type(ary)->is_aryptr()->klass();
+  if (arytype_klass != NULL && arytype_klass->is_flat_array_klass()) {
+    ciFlatArrayKlass* vak = arytype_klass->as_flat_array_klass();
+    shift = vak->log2_element_size();
+  }
   uint header = arrayOopDesc::base_offset_in_bytes(elembt);
 
   // short-circuit a common case (saves lots of confusing waste motion)
   jint idx_con = find_int_con(idx, -1);
   if (idx_con >= 0) {
@@ -1722,26 +1784,61 @@
 
 //-------------------------load_array_element-------------------------
 Node* GraphKit::load_array_element(Node* ctl, Node* ary, Node* idx, const TypeAryPtr* arytype) {
   const Type* elemtype = arytype->elem();
   BasicType elembt = elemtype->array_element_basic_type();
+  assert(elembt != T_INLINE_TYPE, "inline types are not supported by this method");
   Node* adr = array_element_address(ary, idx, elembt, arytype->size());
   if (elembt == T_NARROWOOP) {
     elembt = T_OBJECT; // To satisfy switch in LoadNode::make()
   }
   Node* ld = make_load(ctl, adr, elemtype, elembt, arytype, MemNode::unordered);
   return ld;
 }
 
 //-------------------------set_arguments_for_java_call-------------------------
 // Arguments (pre-popped from the stack) are taken from the JVMS.
-void GraphKit::set_arguments_for_java_call(CallJavaNode* call) {
-  // Add the call arguments:
-  uint nargs = call->method()->arg_size();
-  for (uint i = 0; i < nargs; i++) {
-    Node* arg = argument(i);
-    call->init_req(i + TypeFunc::Parms, arg);
+void GraphKit::set_arguments_for_java_call(CallJavaNode* call, bool is_late_inline) {
+  PreserveReexecuteState preexecs(this);
+  if (EnableValhalla) {
+    // Make sure the call is re-executed, if buffering of inline type arguments triggers deoptimization
+    jvms()->set_should_reexecute(true);
+    int arg_size = method()->get_declared_signature_at_bci(bci())->arg_size_for_bc(java_bc());
+    inc_sp(arg_size);
+  }
+  // Add the call arguments
+  const TypeTuple* domain = call->tf()->domain_sig();
+  ExtendedSignature sig_cc = ExtendedSignature(call->method()->get_sig_cc(), SigEntryFilter());
+  uint nargs = domain->cnt();
+  for (uint i = TypeFunc::Parms, idx = TypeFunc::Parms; i < nargs; i++) {
+    Node* arg = argument(i-TypeFunc::Parms);
+    const Type* t = domain->field_at(i);
+    if (call->method()->has_scalarized_args() && t->is_inlinetypeptr() && !t->maybe_null()) {
+      // We don't pass inline type arguments by reference but instead pass each field of the inline type
+      InlineTypeNode* vt = arg->as_InlineType();
+      vt->pass_fields(this, call, sig_cc, idx);
+      // If an inline type argument is passed as fields, attach the Method* to the call site
+      // to be able to access the extended signature later via attached_method_before_pc().
+      // For example, see CompiledMethod::preserve_callee_argument_oops().
+      call->set_override_symbolic_info(true);
+      continue;
+    } else if (arg->is_InlineType()) {
+      // Pass inline type argument via oop to callee
+      arg = arg->as_InlineType()->buffer(this);
+      if (!is_late_inline) {
+        arg = arg->as_InlineTypePtr()->get_oop();
+      }
+    }
+    call->init_req(idx++, arg);
+    // Skip reserved arguments
+    BasicType bt = t->basic_type();
+    while (SigEntry::next_is_reserved(sig_cc, bt, true)) {
+      call->init_req(idx++, top());
+      if (type2size[bt] == 2) {
+        call->init_req(idx++, top());
+      }
+    }
   }
 }
 
 //---------------------------set_edges_for_java_call---------------------------
 // Connect a newly created call into the current JVMS.
@@ -1775,17 +1872,10 @@
 }
 
 Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj, bool deoptimize) {
   if (stopped())  return top();  // maybe the call folded up?
 
-  // Capture the return value, if any.
-  Node* ret;
-  if (call->method() == NULL ||
-      call->method()->return_type()->basic_type() == T_VOID)
-        ret = top();
-  else  ret = _gvn.transform(new ProjNode(call, TypeFunc::Parms));
-
   // Note:  Since any out-of-line call can produce an exception,
   // we always insert an I_O projection from the call into the result.
 
   make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj, deoptimize);
 
@@ -1794,10 +1884,29 @@
     // through and exceptional paths, so replace the projections for
     // the fall through path.
     set_i_o(_gvn.transform( new ProjNode(call, TypeFunc::I_O) ));
     set_all_memory(_gvn.transform( new ProjNode(call, TypeFunc::Memory) ));
   }
+
+  // Capture the return value, if any.
+  Node* ret;
+  if (call->method() == NULL || call->method()->return_type()->basic_type() == T_VOID) {
+    ret = top();
+  } else if (call->tf()->returns_inline_type_as_fields()) {
+    // Return of multiple values (inline type fields): we create a
+    // InlineType node, each field is a projection from the call.
+    ciInlineKlass* vk = call->method()->return_type()->as_inline_klass();
+    const Array<SigEntry>* sig_array = vk->extended_sig();
+    GrowableArray<SigEntry> sig = GrowableArray<SigEntry>(sig_array->length());
+    sig.appendAll(sig_array);
+    ExtendedSignature sig_cc = ExtendedSignature(&sig, SigEntryFilter());
+    uint base_input = TypeFunc::Parms + 1;
+    ret = InlineTypeNode::make_from_multi(this, call, sig_cc, vk, base_input, false);
+  } else {
+    ret = _gvn.transform(new ProjNode(call, TypeFunc::Parms));
+  }
+
   return ret;
 }
 
 //--------------------set_predefined_input_for_runtime_call--------------------
 // Reading and setting the memory state is way conservative here.
@@ -1884,80 +1993,80 @@
   Node* ex_ctl = top();
 
   SafePointNode* final_state = stop();
 
   // Find all the needed outputs of this call
-  CallProjections callprojs;
-  call->extract_projections(&callprojs, true);
+  CallProjections* callprojs = call->extract_projections(true);
 
   Unique_Node_List wl;
   Node* init_mem = call->in(TypeFunc::Memory);
   Node* final_mem = final_state->in(TypeFunc::Memory);
   Node* final_ctl = final_state->in(TypeFunc::Control);
   Node* final_io = final_state->in(TypeFunc::I_O);
 
   // Replace all the old call edges with the edges from the inlining result
-  if (callprojs.fallthrough_catchproj != NULL) {
-    C->gvn_replace_by(callprojs.fallthrough_catchproj, final_ctl);
+  if (callprojs->fallthrough_catchproj != NULL) {
+    C->gvn_replace_by(callprojs->fallthrough_catchproj, final_ctl);
   }
-  if (callprojs.fallthrough_memproj != NULL) {
+  if (callprojs->fallthrough_memproj != NULL) {
     if (final_mem->is_MergeMem()) {
       // Parser's exits MergeMem was not transformed but may be optimized
       final_mem = _gvn.transform(final_mem);
     }
-    C->gvn_replace_by(callprojs.fallthrough_memproj,   final_mem);
+    C->gvn_replace_by(callprojs->fallthrough_memproj,   final_mem);
     add_mergemem_users_to_worklist(wl, final_mem);
   }
-  if (callprojs.fallthrough_ioproj != NULL) {
-    C->gvn_replace_by(callprojs.fallthrough_ioproj,    final_io);
+  if (callprojs->fallthrough_ioproj != NULL) {
+    C->gvn_replace_by(callprojs->fallthrough_ioproj,    final_io);
   }
 
   // Replace the result with the new result if it exists and is used
-  if (callprojs.resproj != NULL && result != NULL) {
-    C->gvn_replace_by(callprojs.resproj, result);
+  if (callprojs->resproj[0] != NULL && result != NULL) {
+    assert(callprojs->nb_resproj == 1, "unexpected number of results");
+    C->gvn_replace_by(callprojs->resproj[0], result);
   }
 
   if (ejvms == NULL) {
     // No exception edges to simply kill off those paths
-    if (callprojs.catchall_catchproj != NULL) {
-      C->gvn_replace_by(callprojs.catchall_catchproj, C->top());
+    if (callprojs->catchall_catchproj != NULL) {
+      C->gvn_replace_by(callprojs->catchall_catchproj, C->top());
     }
-    if (callprojs.catchall_memproj != NULL) {
-      C->gvn_replace_by(callprojs.catchall_memproj,   C->top());
+    if (callprojs->catchall_memproj != NULL) {
+      C->gvn_replace_by(callprojs->catchall_memproj,   C->top());
     }
-    if (callprojs.catchall_ioproj != NULL) {
-      C->gvn_replace_by(callprojs.catchall_ioproj,    C->top());
+    if (callprojs->catchall_ioproj != NULL) {
+      C->gvn_replace_by(callprojs->catchall_ioproj,    C->top());
     }
     // Replace the old exception object with top
-    if (callprojs.exobj != NULL) {
-      C->gvn_replace_by(callprojs.exobj, C->top());
+    if (callprojs->exobj != NULL) {
+      C->gvn_replace_by(callprojs->exobj, C->top());
     }
   } else {
     GraphKit ekit(ejvms);
 
     // Load my combined exception state into the kit, with all phis transformed:
     SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states();
     replaced_nodes_exception = ex_map->replaced_nodes();
 
     Node* ex_oop = ekit.use_exception_state(ex_map);
 
-    if (callprojs.catchall_catchproj != NULL) {
-      C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control());
+    if (callprojs->catchall_catchproj != NULL) {
+      C->gvn_replace_by(callprojs->catchall_catchproj, ekit.control());
       ex_ctl = ekit.control();
     }
-    if (callprojs.catchall_memproj != NULL) {
+    if (callprojs->catchall_memproj != NULL) {
       Node* ex_mem = ekit.reset_memory();
-      C->gvn_replace_by(callprojs.catchall_memproj,   ex_mem);
+      C->gvn_replace_by(callprojs->catchall_memproj,   ex_mem);
       add_mergemem_users_to_worklist(wl, ex_mem);
     }
-    if (callprojs.catchall_ioproj != NULL) {
-      C->gvn_replace_by(callprojs.catchall_ioproj,    ekit.i_o());
+    if (callprojs->catchall_ioproj != NULL) {
+      C->gvn_replace_by(callprojs->catchall_ioproj,    ekit.i_o());
     }
 
     // Replace the old exception object with the newly created one
-    if (callprojs.exobj != NULL) {
-      C->gvn_replace_by(callprojs.exobj, ex_oop);
+    if (callprojs->exobj != NULL) {
+      C->gvn_replace_by(callprojs->exobj, ex_oop);
     }
   }
 
   // Disconnect the call from the graph
   call->disconnect_inputs(NULL, C);
@@ -1967,11 +2076,11 @@
   // optimizer doesn't like that.
   while (wl.size() > 0) {
     _gvn.transform(wl.pop());
   }
 
-  if (callprojs.fallthrough_catchproj != NULL && !final_ctl->is_top() && do_replaced_nodes) {
+  if (callprojs->fallthrough_catchproj != NULL && !final_ctl->is_top() && do_replaced_nodes) {
     replaced_nodes.apply(C, final_ctl);
   }
   if (!ex_ctl->is_top() && do_replaced_nodes) {
     replaced_nodes_exception.apply(C, ex_ctl);
   }
@@ -2188,11 +2297,11 @@
   }
 
   if (speculative != current_type->speculative()) {
     // Build a type with a speculative type (what we think we know
     // about the type but will need a guard when we use it)
-    const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::OffsetBot, TypeOopPtr::InstanceBot, speculative);
+    const TypeOopPtr* spec_type = TypeOopPtr::make(TypePtr::BotPTR, Type::Offset::bottom, TypeOopPtr::InstanceBot, speculative);
     // We're changing the type, we need a new CheckCast node to carry
     // the new type. The new type depends on the control: what
     // profiling tells us is only valid from here as far as we can
     // tell.
     Node* cast = new CheckCastPPNode(control(), n, current_type->remove_speculative()->join_speculative(spec_type));
@@ -2222,23 +2331,34 @@
        java_bc() == Bytecodes::_instanceof ||
        java_bc() == Bytecodes::_aastore) &&
       method()->method_data()->is_mature()) {
     ciProfileData* data = method()->method_data()->bci_to_data(bci());
     if (data != NULL) {
-      if (!data->as_BitData()->null_seen()) {
-        ptr_kind = ProfileNeverNull;
+      if (java_bc() == Bytecodes::_aastore) {
+        ciKlass* array_type = NULL;
+        ciKlass* element_type = NULL;
+        ProfilePtrKind element_ptr = ProfileMaybeNull;
+        bool flat_array = true;
+        bool null_free_array = true;
+        method()->array_access_profiled_type(bci(), array_type, element_type, element_ptr, flat_array, null_free_array);
+        exact_kls = element_type;
+        ptr_kind = element_ptr;
       } else {
-        assert(data->is_ReceiverTypeData(), "bad profile data type");
-        ciReceiverTypeData* call = (ciReceiverTypeData*)data->as_ReceiverTypeData();
-        uint i = 0;
-        for (; i < call->row_limit(); i++) {
-          ciKlass* receiver = call->receiver(i);
-          if (receiver != NULL) {
-            break;
+        if (!data->as_BitData()->null_seen()) {
+          ptr_kind = ProfileNeverNull;
+        } else {
+          assert(data->is_ReceiverTypeData(), "bad profile data type");
+          ciReceiverTypeData* call = (ciReceiverTypeData*)data->as_ReceiverTypeData();
+          uint i = 0;
+          for (; i < call->row_limit(); i++) {
+            ciKlass* receiver = call->receiver(i);
+            if (receiver != NULL) {
+              break;
+            }
           }
+          ptr_kind = (i == call->row_limit()) ? ProfileAlwaysNull : ProfileMaybeNull;
         }
-        ptr_kind = (i == call->row_limit()) ? ProfileAlwaysNull : ProfileMaybeNull;
       }
     }
   }
   return record_profile_for_speculation(n, exact_kls, ptr_kind);
 }
@@ -2253,14 +2373,14 @@
 void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc) {
   if (!UseTypeSpeculation) {
     return;
   }
   const TypeFunc* tf    = TypeFunc::make(dest_method);
-  int             nargs = tf->domain()->cnt() - TypeFunc::Parms;
+  int             nargs = tf->domain_sig()->cnt() - TypeFunc::Parms;
   int skip = Bytecodes::has_receiver(bc) ? 1 : 0;
   for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
-    const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms);
+    const Type *targ = tf->domain_sig()->field_at(j + TypeFunc::Parms);
     if (is_reference_type(targ->basic_type())) {
       ProfilePtrKind ptr_kind = ProfileMaybeNull;
       ciKlass* better_type = NULL;
       if (method()->argument_profiled_type(bci(), i, better_type, ptr_kind)) {
         record_profile_for_speculation(argument(j), better_type, ptr_kind);
@@ -2327,13 +2447,13 @@
 
 void GraphKit::round_double_arguments(ciMethod* dest_method) {
   if (Matcher::strict_fp_requires_explicit_rounding) {
     // (Note:  TypeFunc::make has a cache that makes this fast.)
     const TypeFunc* tf    = TypeFunc::make(dest_method);
-    int             nargs = tf->domain()->cnt() - TypeFunc::Parms;
+    int             nargs = tf->domain_sig()->cnt() - TypeFunc::Parms;
     for (int j = 0; j < nargs; j++) {
-      const Type *targ = tf->domain()->field_at(j + TypeFunc::Parms);
+      const Type *targ = tf->domain_sig()->field_at(j + TypeFunc::Parms);
       if (targ->basic_type() == T_DOUBLE) {
         // If any parameters are doubles, they must be rounded before
         // the call, dstore_rounding does gvn.transform
         Node *arg = argument(j);
         arg = dstore_rounding(arg);
@@ -2809,56 +2929,80 @@
   *ctrl = gvn.transform(r_ok_subtype);
   return gvn.transform(r_not_subtype);
 }
 
 Node* GraphKit::gen_subtype_check(Node* obj_or_subklass, Node* superklass) {
+  const Type* sub_t = _gvn.type(obj_or_subklass);
+  if (sub_t->isa_inlinetype()) {
+    obj_or_subklass = makecon(TypeKlassPtr::make(sub_t->inline_klass()));
+  }
   if (ExpandSubTypeCheckAtParseTime) {
     MergeMemNode* mem = merged_memory();
     Node* ctrl = control();
     Node* subklass = obj_or_subklass;
-    if (!_gvn.type(obj_or_subklass)->isa_klassptr()) {
+    if (!sub_t->isa_klassptr()) {
       subklass = load_object_klass(obj_or_subklass);
     }
-
     Node* n = Phase::gen_subtype_check(subklass, superklass, &ctrl, mem, _gvn);
     set_control(ctrl);
     return n;
   }
 
-  const TypePtr* adr_type = TypeKlassPtr::make(TypePtr::NotNull, C->env()->Object_klass(), Type::OffsetBot);
   Node* check = _gvn.transform(new SubTypeCheckNode(C, obj_or_subklass, superklass));
   Node* bol = _gvn.transform(new BoolNode(check, BoolTest::eq));
   IfNode* iff = create_and_xform_if(control(), bol, PROB_STATIC_FREQUENT, COUNT_UNKNOWN);
   set_control(_gvn.transform(new IfTrueNode(iff)));
   return _gvn.transform(new IfFalseNode(iff));
 }
 
 // Profile-driven exact type check:
 Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
-                                    float prob,
-                                    Node* *casted_receiver) {
+                                    float prob, Node* *casted_receiver) {
+  Node* fail = top();
+  const Type* rec_t = _gvn.type(receiver);
+  if (false && rec_t->isa_inlinetype()) {
+    if (klass->equals(rec_t->inline_klass())) {
+      (*casted_receiver) = receiver; // Always passes
+    } else {
+      (*casted_receiver) = top();    // Always fails
+      fail = control();
+      set_control(top());
+    }
+    return fail;
+  }
   const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
   Node* recv_klass = load_object_klass(receiver);
-  Node* want_klass = makecon(tklass);
-  Node* cmp = _gvn.transform( new CmpPNode(recv_klass, want_klass) );
-  Node* bol = _gvn.transform( new BoolNode(cmp, BoolTest::eq) );
-  IfNode* iff = create_and_xform_if(control(), bol, prob, COUNT_UNKNOWN);
-  set_control( _gvn.transform( new IfTrueNode (iff) ));
-  Node* fail = _gvn.transform( new IfFalseNode(iff) );
-
+  fail = type_check(recv_klass, tklass, prob);
   const TypeOopPtr* recv_xtype = tklass->as_instance_type();
   assert(recv_xtype->klass_is_exact(), "");
 
   // Subsume downstream occurrences of receiver with a cast to
   // recv_xtype, since now we know what the type will be.
   Node* cast = new CheckCastPPNode(control(), receiver, recv_xtype);
-  (*casted_receiver) = _gvn.transform(cast);
+  Node* res = _gvn.transform(cast);
+  if (recv_xtype->is_inlinetypeptr() && recv_xtype->inline_klass()->is_scalarizable()) {
+    assert(!gvn().type(res)->maybe_null(), "receiver should never be null");
+    res = InlineTypeNode::make_from_oop(this, res, recv_xtype->inline_klass());
+  }
+
+  (*casted_receiver) = res;
   // (User must make the replace_in_map call.)
 
   return fail;
 }
 
+Node* GraphKit::type_check(Node* recv_klass, const TypeKlassPtr* tklass,
+                           float prob) {
+  Node* want_klass = makecon(tklass);
+  Node* cmp = _gvn.transform( new CmpPNode(recv_klass, want_klass));
+  Node* bol = _gvn.transform( new BoolNode(cmp, BoolTest::eq) );
+  IfNode* iff = create_and_xform_if(control(), bol, prob, COUNT_UNKNOWN);
+  set_control(  _gvn.transform( new IfTrueNode (iff)));
+  Node* fail = _gvn.transform( new IfFalseNode(iff));
+  return fail;
+}
+
 //------------------------------subtype_check_receiver-------------------------
 Node* GraphKit::subtype_check_receiver(Node* receiver, ciKlass* klass,
                                        Node** casted_receiver) {
   const TypeKlassPtr* tklass = TypeKlassPtr::make(klass);
   Node* want_klass = makecon(tklass);
@@ -2894,10 +3038,13 @@
       return true;
     // If the profile has not seen a null, assume it won't happen.
     assert(java_bc() == Bytecodes::_checkcast ||
            java_bc() == Bytecodes::_instanceof ||
            java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here");
+    if (java_bc() == Bytecodes::_aastore) {
+      return ((ciArrayLoadStoreData*)data->as_ArrayLoadStoreData())->element()->ptr_kind() == ProfileNeverNull;
+    }
     return !data->as_BitData()->null_seen();
   }
   speculating = false;
   return false;
 }
@@ -2973,11 +3120,24 @@
 
   // (No, this isn't a call, but it's enough like a virtual call
   // to use the same ciMethod accessor to get the profile info...)
   // If we have a speculative type use it instead of profiling (which
   // may not help us)
-  ciKlass* exact_kls = spec_klass == NULL ? profile_has_unique_klass() : spec_klass;
+  ciKlass* exact_kls = spec_klass;
+  if (exact_kls == NULL) {
+    if (java_bc() == Bytecodes::_aastore) {
+      ciKlass* array_type = NULL;
+      ciKlass* element_type = NULL;
+      ProfilePtrKind element_ptr = ProfileMaybeNull;
+      bool flat_array = true;
+      bool null_free_array = true;
+      method()->array_access_profiled_type(bci(), array_type, element_type, element_ptr, flat_array, null_free_array);
+      exact_kls = element_type;
+    } else {
+      exact_kls = profile_has_unique_klass();
+    }
+  }
   if (exact_kls != NULL) {// no cast failures here
     if (require_klass == NULL ||
         C->static_subtype_check(require_klass, exact_kls) == Compile::SSC_always_true) {
       // If we narrow the type to match what the type profile sees or
       // the speculative type, we can then remove the rest of the
@@ -3078,14 +3238,15 @@
     data = method()->method_data()->bci_to_data(bci());
   }
   bool speculative_not_null = false;
   bool never_see_null = (ProfileDynamicTypes  // aggressive use of profile
                          && seems_never_null(obj, data, speculative_not_null));
+  bool is_value = obj->is_InlineType();
 
   // Null check; get casted pointer; set region slot 3
   Node* null_ctl = top();
-  Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
+  Node* not_null_obj = is_value ? obj : null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
 
   // If not_null_obj is dead, only null-path is taken
   if (stopped()) {              // Doing instance-of on a NULL?
     set_control(null_ctl);
     return intcon(0);
@@ -3099,32 +3260,37 @@
     region->del_req(_null_path);
     phi   ->del_req(_null_path);
   }
 
   // Do we know the type check always succeed?
-  bool known_statically = false;
-  if (_gvn.type(superklass)->singleton()) {
-    ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
-    ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass();
-    if (subk != NULL && subk->is_loaded()) {
-      int static_res = C->static_subtype_check(superk, subk);
-      known_statically = (static_res == Compile::SSC_always_true || static_res == Compile::SSC_always_false);
+  if (!is_value) {
+    bool known_statically = false;
+    if (_gvn.type(superklass)->singleton()) {
+      ciKlass* superk = _gvn.type(superklass)->is_klassptr()->klass();
+      ciKlass* subk = _gvn.type(obj)->is_oopptr()->klass();
+      if (subk != NULL && subk->is_loaded()) {
+        int static_res = C->static_subtype_check(superk, subk);
+        known_statically = (static_res == Compile::SSC_always_true || static_res == Compile::SSC_always_false);
+      }
     }
-  }
-
-  if (!known_statically) {
-    const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
-    // We may not have profiling here or it may not help us. If we
-    // have a speculative type use it to perform an exact cast.
-    ciKlass* spec_obj_type = obj_type->speculative_type();
-    if (spec_obj_type != NULL || (ProfileDynamicTypes && data != NULL)) {
-      Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, NULL, spec_obj_type, safe_for_replace);
-      if (stopped()) {            // Profile disagrees with this path.
-        set_control(null_ctl);    // Null is the only remaining possibility.
-        return intcon(0);
-      }
-      if (cast_obj != NULL) {
+
+    if (!known_statically) {
+      const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
+      // We may not have profiling here or it may not help us. If we
+      // have a speculative type use it to perform an exact cast.
+      ciKlass* spec_obj_type = obj_type->speculative_type();
+      if (spec_obj_type != NULL || (ProfileDynamicTypes && data != NULL)) {
+        Node* cast_obj = maybe_cast_profiled_receiver(not_null_obj, NULL, spec_obj_type, safe_for_replace);
+        if (stopped()) {            // Profile disagrees with this path.
+          set_control(null_ctl);    // Null is the only remaining possibility.
+          return intcon(0);
+        }
+        if (cast_obj != NULL &&
+            // A value that's sometimes null is not something we can optimize well
+            !(cast_obj->is_InlineType() && null_ctl != top())) {
+          not_null_obj = cast_obj;
+          is_value = not_null_obj->is_InlineType();
         not_null_obj = cast_obj;
       }
     }
   }
 
@@ -3144,11 +3310,11 @@
   record_for_igvn(region);
 
   // If we know the type check always succeeds then we don't use the
   // profiling data at this bytecode. Don't lose it, feed it to the
   // type system as a speculative type.
-  if (safe_for_replace) {
+  if (safe_for_replace && !is_value) {
     Node* casted_obj = record_profiled_receiver_for_speculation(obj);
     replace_in_map(obj, casted_obj);
   }
 
   return _gvn.transform(phi);
@@ -3159,63 +3325,103 @@
 // array store bytecode.  Stack must be as-if BEFORE doing the bytecode so the
 // uncommon-trap paths work.  Adjust stack after this call.
 // If failure_control is supplied and not null, it is filled in with
 // the control edge for the cast failure.  Otherwise, an appropriate
 // uncommon trap or exception is thrown.
-Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
-                              Node* *failure_control) {
+Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_control) {
   kill_dead_locals();           // Benefit all the uncommon traps
-  const TypeKlassPtr *tk = _gvn.type(superklass)->is_klassptr();
-  const Type *toop = TypeOopPtr::make_from_klass(tk->klass());
+  const TypeKlassPtr* tk = _gvn.type(superklass)->is_klassptr();
+  const TypeOopPtr* toop = TypeOopPtr::make_from_klass(tk->klass());
+
+  // Check if inline types are involved
+  bool from_inline = obj->is_InlineType();
+  bool to_inline = tk->klass()->is_inlinetype();
 
   // Fast cutout:  Check the case that the cast is vacuously true.
   // This detects the common cases where the test will short-circuit
   // away completely.  We do this before we perform the null check,
   // because if the test is going to turn into zero code, we don't
   // want a residual null check left around.  (Causes a slowdown,
   // for example, in some objArray manipulations, such as a[i]=a[j].)
   if (tk->singleton()) {
-    const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr();
-    if (objtp != NULL && objtp->klass() != NULL) {
-      switch (C->static_subtype_check(tk->klass(), objtp->klass())) {
+    ciKlass* klass = NULL;
+    if (from_inline) {
+      klass = _gvn.type(obj)->inline_klass();
+    } else {
+      const TypeOopPtr* objtp = _gvn.type(obj)->isa_oopptr();
+      if (objtp != NULL) {
+        klass = objtp->klass();
+      }
+    }
+    if (klass != NULL) {
+      switch (C->static_subtype_check(tk->klass(), klass)) {
       case Compile::SSC_always_true:
         // If we know the type check always succeed then we don't use
         // the profiling data at this bytecode. Don't lose it, feed it
         // to the type system as a speculative type.
-        return record_profiled_receiver_for_speculation(obj);
+        if (!from_inline) {
+          obj = record_profiled_receiver_for_speculation(obj);
+          if (to_inline) {
+            obj = null_check(obj);
+            if (toop->inline_klass()->is_scalarizable()) {
+              obj = InlineTypeNode::make_from_oop(this, obj, toop->inline_klass());
+            }
+          }
+        }
+        return obj;
       case Compile::SSC_always_false:
-        // It needs a null check because a null will *pass* the cast check.
-        // A non-null value will always produce an exception.
-        return null_assert(obj);
+        if (from_inline || to_inline) {
+          if (!from_inline) {
+            null_check(obj);
+          }
+          // Inline type is never null. Always throw an exception.
+          builtin_throw(Deoptimization::Reason_class_check, makecon(TypeKlassPtr::make(klass)));
+          return top();
+        } else {
+          // It needs a null check because a null will *pass* the cast check.
+          return null_assert(obj);
+        }
       }
     }
   }
 
   ciProfileData* data = NULL;
   bool safe_for_replace = false;
   if (failure_control == NULL) {        // use MDO in regular case only
     assert(java_bc() == Bytecodes::_aastore ||
            java_bc() == Bytecodes::_checkcast,
            "interpreter profiles type checks only for these BCs");
-    data = method()->method_data()->bci_to_data(bci());
+    if (method()->method_data()->is_mature()) {
+      data = method()->method_data()->bci_to_data(bci());
+    }
     safe_for_replace = true;
   }
 
   // Make the merge point
   enum { _obj_path = 1, _null_path, PATH_LIMIT };
   RegionNode* region = new RegionNode(PATH_LIMIT);
   Node*       phi    = new PhiNode(region, toop);
+  _gvn.set_type(region, Type::CONTROL);
+  _gvn.set_type(phi, toop);
+
   C->set_has_split_ifs(true); // Has chance for split-if optimization
 
   // Use null-cast information if it is available
   bool speculative_not_null = false;
   bool never_see_null = ((failure_control == NULL)  // regular case only
                          && seems_never_null(obj, data, speculative_not_null));
 
   // Null check; get casted pointer; set region slot 3
   Node* null_ctl = top();
-  Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
+  Node* not_null_obj = NULL;
+  if (from_inline) {
+    not_null_obj = obj;
+  } else if (to_inline) {
+    not_null_obj = null_check(obj);
+  } else {
+    not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
+  }
 
   // If not_null_obj is dead, only null-path is taken
   if (stopped()) {              // Doing instance-of on a NULL?
     set_control(null_ctl);
     return null();
@@ -3229,21 +3435,28 @@
     region->del_req(_null_path);
     phi   ->del_req(_null_path);
   }
 
   Node* cast_obj = NULL;
-  if (tk->klass_is_exact()) {
+  if (!from_inline && tk->klass_is_exact()) {
     // The following optimization tries to statically cast the speculative type of the object
     // (for example obtained during profiling) to the type of the superklass and then do a
     // dynamic check that the type of the object is what we expect. To work correctly
     // for checkcast and aastore the type of superklass should be exact.
     const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
     // We may not have profiling here or it may not help us. If we have
     // a speculative type use it to perform an exact cast.
     ciKlass* spec_obj_type = obj_type->speculative_type();
     if (spec_obj_type != NULL || data != NULL) {
       cast_obj = maybe_cast_profiled_receiver(not_null_obj, tk->klass(), spec_obj_type, safe_for_replace);
+      if (cast_obj != NULL && cast_obj->is_InlineType()) {
+        if (null_ctl != top()) {
+          cast_obj = NULL; // A value that's sometimes null is not something we can optimize well
+        } else {
+          return cast_obj;
+        }
+      }
       if (cast_obj != NULL) {
         if (failure_control != NULL) // failure is now impossible
           (*failure_control) = top();
         // adjust the type of the phi to the exact klass:
         phi->raise_bottom_type(_gvn.type(cast_obj)->meet_speculative(TypePtr::NULL_PTR));
@@ -3251,20 +3464,26 @@
     }
   }
 
   if (cast_obj == NULL) {
     // Generate the subtype check
-    Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, superklass );
+    Node* not_subtype_ctrl = gen_subtype_check(not_null_obj, superklass);
 
     // Plug in success path into the merge
-    cast_obj = _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop));
+    cast_obj = from_inline ? not_null_obj : _gvn.transform(new CheckCastPPNode(control(), not_null_obj, toop));
     // Failure path ends in uncommon trap (or may be dead - failure impossible)
     if (failure_control == NULL) {
       if (not_subtype_ctrl != top()) { // If failure is possible
         PreserveJVMState pjvms(this);
         set_control(not_subtype_ctrl);
-        builtin_throw(Deoptimization::Reason_class_check, load_object_klass(not_null_obj));
+        Node* obj_klass = NULL;
+        if (from_inline) {
+          obj_klass = makecon(TypeKlassPtr::make(_gvn.type(not_null_obj)->inline_klass()));
+        } else {
+          obj_klass = load_object_klass(not_null_obj);
+        }
+        builtin_throw(Deoptimization::Reason_class_check, obj_klass);
       }
     } else {
       (*failure_control) = not_subtype_ctrl;
     }
   }
@@ -3287,11 +3506,133 @@
 
   // Return final merged results
   set_control( _gvn.transform(region) );
   record_for_igvn(region);
 
-  return record_profiled_receiver_for_speculation(res);
+  bool not_inline = !toop->can_be_inline_type();
+  bool not_flattened = !UseFlatArray || not_inline || (toop->is_inlinetypeptr() && !toop->inline_klass()->flatten_array());
+  if (EnableValhalla && not_flattened) {
+    // Check if obj has been loaded from an array
+    obj = obj->isa_DecodeN() ? obj->in(1) : obj;
+    Node* array = NULL;
+    if (obj->isa_Load()) {
+      Node* address = obj->in(MemNode::Address);
+      if (address->isa_AddP()) {
+        array = address->as_AddP()->in(AddPNode::Base);
+      }
+    } else if (obj->is_Phi()) {
+      Node* region = obj->in(0);
+      // TODO make this more robust (see JDK-8231346)
+      if (region->req() == 3 && region->in(2) != NULL && region->in(2)->in(0) != NULL) {
+        IfNode* iff = region->in(2)->in(0)->isa_If();
+        if (iff != NULL) {
+          iff->is_non_flattened_array_check(&_gvn, &array);
+        }
+      }
+    }
+    if (array != NULL) {
+      const TypeAryPtr* ary_t = _gvn.type(array)->isa_aryptr();
+      if (ary_t != NULL) {
+        if (!ary_t->is_not_null_free() && not_inline) {
+          // Casting array element to a non-inline-type, mark array as not null-free.
+          Node* cast = _gvn.transform(new CheckCastPPNode(control(), array, ary_t->cast_to_not_null_free()));
+          replace_in_map(array, cast);
+        } else if (!ary_t->is_not_flat()) {
+          // Casting array element to a non-flattened type, mark array as not flat.
+          Node* cast = _gvn.transform(new CheckCastPPNode(control(), array, ary_t->cast_to_not_flat()));
+          replace_in_map(array, cast);
+        }
+      }
+    }
+  }
+
+  if (!from_inline) {
+    res = record_profiled_receiver_for_speculation(res);
+    if (to_inline && toop->inline_klass()->is_scalarizable()) {
+      assert(!gvn().type(res)->maybe_null(), "Inline types are null-free");
+      res = InlineTypeNode::make_from_oop(this, res, toop->inline_klass());
+    }
+  }
+  return res;
+}
+
+// Check if 'obj' is an inline type by checking if it has the always_locked markWord pattern set.
+Node* GraphKit::is_inline_type(Node* obj) {
+  Node* mark_addr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes());
+  Node* mark = make_load(NULL, mark_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered);
+  Node* mask = _gvn.MakeConX(markWord::always_locked_pattern);
+  Node* andx = _gvn.transform(new AndXNode(mark, mask));
+  Node* cmp = _gvn.transform(new CmpXNode(andx, mask));
+  return _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+}
+
+// Check if 'ary' is a non-flattened array
+Node* GraphKit::is_non_flattened_array(Node* ary) {
+  Node* kls = load_object_klass(ary);
+  Node* tag = load_lh_array_tag(kls);
+  Node* cmp = gen_lh_array_test(kls, Klass::_lh_array_tag_vt_value);
+  return _gvn.transform(new BoolNode(cmp, BoolTest::ne));
+}
+
+// Check if 'ary' is a nullable array
+Node* GraphKit::is_nullable_array(Node* ary) {
+  Node* kls = load_object_klass(ary);
+  Node* lhp = basic_plus_adr(kls, in_bytes(Klass::layout_helper_offset()));
+  Node* layout_val = _gvn.transform(LoadNode::make(_gvn, NULL, immutable_memory(), lhp, lhp->bottom_type()->is_ptr(), TypeInt::INT, T_INT, MemNode::unordered));
+  Node* null_free = _gvn.transform(new RShiftINode(layout_val, intcon(Klass::_lh_null_free_shift)));
+  null_free = _gvn.transform(new AndINode(null_free, intcon(Klass::_lh_null_free_mask)));
+  Node* cmp = _gvn.transform(new CmpINode(null_free, intcon(0)));
+  return _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+}
+
+// Deoptimize if 'ary' is a null-free inline type array and 'val' is null
+Node* GraphKit::gen_inline_array_null_guard(Node* ary, Node* val, int nargs, bool safe_for_replace) {
+  const Type* val_t = _gvn.type(val);
+  if (val->is_InlineType() || !TypePtr::NULL_PTR->higher_equal(val_t)) {
+    return ary; // Never null
+  }
+  RegionNode* region = new RegionNode(3);
+  Node* null_ctl = top();
+  null_check_oop(val, &null_ctl);
+  if (null_ctl != top()) {
+    PreserveJVMState pjvms(this);
+    set_control(null_ctl);
+    {
+      // Deoptimize if null-free array
+      BuildCutout unless(this, is_nullable_array(ary), PROB_MAX);
+      inc_sp(nargs);
+      uncommon_trap(Deoptimization::Reason_null_check,
+                    Deoptimization::Action_none);
+    }
+    region->init_req(1, control());
+  }
+  region->init_req(2, control());
+  set_control(_gvn.transform(region));
+  record_for_igvn(region);
+  const TypeAryPtr* ary_t = _gvn.type(ary)->is_aryptr();
+  if (val_t == TypePtr::NULL_PTR && !ary_t->is_not_null_free()) {
+    // Since we were just successfully storing null, the array can't be null free.
+    ary_t = ary_t->cast_to_not_null_free();
+    Node* cast = _gvn.transform(new CheckCastPPNode(control(), ary, ary_t));
+    if (safe_for_replace) {
+      replace_in_map(ary, cast);
+    }
+    ary = cast;
+  }
+  return ary;
+}
+
+Node* GraphKit::load_lh_array_tag(Node* kls) {
+  Node* lhp = basic_plus_adr(kls, in_bytes(Klass::layout_helper_offset()));
+  Node* layout_val = _gvn.transform(LoadNode::make(_gvn, NULL, immutable_memory(), lhp, lhp->bottom_type()->is_ptr(), TypeInt::INT, T_INT, MemNode::unordered));
+  return _gvn.transform(new RShiftINode(layout_val, intcon(Klass::_lh_array_tag_shift)));
+}
+
+Node* GraphKit::gen_lh_array_test(Node* kls, unsigned int lh_value) {
+  Node* layout_val = load_lh_array_tag(kls);
+  Node* cmp = _gvn.transform(new CmpINode(layout_val, intcon(lh_value)));
+  return cmp;
 }
 
 //------------------------------next_monitor-----------------------------------
 // What number should be given to the next monitor?
 int GraphKit::next_monitor() {
@@ -3355,10 +3696,11 @@
   // %%% SynchronizationEntryBCI is redundant; use InvocationEntryBci in interfaces
   assert(SynchronizationEntryBCI == InvocationEntryBci, "");
 
   if( !GenerateSynchronizationCode )
     return NULL;                // Not locking things?
+
   if (stopped())                // Dead monitor?
     return NULL;
 
   assert(dead_locals_are_killed(), "should kill locals before sync. point");
 
@@ -3427,10 +3769,11 @@
     return;
   if (stopped()) {               // Dead monitor?
     map()->pop_monitor();        // Kill monitor from debug info
     return;
   }
+  assert(!obj->is_InlineTypeBase(), "should not unlock on inline type");
 
   // Memory barrier to avoid floating things down past the locked region
   insert_mem_bar(Op_MemBarReleaseLock);
 
   const TypeFunc *tf = OptoRuntime::complete_monitor_exit_Type();
@@ -3467,12 +3810,18 @@
 // almost always feature constant types.
 Node* GraphKit::get_layout_helper(Node* klass_node, jint& constant_value) {
   const TypeKlassPtr* inst_klass = _gvn.type(klass_node)->isa_klassptr();
   if (!StressReflectiveCode && inst_klass != NULL) {
     ciKlass* klass = inst_klass->klass();
+    assert(klass != NULL, "klass should not be NULL");
     bool    xklass = inst_klass->klass_is_exact();
-    if (xklass || klass->is_array_klass()) {
+    bool can_be_flattened = false;
+    if (UseFlatArray && klass->is_obj_array_klass()) {
+      ciKlass* elem = klass->as_obj_array_klass()->element_klass();
+      can_be_flattened = elem->can_be_inline_klass() && (!elem->is_inlinetype() || elem->flatten_array());
+    }
+    if (xklass || (klass->is_array_klass() && !can_be_flattened)) {
       jint lhelper = klass->layout_helper();
       if (lhelper != Klass::_lh_neutral_value) {
         constant_value = lhelper;
         return (Node*) NULL;
       }
@@ -3530,21 +3879,46 @@
     // and link them properly (as a group) to the InitializeNode.
     assert(init->in(InitializeNode::Memory) == malloc, "");
     MergeMemNode* minit_in = MergeMemNode::make(malloc);
     init->set_req(InitializeNode::Memory, minit_in);
     record_for_igvn(minit_in); // fold it up later, if possible
+    _gvn.set_type(minit_in, Type::MEMORY);
     Node* minit_out = memory(rawidx);
     assert(minit_out->is_Proj() && minit_out->in(0) == init, "");
     // Add an edge in the MergeMem for the header fields so an access
     // to one of those has correct memory state
     set_memory(minit_out, C->get_alias_index(oop_type->add_offset(oopDesc::mark_offset_in_bytes())));
     set_memory(minit_out, C->get_alias_index(oop_type->add_offset(oopDesc::klass_offset_in_bytes())));
     if (oop_type->isa_aryptr()) {
-      const TypePtr* telemref = oop_type->add_offset(Type::OffsetBot);
-      int            elemidx  = C->get_alias_index(telemref);
-      hook_memory_on_init(*this, elemidx, minit_in, minit_out);
+      const TypeAryPtr* arytype = oop_type->is_aryptr();
+      if (arytype->klass()->is_flat_array_klass()) {
+        // Initially all flattened array accesses share a single slice
+        // but that changes after parsing. Prepare the memory graph so
+        // it can optimize flattened array accesses properly once they
+        // don't share a single slice.
+        assert(C->flattened_accesses_share_alias(), "should be set at parse time");
+        C->set_flattened_accesses_share_alias(false);
+        ciFlatArrayKlass* vak = arytype->klass()->as_flat_array_klass();
+        ciInlineKlass* vk = vak->element_klass()->as_inline_klass();
+        for (int i = 0, len = vk->nof_nonstatic_fields(); i < len; i++) {
+          ciField* field = vk->nonstatic_field_at(i);
+          if (field->offset() >= TrackedInitializationLimit * HeapWordSize)
+            continue;  // do not bother to track really large numbers of fields
+          int off_in_vt = field->offset() - vk->first_field_offset();
+          const TypePtr* adr_type = arytype->with_field_offset(off_in_vt)->add_offset(Type::OffsetBot);
+          int fieldidx = C->get_alias_index(adr_type, true);
+          hook_memory_on_init(*this, fieldidx, minit_in, minit_out);
+        }
+        C->set_flattened_accesses_share_alias(true);
+        hook_memory_on_init(*this, C->get_alias_index(TypeAryPtr::INLINES), minit_in, minit_out);
+      } else {
+        const TypePtr* telemref = oop_type->add_offset(Type::OffsetBot);
+        int            elemidx  = C->get_alias_index(telemref);
+        hook_memory_on_init(*this, elemidx, minit_in, minit_out);
+      }
     } else if (oop_type->isa_instptr()) {
+      set_memory(minit_out, C->get_alias_index(oop_type)); // mark word
       ciInstanceKlass* ik = oop_type->klass()->as_instance_klass();
       for (int i = 0, len = ik->nof_nonstatic_fields(); i < len; i++) {
         ciField* field = ik->nonstatic_field_at(i);
         if (field->offset() >= TrackedInitializationLimit * HeapWordSize)
           continue;  // do not bother to track really large numbers of fields
@@ -3591,18 +3965,19 @@
 //  - If 'return_size_val', report the the total object size to the caller.
 //  - deoptimize_on_exception controls how Java exceptions are handled (rethrow vs deoptimize)
 Node* GraphKit::new_instance(Node* klass_node,
                              Node* extra_slow_test,
                              Node* *return_size_val,
-                             bool deoptimize_on_exception) {
+                             bool deoptimize_on_exception,
+                             InlineTypeBaseNode* inline_type_node) {
   // Compute size in doublewords
   // The size is always an integral number of doublewords, represented
   // as a positive bytewise size stored in the klass's layout_helper.
   // The layout_helper also encodes (in a low bit) the need for a slow path.
   jint  layout_con = Klass::_lh_neutral_value;
   Node* layout_val = get_layout_helper(klass_node, layout_con);
-  int   layout_is_con = (layout_val == NULL);
+  bool  layout_is_con = (layout_val == NULL);
 
   if (extra_slow_test == NULL)  extra_slow_test = intcon(0);
   // Generate the initial go-slow test.  It's either ALWAYS (return a
   // Node for 1) or NEVER (return a NULL) or perhaps (in the reflective
   // case) a computed value derived from the layout_helper.
@@ -3649,34 +4024,42 @@
   const TypeOopPtr* oop_type = tklass->as_instance_type();
 
   // Now generate allocation code
 
   // The entire memory state is needed for slow path of the allocation
-  // since GC and deoptimization can happened.
+  // since GC and deoptimization can happen.
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
   AllocateNode* alloc = new AllocateNode(C, AllocateNode::alloc_type(Type::TOP),
                                          control(), mem, i_o(),
                                          size, klass_node,
-                                         initial_slow_test);
+                                         initial_slow_test, inline_type_node);
 
   return set_output_for_allocation(alloc, oop_type, deoptimize_on_exception);
 }
 
+// With compressed oops, the 64 bit init value for non flattened value
+// arrays is built from 2 32 bit compressed oops
+static Node* raw_default_for_coops(Node* default_value, GraphKit& kit) {
+  Node* lower = kit.gvn().transform(new CastP2XNode(kit.control(), default_value));
+  Node* upper = kit.gvn().transform(new LShiftLNode(lower, kit.intcon(32)));
+  return kit.gvn().transform(new OrLNode(lower, upper));
+}
+
 //-------------------------------new_array-------------------------------------
-// helper for both newarray and anewarray
+// helper for newarray and anewarray
 // The 'length' parameter is (obviously) the length of the array.
 // See comments on new_instance for the meaning of the other arguments.
 Node* GraphKit::new_array(Node* klass_node,     // array klass (maybe variable)
                           Node* length,         // number of array elements
                           int   nargs,          // number of arguments to push back for uncommon trap
                           Node* *return_size_val,
                           bool deoptimize_on_exception) {
   jint  layout_con = Klass::_lh_neutral_value;
   Node* layout_val = get_layout_helper(klass_node, layout_con);
-  int   layout_is_con = (layout_val == NULL);
+  bool  layout_is_con = (layout_val == NULL);
 
   if (!layout_is_con && !StressReflectiveCode &&
       !too_many_traps(Deoptimization::Reason_class_check)) {
     // This is a reflective array creation site.
     // Optimistically assume that it is a subtype of Object[],
@@ -3702,11 +4085,11 @@
   int fast_size_limit = FastAllocateSizeLimit;
   if (layout_is_con) {
     assert(!StressReflectiveCode, "stress mode does not use these paths");
     // Increase the size limit if we have exact knowledge of array type.
     int log2_esize = Klass::layout_helper_log2_element_size(layout_con);
-    fast_size_limit <<= (LogBytesPerLong - log2_esize);
+    fast_size_limit <<= MAX2(LogBytesPerLong - log2_esize, 0);
   }
 
   Node* initial_slow_cmp  = _gvn.transform( new CmpUNode( length, intcon( fast_size_limit ) ) );
   Node* initial_slow_test = _gvn.transform( new BoolNode( initial_slow_cmp, BoolTest::gt ) );
 
@@ -3720,14 +4103,14 @@
   int   header_size_min  = arrayOopDesc::base_offset_in_bytes(T_BYTE);
   // (T_BYTE has the weakest alignment and size restrictions...)
   if (layout_is_con) {
     int       hsize  = Klass::layout_helper_header_size(layout_con);
     int       eshift = Klass::layout_helper_log2_element_size(layout_con);
-    BasicType etype  = Klass::layout_helper_element_type(layout_con);
+    bool is_flat_array = Klass::layout_helper_is_flatArray(layout_con);
     if ((round_mask & ~right_n_bits(eshift)) == 0)
       round_mask = 0;  // strength-reduce it if it goes away completely
-    assert((hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
+    assert(is_flat_array || (hsize & right_n_bits(eshift)) == 0, "hsize is pre-rounded");
     assert(header_size_min <= hsize, "generic minimum is smallest");
     header_size_min = hsize;
     header_size = intcon(hsize + round_mask);
   } else {
     Node* hss   = intcon(Klass::_lh_header_size_shift);
@@ -3807,33 +4190,112 @@
   }
 
   // Now generate allocation code
 
   // The entire memory state is needed for slow path of the allocation
-  // since GC and deoptimization can happened.
+  // since GC and deoptimization can happen.
   Node *mem = reset_memory();
   set_all_memory(mem); // Create new memory state
 
   if (initial_slow_test->is_Bool()) {
     // Hide it behind a CMoveI, or else PhaseIdealLoop::split_up will get sick.
     initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn);
   }
 
+  const TypeKlassPtr* ary_klass = _gvn.type(klass_node)->isa_klassptr();
+  const TypeOopPtr* ary_type = ary_klass->as_instance_type();
+  const TypeAryPtr* ary_ptr = ary_type->isa_aryptr();
+
+  // Inline type array variants:
+  // - null-ok:              MyValue.ref[] (ciObjArrayKlass "[LMyValue$ref")
+  // - null-free:            MyValue.val[] (ciObjArrayKlass "[QMyValue$val")
+  // - null-free, flattened: MyValue.val[] (ciFlatArrayKlass "[QMyValue$val")
+  // Check if array is a null-free, non-flattened inline type array
+  // that needs to be initialized with the default inline type.
+  Node* default_value = NULL;
+  Node* raw_default_value = NULL;
+  if (ary_ptr != NULL && ary_ptr->klass_is_exact()) {
+    // Array type is known
+    ciKlass* elem_klass = ary_ptr->klass()->as_array_klass()->element_klass();
+    if (elem_klass != NULL && elem_klass->is_inlinetype()) {
+      ciInlineKlass* vk = elem_klass->as_inline_klass();
+      if (!vk->flatten_array()) {
+        default_value = InlineTypeNode::default_oop(gvn(), vk);
+        if (UseCompressedOops) {
+          default_value = _gvn.transform(new EncodePNode(default_value, default_value->bottom_type()->make_narrowoop()));
+          raw_default_value = raw_default_for_coops(default_value, *this);
+        } else {
+          raw_default_value = _gvn.transform(new CastP2XNode(control(), default_value));
+        }
+      }
+    }
+  } else if (ary_klass->klass()->can_be_inline_array_klass()) {
+    // Array type is not known, add runtime checks
+    assert(!ary_klass->klass_is_exact(), "unexpected exact type");
+    Node* r = new RegionNode(4);
+    default_value = new PhiNode(r, TypeInstPtr::BOTTOM);
+
+    // Check if array is an object array
+    Node* cmp = gen_lh_array_test(klass_node, Klass::_lh_array_tag_obj_value);
+    Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::eq));
+    IfNode* iff = create_and_map_if(control(), bol, PROB_FAIR, COUNT_UNKNOWN);
+
+    // Not an object array, initialize with all zero
+    r->init_req(1, _gvn.transform(new IfFalseNode(iff)));
+    default_value->init_req(1, null());
+
+    // Object array, check if null-free
+    set_control(_gvn.transform(new IfTrueNode(iff)));
+    Node* lhp = basic_plus_adr(klass_node, in_bytes(Klass::layout_helper_offset()));
+    Node* layout_val = _gvn.transform(LoadNode::make(_gvn, NULL, immutable_memory(), lhp, lhp->bottom_type()->is_ptr(), TypeInt::INT, T_INT, MemNode::unordered));
+    Node* null_free = _gvn.transform(new RShiftINode(layout_val, intcon(Klass::_lh_null_free_shift)));
+    null_free = _gvn.transform(new AndINode(null_free, intcon(Klass::_lh_null_free_mask)));
+    cmp = _gvn.transform(new CmpINode(null_free, intcon(0)));
+    bol = _gvn.transform(new BoolNode(cmp, BoolTest::ne));
+    iff = create_and_map_if(control(), bol, PROB_FAIR, COUNT_UNKNOWN);
+
+    // Not null-free, initialize with all zero
+    r->init_req(2, _gvn.transform(new IfFalseNode(iff)));
+    default_value->init_req(2, null());
+
+    // Null-free, non-flattened inline type array, initialize with the default value
+    set_control(_gvn.transform(new IfTrueNode(iff)));
+    Node* p = basic_plus_adr(klass_node, in_bytes(ArrayKlass::element_klass_offset()));
+    Node* eklass = _gvn.transform(LoadKlassNode::make(_gvn, control(), immutable_memory(), p, TypeInstPtr::KLASS));
+    Node* adr_fixed_block_addr = basic_plus_adr(eklass, in_bytes(InstanceKlass::adr_inlineklass_fixed_block_offset()));
+    Node* adr_fixed_block = make_load(control(), adr_fixed_block_addr, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
+    Node* default_value_offset_addr = basic_plus_adr(adr_fixed_block, in_bytes(InlineKlass::default_value_offset_offset()));
+    Node* default_value_offset = make_load(control(), default_value_offset_addr, TypeInt::INT, T_INT, MemNode::unordered);
+    Node* elem_mirror = load_mirror_from_klass(eklass);
+    Node* default_value_addr = basic_plus_adr(elem_mirror, ConvI2X(default_value_offset));
+    Node* val = access_load_at(elem_mirror, default_value_addr, _gvn.type(default_value_addr)->is_ptr(), TypeInstPtr::BOTTOM, T_OBJECT, IN_HEAP);
+    r->init_req(3, control());
+    default_value->init_req(3, val);
+
+    set_control(_gvn.transform(r));
+    default_value = _gvn.transform(default_value);
+    if (UseCompressedOops) {
+      default_value = _gvn.transform(new EncodePNode(default_value, default_value->bottom_type()->make_narrowoop()));
+      raw_default_value = raw_default_for_coops(default_value, *this);
+    } else {
+      raw_default_value = _gvn.transform(new CastP2XNode(control(), default_value));
+    }
+  }
+
   // Create the AllocateArrayNode and its result projections
-  AllocateArrayNode* alloc
-    = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
-                            control(), mem, i_o(),
-                            size, klass_node,
-                            initial_slow_test,
-                            length);
+  AllocateArrayNode* alloc = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT),
+                                                   control(), mem, i_o(),
+                                                   size, klass_node,
+                                                   initial_slow_test,
+                                                   length, default_value,
+                                                   raw_default_value);
 
   // Cast to correct type.  Note that the klass_node may be constant or not,
   // and in the latter case the actual array type will be inexact also.
   // (This happens via a non-constant argument to inline_native_newArray.)
   // In any case, the value of klass_node provides the desired array type.
   const TypeInt* length_type = _gvn.find_int_type(length);
-  const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type();
   if (ary_type->isa_aryptr() && length_type != NULL) {
     // Try to get a better type than POS for the size
     ary_type = ary_type->is_aryptr()->cast_to_size(length_type);
   }
 
@@ -3987,15 +4449,15 @@
 }
 
 Node* GraphKit::load_String_value(Node* str, bool set_ctrl) {
   int value_offset = java_lang_String::value_offset();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
-                                                     false, NULL, 0);
+                                                     false, NULL, Type::Offset(0));
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
   const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull,
-                                                  TypeAry::make(TypeInt::BYTE, TypeInt::POS),
-                                                  ciTypeArrayKlass::make(T_BYTE), true, 0);
+                                                  TypeAry::make(TypeInt::BYTE, TypeInt::POS, false, true, true),
+                                                  ciTypeArrayKlass::make(T_BYTE), true, Type::Offset(0));
   Node* p = basic_plus_adr(str, str, value_offset);
   Node* load = access_load_at(str, p, value_field_type, value_type, T_OBJECT,
                               IN_HEAP | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0) | MO_UNORDERED);
   return load;
 }
@@ -4004,11 +4466,11 @@
   if (!CompactStrings) {
     return intcon(java_lang_String::CODER_UTF16);
   }
   int coder_offset = java_lang_String::coder_offset();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
-                                                     false, NULL, 0);
+                                                     false, NULL, Type::Offset(0));
   const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
 
   Node* p = basic_plus_adr(str, str, coder_offset);
   Node* load = access_load_at(str, p, coder_field_type, TypeInt::BYTE, T_BYTE,
                               IN_HEAP | (set_ctrl ? C2_CONTROL_DEPENDENT_LOAD : 0) | MO_UNORDERED);
@@ -4016,21 +4478,21 @@
 }
 
 void GraphKit::store_String_value(Node* str, Node* value) {
   int value_offset = java_lang_String::value_offset();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
-                                                     false, NULL, 0);
+                                                     false, NULL, Type::Offset(0));
   const TypePtr* value_field_type = string_type->add_offset(value_offset);
 
   access_store_at(str,  basic_plus_adr(str, value_offset), value_field_type,
                   value, TypeAryPtr::BYTES, T_OBJECT, IN_HEAP | MO_UNORDERED);
 }
 
 void GraphKit::store_String_coder(Node* str, Node* value) {
   int coder_offset = java_lang_String::coder_offset();
   const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(),
-                                                     false, NULL, 0);
+                                                     false, NULL, Type::Offset(0));
   const TypePtr* coder_field_type = string_type->add_offset(coder_offset);
 
   access_store_at(str, basic_plus_adr(str, coder_offset), coder_field_type,
                   value, TypeInt::BYTE, T_BYTE, IN_HEAP | MO_UNORDERED);
 }
@@ -4137,9 +4599,25 @@
     }
   }
   const Type* con_type = Type::make_constant_from_field(field, holder, field->layout_type(),
                                                         /*is_unsigned_load=*/false);
   if (con_type != NULL) {
-    return makecon(con_type);
+    Node* con = makecon(con_type);
+    assert(!field->type()->is_inlinetype() || (field->is_static() && !con_type->is_zero_type()), "sanity");
+    // Check type of constant which might be more precise
+    if (con_type->is_inlinetypeptr() && con_type->inline_klass()->is_scalarizable()) {
+      // Load inline type from constant oop
+      con = InlineTypeNode::make_from_oop(this, con, con_type->inline_klass());
+    }
+    return con;
   }
   return NULL;
 }
+
+//---------------------------load_mirror_from_klass----------------------------
+// Given a klass oop, load its java mirror (a java.lang.Class oop).
+Node* GraphKit::load_mirror_from_klass(Node* klass) {
+  Node* p = basic_plus_adr(klass, in_bytes(Klass::java_mirror_offset()));
+  Node* load = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS, MemNode::unordered);
+  // mirror = ((OopHandle)mirror)->resolve();
+  return access_load(load, TypeInstPtr::MIRROR, T_OBJECT, IN_NATIVE);
+}
diff a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp
--- a/src/hotspot/share/opto/macro.cpp
+++ b/src/hotspot/share/opto/macro.cpp
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2020, 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.
@@ -21,10 +21,11 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "ci/ciFlatArrayKlass.hpp"
 #include "compiler/compileLog.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "libadt/vectset.hpp"
 #include "memory/universe.hpp"
 #include "opto/addnode.hpp"
@@ -33,10 +34,11 @@
 #include "opto/castnode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/compile.hpp"
 #include "opto/convertnode.hpp"
 #include "opto/graphKit.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/intrinsicnode.hpp"
 #include "opto/locknode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/macro.hpp"
 #include "opto/memnode.hpp"
@@ -80,60 +82,10 @@
     }
   }
   return nreplacements;
 }
 
-void PhaseMacroExpand::migrate_outs(Node *old, Node *target) {
-  assert(old != NULL, "sanity");
-  for (DUIterator_Fast imax, i = old->fast_outs(imax); i < imax; i++) {
-    Node* use = old->fast_out(i);
-    _igvn.rehash_node_delayed(use);
-    imax -= replace_input(use, old, target);
-    // back up iterator
-    --i;
-  }
-  assert(old->outcnt() == 0, "all uses must be deleted");
-}
-
-void PhaseMacroExpand::copy_call_debug_info(CallNode *oldcall, CallNode * newcall) {
-  // Copy debug information and adjust JVMState information
-  uint old_dbg_start = oldcall->tf()->domain()->cnt();
-  uint new_dbg_start = newcall->tf()->domain()->cnt();
-  int jvms_adj  = new_dbg_start - old_dbg_start;
-  assert (new_dbg_start == newcall->req(), "argument count mismatch");
-
-  // SafePointScalarObject node could be referenced several times in debug info.
-  // Use Dict to record cloned nodes.
-  Dict* sosn_map = new Dict(cmpkey,hashkey);
-  for (uint i = old_dbg_start; i < oldcall->req(); i++) {
-    Node* old_in = oldcall->in(i);
-    // Clone old SafePointScalarObjectNodes, adjusting their field contents.
-    if (old_in != NULL && old_in->is_SafePointScalarObject()) {
-      SafePointScalarObjectNode* old_sosn = old_in->as_SafePointScalarObject();
-      uint old_unique = C->unique();
-      Node* new_in = old_sosn->clone(sosn_map);
-      if (old_unique != C->unique()) { // New node?
-        new_in->set_req(0, C->root()); // reset control edge
-        new_in = transform_later(new_in); // Register new node.
-      }
-      old_in = new_in;
-    }
-    newcall->add_req(old_in);
-  }
-
-  // JVMS may be shared so clone it before we modify it
-  newcall->set_jvms(oldcall->jvms() != NULL ? oldcall->jvms()->clone_deep(C) : NULL);
-  for (JVMState *jvms = newcall->jvms(); jvms != NULL; jvms = jvms->caller()) {
-    jvms->set_map(newcall);
-    jvms->set_locoff(jvms->locoff()+jvms_adj);
-    jvms->set_stkoff(jvms->stkoff()+jvms_adj);
-    jvms->set_monoff(jvms->monoff()+jvms_adj);
-    jvms->set_scloff(jvms->scloff()+jvms_adj);
-    jvms->set_endoff(jvms->endoff()+jvms_adj);
-  }
-}
-
 Node* PhaseMacroExpand::opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path) {
   Node* cmp;
   if (mask != 0) {
     Node* and_node = transform_later(new AndXNode(word, MakeConX(mask)));
     cmp = transform_later(new CmpXNode(and_node, MakeConX(bits)));
@@ -182,11 +134,11 @@
   // Slow path call has no side-effects, uses few values
   copy_predefined_input_for_runtime_call(slow_path, oldcall, call );
   if (parm0 != NULL)  call->init_req(TypeFunc::Parms+0, parm0);
   if (parm1 != NULL)  call->init_req(TypeFunc::Parms+1, parm1);
   if (parm2 != NULL)  call->init_req(TypeFunc::Parms+2, parm2);
-  copy_call_debug_info(oldcall, call);
+  call->copy_call_debug_info(&_igvn, oldcall);
   call->set_cnt(PROB_UNLIKELY_MAG(4));  // Same effect as RC_UNCOMMON.
   _igvn.replace_node(oldcall, call);
   transform_later(call);
 
   return call;
@@ -290,11 +242,11 @@
     } else if (mem->is_Store()) {
       const TypePtr* atype = mem->as_Store()->adr_type();
       int adr_idx = phase->C->get_alias_index(atype);
       if (adr_idx == alias_idx) {
         assert(atype->isa_oopptr(), "address type must be oopptr");
-        int adr_offset = atype->offset();
+        int adr_offset = atype->flattened_offset();
         uint adr_iid = atype->is_oopptr()->instance_id();
         // Array elements references have the same alias_idx
         // but different offset and different instance_id.
         if (adr_offset == offset && adr_iid == alloc->_idx)
           return mem;
@@ -333,11 +285,11 @@
         DEBUG_ONLY(mem->dump();)
         assert(false, "Object is not scalar replaceable if a LoadStore node accesses its field");
         return NULL;
       }
       mem = mem->in(MemNode::Memory);
-   } else if (mem->Opcode() == Op_StrInflatedCopy) {
+    } else if (mem->Opcode() == Op_StrInflatedCopy) {
       Node* adr = mem->in(3); // Destination array
       const TypePtr* atype = adr->bottom_type()->is_ptr();
       int adr_idx = phase->C->get_alias_index(atype);
       if (adr_idx == alias_idx) {
         DEBUG_ONLY(mem->dump();)
@@ -378,45 +330,51 @@
       Node* dest_pos = ac->in(ArrayCopyNode::DestPos);
       const TypeInt* src_pos_t = _igvn.type(src_pos)->is_int();
       const TypeInt* dest_pos_t = _igvn.type(dest_pos)->is_int();
 
       Node* adr = NULL;
-      const TypePtr* adr_type = NULL;
+      Node* base = ac->in(ArrayCopyNode::Src);
+      const TypePtr* adr_type = _igvn.type(base)->is_ptr();
+      assert(adr_type->isa_aryptr(), "only arrays here");
       if (src_pos_t->is_con() && dest_pos_t->is_con()) {
         intptr_t off = ((src_pos_t->get_con() - dest_pos_t->get_con()) << shift) + offset;
-        Node* base = ac->in(ArrayCopyNode::Src);
-        adr = _igvn.transform(new AddPNode(base, base, MakeConX(off)));
+        adr = _igvn.transform(new AddPNode(base, base, MakeConX(off)));
+        adr_type = _igvn.type(adr)->is_ptr();
         adr_type = _igvn.type(base)->is_ptr()->add_offset(off);
         if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
           // Don't emit a new load from src if src == dst but try to get the value from memory instead
           return value_from_mem(ac->in(TypeFunc::Memory), ctl, ft, ftype, adr_type->isa_oopptr(), alloc);
         }
       } else {
+        if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
+          // Non constant offset in the array: we can't statically
+          // determine the value
+          return NULL;
+        }
         Node* diff = _igvn.transform(new SubINode(ac->in(ArrayCopyNode::SrcPos), ac->in(ArrayCopyNode::DestPos)));
 #ifdef _LP64
         diff = _igvn.transform(new ConvI2LNode(diff));
 #endif
         diff = _igvn.transform(new LShiftXNode(diff, intcon(shift)));
 
         Node* off = _igvn.transform(new AddXNode(MakeConX(offset), diff));
-        Node* base = ac->in(ArrayCopyNode::Src);
-        adr = _igvn.transform(new AddPNode(base, base, off));
-        adr_type = _igvn.type(base)->is_ptr()->add_offset(Type::OffsetBot);
-        if (ac->in(ArrayCopyNode::Src) == ac->in(ArrayCopyNode::Dest)) {
-          // Non constant offset in the array: we can't statically
-          // determine the value
-          return NULL;
+        adr = _igvn.transform(new AddPNode(base, base, off));
+        // In the case of a flattened inline type array, each field has its
+        // own slice so we need to extract the field being accessed from
+        // the address computation
+        adr_type = adr_type->is_aryptr()->add_field_offset_and_offset(offset)->add_offset(Type::OffsetBot);
         }
       }
       MergeMemNode* mergemen = MergeMemNode::make(mem);
       BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
       res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemen, adr, adr_type, type, bt);
     }
   }
   if (res != NULL) {
     if (ftype->isa_narrowoop()) {
       // PhaseMacroExpand::scalar_replacement adds DecodeN nodes
+      assert(res->isa_DecodeN(), "should be narrow oop");
       res = _igvn.transform(new EncodePNode(res, ftype));
     }
     return res;
   }
   return NULL;
@@ -428,11 +386,11 @@
 // Note: this function is recursive, its depth is limited by the "level" argument
 // Returns the computed Phi, or NULL if it cannot compute it.
 Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *phi_type, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level) {
   assert(mem->is_Phi(), "sanity");
   int alias_idx = C->get_alias_index(adr_t);
-  int offset = adr_t->offset();
+  int offset = adr_t->flattened_offset();
   int instance_id = adr_t->instance_id();
 
   // Check if an appropriate value phi already exists.
   Node* region = mem->in(0);
   for (DUIterator_Fast kmax, k = region->fast_outs(kmax); k < kmax; k++) {
@@ -467,11 +425,17 @@
       values.at_put(j, in);
     } else  {
       Node *val = scan_mem_chain(in, alias_idx, offset, start_mem, alloc, &_igvn);
       if (val == start_mem || val == alloc_mem) {
         // hit a sentinel, return appropriate 0 value
-        values.at_put(j, _igvn.zerocon(ft));
+        Node* default_value = alloc->in(AllocateNode::DefaultValue);
+        if (default_value != NULL) {
+          values.at_put(j, default_value);
+        } else {
+          assert(alloc->in(AllocateNode::RawDefaultValue) == NULL, "default value may not be null");
+          values.at_put(j, _igvn.zerocon(ft));
+        }
         continue;
       }
       if (val->is_Initialize()) {
         val = val->as_Initialize()->find_captured_store(offset, type2aelembytes(ft), &_igvn);
       }
@@ -484,11 +448,17 @@
         Node* n = val->in(MemNode::ValueIn);
         BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
         n = bs->step_over_gc_barrier(n);
         values.at_put(j, n);
       } else if(val->is_Proj() && val->in(0) == alloc) {
-        values.at_put(j, _igvn.zerocon(ft));
+        Node* default_value = alloc->in(AllocateNode::DefaultValue);
+        if (default_value != NULL) {
+          values.at_put(j, default_value);
+        } else {
+          assert(alloc->in(AllocateNode::RawDefaultValue) == NULL, "default value may not be null");
+          values.at_put(j, _igvn.zerocon(ft));
+        }
       } else if (val->is_Phi()) {
         val = value_from_mem_phi(val, ft, phi_type, adr_t, alloc, value_phis, level-1);
         if (val == NULL) {
           return NULL;
         }
@@ -530,13 +500,12 @@
   assert(adr_t->is_known_instance_field(), "instance required");
   int instance_id = adr_t->instance_id();
   assert((uint)instance_id == alloc->_idx, "wrong allocation");
 
   int alias_idx = C->get_alias_index(adr_t);
-  int offset = adr_t->offset();
+  int offset = adr_t->flattened_offset();
   Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory);
-  Node *alloc_ctrl = alloc->in(TypeFunc::Control);
   Node *alloc_mem = alloc->in(TypeFunc::Memory);
   VectorSet visited;
 
   bool done = sfpt_mem == alloc_mem;
   Node *mem = sfpt_mem;
@@ -548,21 +517,21 @@
     if (mem == start_mem || mem == alloc_mem) {
       done = true;  // hit a sentinel, return appropriate 0 value
     } else if (mem->is_Initialize()) {
       mem = mem->as_Initialize()->find_captured_store(offset, type2aelembytes(ft), &_igvn);
       if (mem == NULL) {
-        done = true; // Something go wrong.
+        done = true; // Something went wrong.
       } else if (mem->is_Store()) {
         const TypePtr* atype = mem->as_Store()->adr_type();
         assert(C->get_alias_index(atype) == Compile::AliasIdxRaw, "store is correct memory slice");
         done = true;
       }
     } else if (mem->is_Store()) {
       const TypeOopPtr* atype = mem->as_Store()->adr_type()->isa_oopptr();
       assert(atype != NULL, "address type must be oopptr");
       assert(C->get_alias_index(atype) == alias_idx &&
-             atype->is_known_instance_field() && atype->offset() == offset &&
+             atype->is_known_instance_field() && atype->flattened_offset() == offset &&
              atype->instance_id() == instance_id, "store is correct memory slice");
       done = true;
     } else if (mem->is_Phi()) {
       // try to find a phi's unique input
       Node *unique_input = NULL;
@@ -590,10 +559,15 @@
     }
   }
   if (mem != NULL) {
     if (mem == start_mem || mem == alloc_mem) {
       // hit a sentinel, return appropriate 0 value
+      Node* default_value = alloc->in(AllocateNode::DefaultValue);
+      if (default_value != NULL) {
+        return default_value;
+      }
+      assert(alloc->in(AllocateNode::RawDefaultValue) == NULL, "default value may not be null");
       return _igvn.zerocon(ft);
     } else if (mem->is_Store()) {
       Node* n = mem->in(MemNode::ValueIn);
       BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
       n = bs->step_over_gc_barrier(n);
@@ -621,14 +595,51 @@
         m = sfpt_mem;
       }
       return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, m, ft, ftype, alloc);
     }
   }
-  // Something go wrong.
+  // Something went wrong.
   return NULL;
 }
 
+// Search the last value stored into the inline type's fields.
+Node* PhaseMacroExpand::inline_type_from_mem(Node* mem, Node* ctl, ciInlineKlass* vk, const TypeAryPtr* adr_type, int offset, AllocateNode* alloc) {
+  // Subtract the offset of the first field to account for the missing oop header
+  offset -= vk->first_field_offset();
+  // Create a new InlineTypeNode and retrieve the field values from memory
+  InlineTypeNode* vt = InlineTypeNode::make_uninitialized(_igvn, vk)->as_InlineType();
+  for (int i = 0; i < vk->nof_declared_nonstatic_fields(); ++i) {
+    ciType* field_type = vt->field_type(i);
+    int field_offset = offset + vt->field_offset(i);
+    // Each inline type field has its own memory slice
+    adr_type = adr_type->with_field_offset(field_offset);
+    Node* value = NULL;
+    if (vt->field_is_flattened(i)) {
+      value = inline_type_from_mem(mem, ctl, field_type->as_inline_klass(), adr_type, field_offset, alloc);
+    } else {
+      const Type* ft = Type::get_const_type(field_type);
+      BasicType bt = field_type->basic_type();
+      if (UseCompressedOops && !is_java_primitive(bt)) {
+        ft = ft->make_narrowoop();
+        bt = T_NARROWOOP;
+      }
+      value = value_from_mem(mem, ctl, bt, ft, adr_type, alloc);
+      if (value != NULL && ft->isa_narrowoop()) {
+        assert(UseCompressedOops, "unexpected narrow oop");
+        value = transform_later(new DecodeNNode(value, value->get_ptr_type()));
+      }
+    }
+    if (value != NULL) {
+      vt->set_field_value(i, value);
+    } else {
+      // We might have reached the TrackedInitializationLimit
+      return NULL;
+    }
+  }
+  return transform_later(vt);
+}
+
 // Check the possibility of scalar replacement.
 bool PhaseMacroExpand::can_eliminate_allocation(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints) {
   //  Scan the uses of the allocation to check for anything that would
   //  prevent us from eliminating it.
   NOT_PRODUCT( const char* fail_eliminate = NULL; )
@@ -677,11 +688,11 @@
               SHENANDOAHGC_ONLY(&& (!UseShenandoahGC || !ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(n))) ) {
             DEBUG_ONLY(disq_node = n;)
             if (n->is_Load() || n->is_LoadStore()) {
               NOT_PRODUCT(fail_eliminate = "Field load";)
             } else {
-              NOT_PRODUCT(fail_eliminate = "Not store field referrence";)
+              NOT_PRODUCT(fail_eliminate = "Not store field reference";)
             }
             can_eliminate = false;
           }
         }
       } else if (use->is_ArrayCopy() &&
@@ -705,10 +716,14 @@
           NOT_PRODUCT(fail_eliminate = "NULL or TOP memory";)
           can_eliminate = false;
         } else {
           safepoints.append_if_missing(sfpt);
         }
+      } else if (use->is_InlineType() && use->isa_InlineType()->get_oop() == res) {
+        // ok to eliminate
+      } else if (use->Opcode() == Op_StoreX && use->in(MemNode::Address) == res) {
+        // store to mark work
       } else if (use->Opcode() != Op_CastP2X) { // CastP2X is used by card mark
         if (use->is_Phi()) {
           if (use->outcnt() == 1 && use->unique_out()->Opcode() == Op_Return) {
             NOT_PRODUCT(fail_eliminate = "Object is return value";)
           } else {
@@ -716,16 +731,19 @@
           }
           DEBUG_ONLY(disq_node = use;)
         } else {
           if (use->Opcode() == Op_Return) {
             NOT_PRODUCT(fail_eliminate = "Object is return value";)
-          }else {
+          } else {
             NOT_PRODUCT(fail_eliminate = "Object is referenced by node";)
           }
           DEBUG_ONLY(disq_node = use;)
         }
         can_eliminate = false;
+      } else {
+        assert(use->Opcode() == Op_CastP2X, "should be");
+        assert(!use->has_out_with(Op_OrL), "should have been removed because oop is never null");
       }
     }
   }
 
 #ifndef PRODUCT
@@ -784,17 +802,26 @@
       // find the array's elements which will be needed for safepoint debug information
       nfields = alloc->in(AllocateNode::ALength)->find_int_con(-1);
       assert(klass->is_array_klass() && nfields >= 0, "must be an array klass.");
       elem_type = klass->as_array_klass()->element_type();
       basic_elem_type = elem_type->basic_type();
+      if (elem_type->is_inlinetype() && !klass->is_flat_array_klass()) {
+        assert(basic_elem_type == T_INLINE_TYPE, "unexpected element basic type");
+        basic_elem_type = T_OBJECT;
+      }
       array_base = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
       element_size = type2aelembytes(basic_elem_type);
+      if (klass->is_flat_array_klass()) {
+        // Flattened inline type array
+        element_size = klass->as_flat_array_klass()->element_byte_size();
+      }
     }
   }
   //
   // Process the safepoint uses
   //
+  Unique_Node_List value_worklist;
   while (safepoints.length() > 0) {
     SafePointNode* sfpt = safepoints.pop();
     Node* mem = sfpt->memory();
     Node* ctl = sfpt->control();
     assert(sfpt->jvms() != NULL, "missed JVMS");
@@ -817,10 +844,11 @@
       if (iklass != NULL) {
         field = iklass->nonstatic_field_at(j);
         offset = field->offset();
         elem_type = field->type();
         basic_elem_type = field->layout_type();
+        assert(!field->is_flattened(), "flattened inline type fields should not have safepoint uses");
       } else {
         offset = array_base + j * (intptr_t)element_size;
       }
 
       const Type *field_type;
@@ -844,13 +872,19 @@
         }
       } else {
         field_type = Type::get_const_basic_type(basic_elem_type);
       }
 
-      const TypeOopPtr *field_addr_type = res_type->add_offset(offset)->isa_oopptr();
-
-      Node *field_val = value_from_mem(mem, ctl, basic_elem_type, field_type, field_addr_type, alloc);
+      Node* field_val = NULL;
+      const TypeOopPtr* field_addr_type = res_type->add_offset(offset)->isa_oopptr();
+      if (klass->is_flat_array_klass()) {
+        ciInlineKlass* vk = elem_type->as_inline_klass();
+        assert(vk->flatten_array(), "must be flattened");
+        field_val = inline_type_from_mem(mem, ctl, vk, field_addr_type->isa_aryptr(), 0, alloc);
+      } else {
+        field_val = value_from_mem(mem, ctl, basic_elem_type, field_type, field_addr_type, alloc);
+      }
       if (field_val == NULL) {
         // We weren't able to find a value for this field,
         // give up on eliminating this allocation.
 
         // Remove any extra entries we added to the safepoint.
@@ -904,11 +938,14 @@
             res->dump();
         }
 #endif
         return false;
       }
-      if (UseCompressedOops && field_type->isa_narrowoop()) {
+      if (field_val->is_InlineType()) {
+        // Keep track of inline types to scalarize them later
+        value_worklist.push(field_val);
+      } else if (UseCompressedOops && field_type->isa_narrowoop()) {
         // Enable "DecodeN(EncodeP(Allocate)) --> Allocate" transformation
         // to be able scalar replace the allocation.
         if (field_val->is_EncodeP()) {
           field_val = field_val->in(1);
         } else {
@@ -925,10 +962,15 @@
     int end   = jvms->debug_end();
     sfpt->replace_edges_in_range(res, sobj, start, end);
     _igvn._worklist.push(sfpt);
     safepoints_done.append_if_missing(sfpt); // keep it for rollback
   }
+  // Scalarize inline types that were added to the safepoint
+  for (uint i = 0; i < value_worklist.size(); ++i) {
+    Node* vt = value_worklist.at(i);
+    vt->as_InlineType()->make_scalar_in_safepoints(&_igvn);
+  }
   return true;
 }
 
 static void disconnect_projections(MultiNode* n, PhaseIterGVN& igvn) {
   Node* ctl_proj = n->proj_out_or_null(TypeFunc::Control);
@@ -940,11 +982,11 @@
     igvn.replace_node(mem_proj, n->in(TypeFunc::Memory));
   }
 }
 
 // Process users of eliminated allocation.
-void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc) {
+void PhaseMacroExpand::process_users_of_allocation(CallNode *alloc, bool inline_alloc) {
   Node* res = alloc->result_cast();
   if (res != NULL) {
     for (DUIterator_Last jmin, j = res->last_outs(jmin); j >= jmin; ) {
       Node *use = res->last_out(j);
       uint oc1 = res->outcnt();
@@ -952,22 +994,18 @@
       if (use->is_AddP()) {
         for (DUIterator_Last kmin, k = use->last_outs(kmin); k >= kmin; ) {
           Node *n = use->last_out(k);
           uint oc2 = use->outcnt();
           if (n->is_Store()) {
-#ifdef ASSERT
-            // Verify that there is no dependent MemBarVolatile nodes,
-            // they should be removed during IGVN, see MemBarNode::Ideal().
-            for (DUIterator_Fast pmax, p = n->fast_outs(pmax);
-                                       p < pmax; p++) {
-              Node* mb = n->fast_out(p);
-              assert(mb->is_Initialize() || !mb->is_MemBar() ||
-                     mb->req() <= MemBarNode::Precedent ||
-                     mb->in(MemBarNode::Precedent) != n,
-                     "MemBarVolatile should be eliminated for non-escaping object");
+            for (DUIterator_Fast pmax, p = n->fast_outs(pmax); p < pmax; p++) {
+              MemBarNode* mb = n->fast_out(p)->isa_MemBar();
+              if (mb != NULL && mb->req() <= MemBarNode::Precedent && mb->in(MemBarNode::Precedent) == n) {
+                // MemBarVolatiles should have been removed by MemBarNode::Ideal() for non-inline allocations
+                assert(inline_alloc, "MemBarVolatile should be eliminated for non-escaping object");
+                mb->remove(&_igvn);
+              }
             }
-#endif
             _igvn.replace_node(n, n->in(MemNode::Memory));
           } else {
             eliminate_gc_barrier(n);
           }
           k -= (oc2 - use->outcnt());
@@ -987,16 +1025,15 @@
           }
         } else {
           assert(ac->is_arraycopy_validated() ||
                  ac->is_copyof_validated() ||
                  ac->is_copyofrange_validated(), "unsupported");
-          CallProjections callprojs;
-          ac->extract_projections(&callprojs, true);
+          CallProjections* callprojs = ac->extract_projections(true);
 
-          _igvn.replace_node(callprojs.fallthrough_ioproj, ac->in(TypeFunc::I_O));
-          _igvn.replace_node(callprojs.fallthrough_memproj, ac->in(TypeFunc::Memory));
-          _igvn.replace_node(callprojs.fallthrough_catchproj, ac->in(TypeFunc::Control));
+          _igvn.replace_node(callprojs->fallthrough_ioproj, ac->in(TypeFunc::I_O));
+          _igvn.replace_node(callprojs->fallthrough_memproj, ac->in(TypeFunc::Memory));
+          _igvn.replace_node(callprojs->fallthrough_catchproj, ac->in(TypeFunc::Control));
 
           // Set control to top. IGVN will remove the remaining projections
           ac->set_req(0, top());
           ac->replace_edge(res, top());
 
@@ -1009,10 +1046,16 @@
           if (src->outcnt() == 0 && !src->is_top()) {
             _igvn.remove_dead_node(src);
           }
         }
         _igvn._worklist.push(ac);
+      } else if (use->is_InlineType()) {
+        assert(use->isa_InlineType()->get_oop() == res, "unexpected inline type use");
+        _igvn.rehash_node_delayed(use);
+        use->isa_InlineType()->set_oop(_igvn.zerocon(T_INLINE_TYPE));
+      } else if (use->is_Store()) {
+        _igvn.replace_node(use, use->in(MemNode::Memory));
       } else {
         eliminate_gc_barrier(use);
       }
       j -= (oc1 - res->outcnt());
     }
@@ -1042,10 +1085,15 @@
         // Eliminate Initialize node.
         InitializeNode *init = use->as_Initialize();
         assert(init->outcnt() <= 2, "only a control and memory projection expected");
         Node *ctrl_proj = init->proj_out_or_null(TypeFunc::Control);
         if (ctrl_proj != NULL) {
+          // Inline type buffer allocations are followed by a membar
+          Node* membar_after = ctrl_proj->unique_ctrl_out();
+          if (inline_alloc && membar_after->Opcode() == Op_MemBarCPUOrder) {
+            membar_after->as_MemBar()->remove(&_igvn);
+          }
           _igvn.replace_node(ctrl_proj, init->in(TypeFunc::Control));
 #ifdef ASSERT
           Node* tmp = init->in(TypeFunc::Control);
           assert(tmp == _fallthroughcatchproj, "allocation control projection");
 #endif
@@ -1060,10 +1108,14 @@
             assert(mem == _memproj_fallthrough, "allocation memory projection");
           }
 #endif
           _igvn.replace_node(mem_proj, mem);
         }
+      } else if (use->Opcode() == Op_MemBarStoreStore) {
+        // Inline type buffer allocations are followed by a membar
+        assert(inline_alloc, "Unexpected MemBarStoreStore");
+        use->as_MemBar()->remove(&_igvn);
       } else  {
         assert(false, "only Initialize or AddP expected");
       }
       j -= (oc1 - _resproj->outcnt());
     }
@@ -1091,22 +1143,29 @@
 bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
   // Don't do scalar replacement if the frame can be popped by JVMTI:
   // if reallocation fails during deoptimization we'll pop all
   // interpreter frames for this compiled frame and that won't play
   // nice with JVMTI popframe.
-  if (!EliminateAllocations || JvmtiExport::can_pop_frame() || !alloc->_is_non_escaping) {
+  if (!EliminateAllocations || JvmtiExport::can_pop_frame()) {
     return false;
   }
   Node* klass = alloc->in(AllocateNode::KlassNode);
   const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr();
-  Node* res = alloc->result_cast();
+
+  // Attempt to eliminate inline type buffer allocations
+  // regardless of usage and escape/replaceable status.
+  bool inline_alloc = tklass->klass()->is_inlinetype();
+  if (!alloc->_is_non_escaping && !inline_alloc) {
+    return false;
+  }
   // Eliminate boxing allocations which are not used
-  // regardless scalar replacable status.
-  bool boxing_alloc = C->eliminate_boxing() &&
-                      tklass->klass()->is_instance_klass()  &&
+  // regardless of scalar replaceable status.
+  Node* res = alloc->result_cast();
+  bool boxing_alloc = (res == NULL) && C->eliminate_boxing() &&
+                      tklass->klass()->is_instance_klass() &&
                       tklass->klass()->as_instance_klass()->is_box_klass();
-  if (!alloc->_is_scalar_replaceable && (!boxing_alloc || (res != NULL))) {
+  if (!alloc->_is_scalar_replaceable && !boxing_alloc && !inline_alloc) {
     return false;
   }
 
   extract_call_projections(alloc);
 
@@ -1114,15 +1173,16 @@
   if (!can_eliminate_allocation(alloc, safepoints)) {
     return false;
   }
 
   if (!alloc->_is_scalar_replaceable) {
-    assert(res == NULL, "sanity");
+    assert(res == NULL || inline_alloc, "sanity");
     // We can only eliminate allocation if all debug info references
     // are already replaced with SafePointScalarObject because
     // we can't search for a fields value without instance_id.
     if (safepoints.length() > 0) {
+      assert(!inline_alloc, "Inline type allocations should not have safepoint uses");
       return false;
     }
   }
 
   if (!scalar_replacement(alloc, safepoints)) {
@@ -1139,11 +1199,11 @@
       p = p->caller();
     }
     log->tail("eliminate_allocation");
   }
 
-  process_users_of_allocation(alloc);
+  process_users_of_allocation(alloc, inline_alloc);
 
 #ifndef PRODUCT
   if (PrintEliminateAllocations) {
     if (alloc->is_AllocateArray())
       tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx);
@@ -1163,11 +1223,11 @@
 
   assert(boxing->result_cast() == NULL, "unexpected boxing node result");
 
   extract_call_projections(boxing);
 
-  const TypeTuple* r = boxing->tf()->range();
+  const TypeTuple* r = boxing->tf()->range_sig();
   assert(r->cnt() > TypeFunc::Parms, "sanity");
   const TypeInstPtr* t = r->field_at(TypeFunc::Parms)->isa_instptr();
   assert(t != NULL, "sanity");
 
   CompileLog* log = C->log();
@@ -1364,17 +1424,17 @@
     slow_region = new RegionNode(3);
 
     // Now make the initial failure test.  Usually a too-big test but
     // might be a TRUE for finalizers or a fancy class check for
     // newInstance0.
-    IfNode *toobig_iff = new IfNode(ctrl, initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
+    IfNode* toobig_iff = new IfNode(ctrl, initial_slow_test, PROB_MIN, COUNT_UNKNOWN);
     transform_later(toobig_iff);
     // Plug the failing-too-big test into the slow-path region
-    Node *toobig_true = new IfTrueNode( toobig_iff );
+    Node* toobig_true = new IfTrueNode(toobig_iff);
     transform_later(toobig_true);
     slow_region    ->init_req( too_big_or_final_path, toobig_true );
-    toobig_false = new IfFalseNode( toobig_iff );
+    toobig_false = new IfFalseNode(toobig_iff);
     transform_later(toobig_false);
   } else {
     // No initial test, just fall into next case
     assert(allocation_has_use || !expand_fast_path, "Should already have been handled");
     toobig_false = ctrl;
@@ -1409,10 +1469,11 @@
     result_phi_i_o->init_req(slow_result_path, i_o);
 
     // Name successful fast-path variables
     Node* fast_oop_ctrl;
     Node* fast_oop_rawmem;
+
     if (allocation_has_use) {
       Node* needgc_ctrl = NULL;
       result_phi_rawoop = new PhiNode(result_region, TypeRawPtr::BOTTOM);
 
       intx prefetch_lines = length != NULL ? AllocatePrefetchLines : AllocateInstancePrefetchLines;
@@ -1467,15 +1528,18 @@
   call->init_req(TypeFunc::FramePtr,  alloc->in(TypeFunc::FramePtr));
 
   call->init_req(TypeFunc::Parms+0, klass_node);
   if (length != NULL) {
     call->init_req(TypeFunc::Parms+1, length);
+  } else {
+    // Let the runtime know if this is a larval allocation
+    call->init_req(TypeFunc::Parms+1, _igvn.intcon(alloc->_larval));
   }
 
   // Copy debug information and adjust JVMState information, then replace
   // allocate node with the call
-  copy_call_debug_info((CallNode *) alloc,  call);
+  call->copy_call_debug_info(&_igvn, alloc);
   if (expand_fast_path) {
     call->set_cnt(PROB_UNLIKELY_MAG(4));  // Same effect as RC_UNCOMMON.
   } else {
     // Hook i_o projection to avoid its elimination during allocation
     // replacement (when only a slow call is generated).
@@ -1499,39 +1563,39 @@
   // An allocate node has separate memory projections for the uses on
   // the control and i_o paths. Replace the control memory projection with
   // result_phi_rawmem (unless we are only generating a slow call when
   // both memory projections are combined)
   if (expand_fast_path && _memproj_fallthrough != NULL) {
-    migrate_outs(_memproj_fallthrough, result_phi_rawmem);
+    _igvn.replace_in_uses(_memproj_fallthrough, result_phi_rawmem);
   }
   // Now change uses of _memproj_catchall to use _memproj_fallthrough and delete
   // _memproj_catchall so we end up with a call that has only 1 memory projection.
-  if (_memproj_catchall != NULL ) {
+  if (_memproj_catchall != NULL) {
     if (_memproj_fallthrough == NULL) {
       _memproj_fallthrough = new ProjNode(call, TypeFunc::Memory);
       transform_later(_memproj_fallthrough);
     }
-    migrate_outs(_memproj_catchall, _memproj_fallthrough);
+    _igvn.replace_in_uses(_memproj_catchall, _memproj_fallthrough);
     _igvn.remove_dead_node(_memproj_catchall);
   }
 
   // An allocate node has separate i_o projections for the uses on the control
   // and i_o paths. Always replace the control i_o projection with result i_o
   // otherwise incoming i_o become dead when only a slow call is generated
   // (it is different from memory projections where both projections are
   // combined in such case).
   if (_ioproj_fallthrough != NULL) {
-    migrate_outs(_ioproj_fallthrough, result_phi_i_o);
+    _igvn.replace_in_uses(_ioproj_fallthrough, result_phi_i_o);
   }
   // Now change uses of _ioproj_catchall to use _ioproj_fallthrough and delete
   // _ioproj_catchall so we end up with a call that has only 1 i_o projection.
-  if (_ioproj_catchall != NULL ) {
+  if (_ioproj_catchall != NULL) {
     if (_ioproj_fallthrough == NULL) {
       _ioproj_fallthrough = new ProjNode(call, TypeFunc::I_O);
       transform_later(_ioproj_fallthrough);
     }
-    migrate_outs(_ioproj_catchall, _ioproj_fallthrough);
+    _igvn.replace_in_uses(_ioproj_catchall, _ioproj_fallthrough);
     _igvn.remove_dead_node(_ioproj_catchall);
   }
 
   // if we generated only a slow call, we are done
   if (!expand_fast_path) {
@@ -1595,11 +1659,11 @@
     }
     assert(_resproj->outcnt() == 0, "all uses must be deleted");
     _igvn.remove_dead_node(_resproj);
   }
   if (_fallthroughcatchproj != NULL) {
-    migrate_outs(_fallthroughcatchproj, ctrl);
+    _igvn.replace_in_uses(_fallthroughcatchproj, ctrl);
     _igvn.remove_dead_node(_fallthroughcatchproj);
   }
   if (_catchallcatchproj != NULL) {
     _igvn.rehash_node_delayed(_catchallcatchproj);
     _catchallcatchproj->set_req(0, top());
@@ -1608,15 +1672,15 @@
     Node* catchnode = _fallthroughproj->unique_ctrl_out();
     _igvn.remove_dead_node(catchnode);
     _igvn.remove_dead_node(_fallthroughproj);
   }
   if (_memproj_fallthrough != NULL) {
-    migrate_outs(_memproj_fallthrough, mem);
+    _igvn.replace_in_uses(_memproj_fallthrough, mem);
     _igvn.remove_dead_node(_memproj_fallthrough);
   }
   if (_ioproj_fallthrough != NULL) {
-    migrate_outs(_ioproj_fallthrough, i_o);
+    _igvn.replace_in_uses(_ioproj_fallthrough, i_o);
     _igvn.remove_dead_node(_ioproj_fallthrough);
   }
   if (_memproj_catchall != NULL) {
     _igvn.rehash_node_delayed(_memproj_catchall);
     _memproj_catchall->set_req(0, top());
@@ -1738,18 +1802,17 @@
   }
 }
 
 // Helper for PhaseMacroExpand::expand_allocate_common.
 // Initializes the newly-allocated storage.
-Node*
-PhaseMacroExpand::initialize_object(AllocateNode* alloc,
-                                    Node* control, Node* rawmem, Node* object,
-                                    Node* klass_node, Node* length,
-                                    Node* size_in_bytes) {
+Node* PhaseMacroExpand::initialize_object(AllocateNode* alloc,
+                                          Node* control, Node* rawmem, Node* object,
+                                          Node* klass_node, Node* length,
+                                          Node* size_in_bytes) {
   InitializeNode* init = alloc->initialization();
   // Store the klass & mark bits
-  Node* mark_node = alloc->make_ideal_mark(&_igvn, object, control, rawmem);
+  Node* mark_node = alloc->make_ideal_mark(&_igvn, control, rawmem);
   if (!mark_node->is_Con()) {
     transform_later(mark_node);
   }
   rawmem = make_store(control, rawmem, object, oopDesc::mark_offset_in_bytes(), mark_node, TypeX_X->basic_type());
 
@@ -1777,10 +1840,12 @@
     // there can be two Allocates to one Initialize.  The answer in all these
     // edge cases is safety first.  It is always safe to clear immediately
     // within an Allocate, and then (maybe or maybe not) clear some more later.
     if (!(UseTLAB && ZeroTLAB)) {
       rawmem = ClearArrayNode::clear_memory(control, rawmem, object,
+                                            alloc->in(AllocateNode::DefaultValue),
+                                            alloc->in(AllocateNode::RawDefaultValue),
                                             header_size, size_in_bytes,
                                             &_igvn);
     }
   } else {
     if (!init->is_complete()) {
@@ -2157,10 +2222,12 @@
 
   if (!alock->is_eliminated()) {
     return false;
   }
 #ifdef ASSERT
+  const Type* obj_type = _igvn.type(alock->obj_node());
+  assert(!obj_type->isa_inlinetype() && !obj_type->is_inlinetypeptr(), "Eliminating lock on inline type");
   if (!alock->is_coarsened()) {
     // Check that new "eliminated" BoxLock node is created.
     BoxLockNode* oldbox = alock->box_node()->as_BoxLock();
     assert(oldbox->is_eliminated(), "should be done already");
   }
@@ -2438,10 +2505,52 @@
     // Optimize test; set region slot 2
     slow_path = opt_bits_test(ctrl, region, 2, flock, 0, 0);
     mem_phi->init_req(2, mem);
   }
 
+  const TypeOopPtr* objptr = _igvn.type(obj)->make_oopptr();
+  if (objptr->can_be_inline_type()) {
+    // Deoptimize and re-execute if a value
+    assert(EnableValhalla, "should only be used if inline types are enabled");
+    Node* mark = make_load(slow_path, mem, obj, oopDesc::mark_offset_in_bytes(), TypeX_X, TypeX_X->basic_type());
+    Node* value_mask = _igvn.MakeConX(markWord::always_locked_pattern);
+    Node* is_value = _igvn.transform(new AndXNode(mark, value_mask));
+    Node* cmp = _igvn.transform(new CmpXNode(is_value, value_mask));
+    Node* bol = _igvn.transform(new BoolNode(cmp, BoolTest::eq));
+    Node* unc_ctrl = generate_slow_guard(&slow_path, bol, NULL);
+
+    int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_class_check, Deoptimization::Action_none);
+    address call_addr = SharedRuntime::uncommon_trap_blob()->entry_point();
+    const TypePtr* no_memory_effects = NULL;
+    JVMState* jvms = lock->jvms();
+    CallNode* unc = new CallStaticJavaNode(OptoRuntime::uncommon_trap_Type(), call_addr, "uncommon_trap",
+                                           jvms->bci(), no_memory_effects);
+
+    unc->init_req(TypeFunc::Control, unc_ctrl);
+    unc->init_req(TypeFunc::I_O, lock->i_o());
+    unc->init_req(TypeFunc::Memory, mem); // may gc ptrs
+    unc->init_req(TypeFunc::FramePtr,  lock->in(TypeFunc::FramePtr));
+    unc->init_req(TypeFunc::ReturnAdr, lock->in(TypeFunc::ReturnAdr));
+    unc->init_req(TypeFunc::Parms+0, _igvn.intcon(trap_request));
+    unc->set_cnt(PROB_UNLIKELY_MAG(4));
+    unc->copy_call_debug_info(&_igvn, lock);
+
+    assert(unc->peek_monitor_box() == box, "wrong monitor");
+    assert(unc->peek_monitor_obj() == obj, "wrong monitor");
+
+    // pop monitor and push obj back on stack: we trap before the monitorenter
+    unc->pop_monitor();
+    unc->grow_stack(unc->jvms(), 1);
+    unc->set_stack(unc->jvms(), unc->jvms()->stk_size()-1, obj);
+
+    _igvn.register_new_node_with_optimizer(unc);
+
+    Node* ctrl = _igvn.transform(new ProjNode(unc, TypeFunc::Control));
+    Node* halt = _igvn.transform(new HaltNode(ctrl, lock->in(TypeFunc::FramePtr), "monitor enter on value-type"));
+    C->root()->add_req(halt);
+  }
+
   // Make slow path call
   CallNode *call = make_slow_call((CallNode *) lock, OptoRuntime::complete_monitor_enter_Type(),
                                   OptoRuntime::complete_monitor_locking_Java(), NULL, slow_path,
                                   obj, box, NULL);
 
@@ -2539,10 +2648,215 @@
   mem_phi->init_req(2, mem);
   transform_later(mem_phi);
   _igvn.replace_node(_memproj_fallthrough, mem_phi);
 }
 
+// An inline type might be returned from the call but we don't know its
+// type. Either we get a buffered inline type (and nothing needs to be done)
+// or one of the inlines being returned is the klass of the inline type
+// and we need to allocate an inline type instance of that type and
+// initialize it with other values being returned. In that case, we
+// first try a fast path allocation and initialize the value with the
+// inline klass's pack handler or we fall back to a runtime call.
+void PhaseMacroExpand::expand_mh_intrinsic_return(CallStaticJavaNode* call) {
+  assert(call->method()->is_method_handle_intrinsic(), "must be a method handle intrinsic call");
+  Node* ret = call->proj_out_or_null(TypeFunc::Parms);
+  if (ret == NULL) {
+    return;
+  }
+  const TypeFunc* tf = call->_tf;
+  const TypeTuple* domain = OptoRuntime::store_inline_type_fields_Type()->domain_cc();
+  const TypeFunc* new_tf = TypeFunc::make(tf->domain_sig(), tf->domain_cc(), tf->range_sig(), domain);
+  call->_tf = new_tf;
+  // Make sure the change of type is applied before projections are processed by igvn
+  _igvn.set_type(call, call->Value(&_igvn));
+  _igvn.set_type(ret, ret->Value(&_igvn));
+
+  // Before any new projection is added:
+  CallProjections* projs = call->extract_projections(true, true);
+
+  Node* ctl = new Node(1);
+  Node* mem = new Node(1);
+  Node* io = new Node(1);
+  Node* ex_ctl = new Node(1);
+  Node* ex_mem = new Node(1);
+  Node* ex_io = new Node(1);
+  Node* res = new Node(1);
+
+  Node* cast = transform_later(new CastP2XNode(ctl, res));
+  Node* mask = MakeConX(0x1);
+  Node* masked = transform_later(new AndXNode(cast, mask));
+  Node* cmp = transform_later(new CmpXNode(masked, mask));
+  Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq));
+  IfNode* allocation_iff = new IfNode(ctl, bol, PROB_MAX, COUNT_UNKNOWN);
+  transform_later(allocation_iff);
+  Node* allocation_ctl = transform_later(new IfTrueNode(allocation_iff));
+  Node* no_allocation_ctl = transform_later(new IfFalseNode(allocation_iff));
+
+  Node* no_allocation_res = transform_later(new CheckCastPPNode(no_allocation_ctl, res, TypeInstPtr::BOTTOM));
+
+  Node* mask2 = MakeConX(-2);
+  Node* masked2 = transform_later(new AndXNode(cast, mask2));
+  Node* rawklassptr = transform_later(new CastX2PNode(masked2));
+  Node* klass_node = transform_later(new CheckCastPPNode(allocation_ctl, rawklassptr, TypeKlassPtr::OBJECT_OR_NULL));
+
+  Node* slowpath_bol = NULL;
+  Node* top_adr = NULL;
+  Node* old_top = NULL;
+  Node* new_top = NULL;
+  if (UseTLAB) {
+    Node* end_adr = NULL;
+    set_eden_pointers(top_adr, end_adr);
+    Node* end = make_load(ctl, mem, end_adr, 0, TypeRawPtr::BOTTOM, T_ADDRESS);
+    old_top = new LoadPNode(ctl, mem, top_adr, TypeRawPtr::BOTTOM, TypeRawPtr::BOTTOM, MemNode::unordered);
+    transform_later(old_top);
+    Node* layout_val = make_load(NULL, mem, klass_node, in_bytes(Klass::layout_helper_offset()), TypeInt::INT, T_INT);
+    Node* size_in_bytes = ConvI2X(layout_val);
+    new_top = new AddPNode(top(), old_top, size_in_bytes);
+    transform_later(new_top);
+    Node* slowpath_cmp = new CmpPNode(new_top, end);
+    transform_later(slowpath_cmp);
+    slowpath_bol = new BoolNode(slowpath_cmp, BoolTest::ge);
+    transform_later(slowpath_bol);
+  } else {
+    slowpath_bol = intcon(1);
+    top_adr = top();
+    old_top = top();
+    new_top = top();
+  }
+  IfNode* slowpath_iff = new IfNode(allocation_ctl, slowpath_bol, PROB_UNLIKELY_MAG(4), COUNT_UNKNOWN);
+  transform_later(slowpath_iff);
+
+  Node* slowpath_true = new IfTrueNode(slowpath_iff);
+  transform_later(slowpath_true);
+
+  CallStaticJavaNode* slow_call = new CallStaticJavaNode(OptoRuntime::store_inline_type_fields_Type(),
+                                                         StubRoutines::store_inline_type_fields_to_buf(),
+                                                         "store_inline_type_fields",
+                                                         call->jvms()->bci(),
+                                                         TypePtr::BOTTOM);
+  slow_call->init_req(TypeFunc::Control, slowpath_true);
+  slow_call->init_req(TypeFunc::Memory, mem);
+  slow_call->init_req(TypeFunc::I_O, io);
+  slow_call->init_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr));
+  slow_call->init_req(TypeFunc::ReturnAdr, call->in(TypeFunc::ReturnAdr));
+  slow_call->init_req(TypeFunc::Parms, res);
+
+  Node* slow_ctl = transform_later(new ProjNode(slow_call, TypeFunc::Control));
+  Node* slow_mem = transform_later(new ProjNode(slow_call, TypeFunc::Memory));
+  Node* slow_io = transform_later(new ProjNode(slow_call, TypeFunc::I_O));
+  Node* slow_res = transform_later(new ProjNode(slow_call, TypeFunc::Parms));
+  Node* slow_catc = transform_later(new CatchNode(slow_ctl, slow_io, 2));
+  Node* slow_norm = transform_later(new CatchProjNode(slow_catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci));
+  Node* slow_excp = transform_later(new CatchProjNode(slow_catc, CatchProjNode::catch_all_index,    CatchProjNode::no_handler_bci));
+
+  Node* ex_r = new RegionNode(3);
+  Node* ex_mem_phi = new PhiNode(ex_r, Type::MEMORY, TypePtr::BOTTOM);
+  Node* ex_io_phi = new PhiNode(ex_r, Type::ABIO);
+  ex_r->init_req(1, slow_excp);
+  ex_mem_phi->init_req(1, slow_mem);
+  ex_io_phi->init_req(1, slow_io);
+  ex_r->init_req(2, ex_ctl);
+  ex_mem_phi->init_req(2, ex_mem);
+  ex_io_phi->init_req(2, ex_io);
+
+  transform_later(ex_r);
+  transform_later(ex_mem_phi);
+  transform_later(ex_io_phi);
+
+  Node* slowpath_false = new IfFalseNode(slowpath_iff);
+  transform_later(slowpath_false);
+  Node* rawmem = new StorePNode(slowpath_false, mem, top_adr, TypeRawPtr::BOTTOM, new_top, MemNode::unordered);
+  transform_later(rawmem);
+  Node* mark_node = makecon(TypeRawPtr::make((address)markWord::always_locked_prototype().value()));
+  rawmem = make_store(slowpath_false, rawmem, old_top, oopDesc::mark_offset_in_bytes(), mark_node, T_ADDRESS);
+  rawmem = make_store(slowpath_false, rawmem, old_top, oopDesc::klass_offset_in_bytes(), klass_node, T_METADATA);
+  if (UseCompressedClassPointers) {
+    rawmem = make_store(slowpath_false, rawmem, old_top, oopDesc::klass_gap_offset_in_bytes(), intcon(0), T_INT);
+  }
+  Node* fixed_block  = make_load(slowpath_false, rawmem, klass_node, in_bytes(InstanceKlass::adr_inlineklass_fixed_block_offset()), TypeRawPtr::BOTTOM, T_ADDRESS);
+  Node* pack_handler = make_load(slowpath_false, rawmem, fixed_block, in_bytes(InlineKlass::pack_handler_offset()), TypeRawPtr::BOTTOM, T_ADDRESS);
+
+  CallLeafNoFPNode* handler_call = new CallLeafNoFPNode(OptoRuntime::pack_inline_type_Type(),
+                                                        NULL,
+                                                        "pack handler",
+                                                        TypeRawPtr::BOTTOM);
+  handler_call->init_req(TypeFunc::Control, slowpath_false);
+  handler_call->init_req(TypeFunc::Memory, rawmem);
+  handler_call->init_req(TypeFunc::I_O, top());
+  handler_call->init_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr));
+  handler_call->init_req(TypeFunc::ReturnAdr, top());
+  handler_call->init_req(TypeFunc::Parms, pack_handler);
+  handler_call->init_req(TypeFunc::Parms+1, old_top);
+
+  // We don't know how many values are returned. This assumes the
+  // worst case, that all available registers are used.
+  for (uint i = TypeFunc::Parms+1; i < domain->cnt(); i++) {
+    if (domain->field_at(i) == Type::HALF) {
+      slow_call->init_req(i, top());
+      handler_call->init_req(i+1, top());
+      continue;
+    }
+    Node* proj = transform_later(new ProjNode(call, i));
+    slow_call->init_req(i, proj);
+    handler_call->init_req(i+1, proj);
+  }
+
+  // We can safepoint at that new call
+  slow_call->copy_call_debug_info(&_igvn, call);
+  transform_later(slow_call);
+  transform_later(handler_call);
+
+  Node* handler_ctl = transform_later(new ProjNode(handler_call, TypeFunc::Control));
+  rawmem = transform_later(new ProjNode(handler_call, TypeFunc::Memory));
+  Node* slowpath_false_res = transform_later(new ProjNode(handler_call, TypeFunc::Parms));
+
+  MergeMemNode* slowpath_false_mem = MergeMemNode::make(mem);
+  slowpath_false_mem->set_memory_at(Compile::AliasIdxRaw, rawmem);
+  transform_later(slowpath_false_mem);
+
+  Node* r = new RegionNode(4);
+  Node* mem_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM);
+  Node* io_phi = new PhiNode(r, Type::ABIO);
+  Node* res_phi = new PhiNode(r, TypeInstPtr::BOTTOM);
+
+  r->init_req(1, no_allocation_ctl);
+  mem_phi->init_req(1, mem);
+  io_phi->init_req(1, io);
+  res_phi->init_req(1, no_allocation_res);
+  r->init_req(2, slow_norm);
+  mem_phi->init_req(2, slow_mem);
+  io_phi->init_req(2, slow_io);
+  res_phi->init_req(2, slow_res);
+  r->init_req(3, handler_ctl);
+  mem_phi->init_req(3, slowpath_false_mem);
+  io_phi->init_req(3, io);
+  res_phi->init_req(3, slowpath_false_res);
+
+  transform_later(r);
+  transform_later(mem_phi);
+  transform_later(io_phi);
+  transform_later(res_phi);
+
+  assert(projs->nb_resproj == 1, "unexpected number of results");
+  _igvn.replace_in_uses(projs->fallthrough_catchproj, r);
+  _igvn.replace_in_uses(projs->fallthrough_memproj, mem_phi);
+  _igvn.replace_in_uses(projs->fallthrough_ioproj, io_phi);
+  _igvn.replace_in_uses(projs->resproj[0], res_phi);
+  _igvn.replace_in_uses(projs->catchall_catchproj, ex_r);
+  _igvn.replace_in_uses(projs->catchall_memproj, ex_mem_phi);
+  _igvn.replace_in_uses(projs->catchall_ioproj, ex_io_phi);
+
+  _igvn.replace_node(ctl, projs->fallthrough_catchproj);
+  _igvn.replace_node(mem, projs->fallthrough_memproj);
+  _igvn.replace_node(io, projs->fallthrough_ioproj);
+  _igvn.replace_node(res, projs->resproj[0]);
+  _igvn.replace_node(ex_ctl, projs->catchall_catchproj);
+  _igvn.replace_node(ex_mem, projs->catchall_memproj);
+  _igvn.replace_node(ex_io, projs->catchall_ioproj);
+ }
+
 void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) {
   assert(check->in(SubTypeCheckNode::Control) == NULL, "should be pinned");
   Node* bol = check->unique_out();
   Node* obj_or_subklass = check->in(SubTypeCheckNode::ObjOrSubKlass);
   Node* superklass = check->in(SubTypeCheckNode::SuperKlass);
@@ -2564,11 +2878,11 @@
     Node* subklass = NULL;
     if (_igvn.type(obj_or_subklass)->isa_klassptr()) {
       subklass = obj_or_subklass;
     } else {
       Node* k_adr = basic_plus_adr(obj_or_subklass, oopDesc::klass_offset_in_bytes());
-      subklass = _igvn.transform(LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), k_adr, TypeInstPtr::KLASS));
+      subklass = _igvn.transform(LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), k_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
     }
 
     Node* not_subtype_ctrl = Phase::gen_subtype_check(subklass, superklass, &ctrl, NULL, _igvn);
 
     _igvn.replace_input_of(iff, 0, C->top());
@@ -2620,13 +2934,17 @@
       switch (n->class_id()) {
       case Node::Class_Allocate:
       case Node::Class_AllocateArray:
         success = eliminate_allocate_node(n->as_Allocate());
         break;
-      case Node::Class_CallStaticJava:
-        success = eliminate_boxing_node(n->as_CallStaticJava());
+      case Node::Class_CallStaticJava: {
+        CallStaticJavaNode* call = n->as_CallStaticJava();
+        if (!call->method()->is_method_handle_intrinsic()) {
+          success = eliminate_boxing_node(n->as_CallStaticJava());
+        }
         break;
+      }
       case Node::Class_Lock:
       case Node::Class_Unlock:
         assert(!n->as_AbstractLock()->is_eliminated(), "sanity");
         _has_locks = true;
         break;
@@ -2668,14 +2986,17 @@
         // Remove it from macro list and put on IGVN worklist to optimize.
         C->remove_macro_node(n);
         _igvn._worklist.push(n);
         success = true;
       } else if (n->Opcode() == Op_CallStaticJava) {
-        // Remove it from macro list and put on IGVN worklist to optimize.
-        C->remove_macro_node(n);
-        _igvn._worklist.push(n);
-        success = true;
+        CallStaticJavaNode* call = n->as_CallStaticJava();
+        if (!call->method()->is_method_handle_intrinsic()) {
+          // Remove it from macro list and put on IGVN worklist to optimize.
+          C->remove_macro_node(n);
+          _igvn._worklist.push(n);
+          success = true;
+        }
       } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
         _igvn.replace_node(n, n->in(1));
         success = true;
 #if INCLUDE_RTM_OPT
       } else if ((n->Opcode() == Op_Opaque3) && ((Opaque3Node*)n)->rtm_opt()) {
@@ -2765,10 +3086,15 @@
       break;
     case Node::Class_SubTypeCheck:
       expand_subtypecheck_node(n->as_SubTypeCheck());
       assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list");
       break;
+    case Node::Class_CallStaticJava:
+      expand_mh_intrinsic_return(n->as_CallStaticJava());
+      C->remove_macro_node(n);
+      assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list");
+      break;
     default:
       assert(false, "unknown node type in macro list");
     }
     assert(C->macro_count() < macro_count, "must have deleted a node from macro list");
     if (C->failing())  return true;
diff a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -21,11 +21,13 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "ci/ciFlatArrayKlass.hpp"
 #include "classfile/javaClasses.hpp"
+#include "classfile/systemDictionary.hpp"
 #include "compiler/compileLog.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/c2/barrierSetC2.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/resourceArea.hpp"
@@ -34,10 +36,11 @@
 #include "opto/arraycopynode.hpp"
 #include "opto/cfgnode.hpp"
 #include "opto/compile.hpp"
 #include "opto/connode.hpp"
 #include "opto/convertnode.hpp"
+#include "opto/inlinetypenode.hpp"
 #include "opto/loopnode.hpp"
 #include "opto/machnode.hpp"
 #include "opto/matcher.hpp"
 #include "opto/memnode.hpp"
 #include "opto/mulnode.hpp"
@@ -235,11 +238,11 @@
     assert(alias_idx >= Compile::AliasIdxRaw, "must not be a bad alias_idx");
     bool consistent =  adr_check == NULL || adr_check->empty() ||
                        phase->C->must_alias(adr_check, alias_idx );
     // Sometimes dead array references collapse to a[-1], a[-2], or a[-3]
     if( !consistent && adr_check != NULL && !adr_check->empty() &&
-               tp->isa_aryptr() &&        tp->offset() == Type::OffsetBot &&
+        tp->isa_aryptr() &&        tp->offset() == Type::OffsetBot &&
         adr_check->isa_aryptr() && adr_check->offset() != Type::OffsetBot &&
         ( adr_check->offset() == arrayOopDesc::length_offset_in_bytes() ||
           adr_check->offset() == oopDesc::klass_offset_in_bytes() ||
           adr_check->offset() == oopDesc::mark_offset_in_bytes() ) ) {
       // don't assert if it is dead code.
@@ -842,10 +845,11 @@
   case T_SHORT:   load = new LoadSNode (ctl, mem, adr, adr_type, rt->is_int(),  mo, control_dependency); break;
   case T_LONG:    load = new LoadLNode (ctl, mem, adr, adr_type, rt->is_long(), mo, control_dependency); break;
   case T_FLOAT:   load = new LoadFNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency); break;
   case T_DOUBLE:  load = new LoadDNode (ctl, mem, adr, adr_type, rt,            mo, control_dependency); break;
   case T_ADDRESS: load = new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(),  mo, control_dependency); break;
+  case T_INLINE_TYPE:
   case T_OBJECT:
 #ifdef _LP64
     if (adr->bottom_type()->is_ptr_to_narrowoop()) {
       load = new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency);
     } else
@@ -969,13 +973,17 @@
       assert(addp->in(AddPNode::Base) == addp->in(AddPNode::Address), "should be");
       addp->set_req(AddPNode::Base, src);
       addp->set_req(AddPNode::Address, src);
 
       const TypeAryPtr* ary_t = phase->type(in(MemNode::Address))->isa_aryptr();
-      BasicType ary_elem  = ary_t->klass()->as_array_klass()->element_type()->basic_type();
+      BasicType ary_elem = ary_t->klass()->as_array_klass()->element_type()->basic_type();
       uint header = arrayOopDesc::base_offset_in_bytes(ary_elem);
       uint shift  = exact_log2(type2aelembytes(ary_elem));
+      if (ary_t->klass()->is_flat_array_klass()) {
+        ciFlatArrayKlass* vak = ary_t->klass()->as_flat_array_klass();
+        shift = vak->log2_element_size();
+      }
 
       Node* diff = phase->transform(new SubINode(ac->in(ArrayCopyNode::SrcPos), ac->in(ArrayCopyNode::DestPos)));
 #ifdef _LP64
       diff = phase->transform(new ConvI2LNode(diff));
 #endif
@@ -1099,10 +1107,16 @@
         (ld_off >= st->in(0)->as_Allocate()->minimum_header_size())) {
       // return a zero value for the load's basic type
       // (This is one of the few places where a generic PhaseTransform
       // can create new nodes.  Think of it as lazily manifesting
       // virtually pre-existing constants.)
+      assert(memory_type() != T_INLINE_TYPE, "should not be used for inline types");
+      Node* default_value = ld_alloc->in(AllocateNode::DefaultValue);
+      if (default_value != NULL) {
+        return default_value;
+      }
+      assert(ld_alloc->in(AllocateNode::RawDefaultValue) == NULL, "default value may not be null");
       return phase->zerocon(memory_type());
     }
 
     // A load from an initialization barrier can match a captured store.
     if (st->is_Proj() && st->in(0)->is_Initialize()) {
@@ -1156,10 +1170,37 @@
 }
 
 //------------------------------Identity---------------------------------------
 // Loads are identity if previous store is to same address
 Node* LoadNode::Identity(PhaseGVN* phase) {
+  // Loading from an InlineTypePtr? The InlineTypePtr has the values of
+  // all fields as input. Look for the field with matching offset.
+  Node* addr = in(Address);
+  intptr_t offset;
+  Node* base = AddPNode::Ideal_base_and_offset(addr, phase, offset);
+  if (base != NULL && base->is_InlineTypePtr() && offset > oopDesc::klass_offset_in_bytes()) {
+    Node* value = base->as_InlineTypePtr()->field_value_by_offset((int)offset, true);
+    if (value->is_InlineType()) {
+      // Non-flattened inline type field
+      InlineTypeNode* vt = value->as_InlineType();
+      if (vt->is_allocated(phase)) {
+        value = vt->get_oop();
+      } else {
+        // Not yet allocated, bail out
+        value = NULL;
+      }
+    }
+    if (value != NULL) {
+      if (Opcode() == Op_LoadN) {
+        // Encode oop value if we are loading a narrow oop
+        assert(!phase->type(value)->isa_narrowoop(), "should already be decoded");
+        value = phase->transform(new EncodePNode(value, bottom_type()));
+      }
+      return value;
+    }
+  }
+
   // If the previous store-maker is the right kind of Store, and the store is
   // to the same address, then we are equal to the value stored.
   Node* mem = in(Memory);
   Node* value = can_see_stored_value(mem, phase);
   if( value ) {
@@ -1713,15 +1754,19 @@
       set_req(MemNode::Memory, prev_mem);
       return this;
     }
   }
 
-  AllocateNode* alloc = is_new_object_mark_load(phase);
-  if (alloc != NULL && alloc->Opcode() == Op_Allocate && UseBiasedLocking) {
+  AllocateNode* alloc = AllocateNode::Ideal_allocation(address, phase);
+  if (alloc != NULL && mem->is_Proj() &&
+      mem->in(0) != NULL &&
+      mem->in(0) == alloc->initialization() &&
+      Opcode() == Op_LoadX &&
+      alloc->initialization()->proj_out_or_null(0) != NULL) {
     InitializeNode* init = alloc->initialization();
     Node* control = init->proj_out(0);
-    return alloc->make_ideal_mark(phase, address, control, mem);
+    return alloc->make_ideal_mark(phase, control, mem);
   }
 
   return progress ? this : NULL;
 }
 
@@ -1809,10 +1854,11 @@
     // In fact, that could have been the original type of p1, and p1 could have
     // had an original form like p1:(AddP x x (LShiftL quux 3)), where the
     // expression (LShiftL quux 3) independently optimized to the constant 8.
     if ((t->isa_int() == NULL) && (t->isa_long() == NULL)
         && (_type->isa_vect() == NULL)
+        && t->isa_inlinetype() == NULL
         && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
       // t might actually be lower than _type, if _type is a unique
       // concrete subclass of abstract class t.
       if (off_beyond_header || off == Type::OffsetBot) {  // is the offset beyond the header?
         const Type* jt = t->join_speculative(_type);
@@ -1843,56 +1889,85 @@
     }
   } else if (tp->base() == Type::InstPtr) {
     assert( off != Type::OffsetBot ||
             // arrays can be cast to Objects
             tp->is_oopptr()->klass()->is_java_lang_Object() ||
+            tp->is_oopptr()->klass() == ciEnv::current()->Class_klass() ||
             // unsafe field access may not have a constant offset
             C->has_unsafe_access(),
             "Field accesses must be precise" );
     // For oop loads, we expect the _type to be precise.
 
-    // Optimize loads from constant fields.
+    const TypeInstPtr* tinst = tp->is_instptr();
+    BasicType bt = memory_type();
+
     const TypeInstPtr* tinst = tp->is_instptr();
     ciObject* const_oop = tinst->const_oop();
     if (!is_mismatched_access() && off != Type::OffsetBot && const_oop != NULL && const_oop->is_instance()) {
-      const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), memory_type());
+      ciType* mirror_type = const_oop->as_instance()->java_mirror_type();
+      if (mirror_type != NULL && mirror_type->is_inlinetype()) {
+        ciInlineKlass* vk = mirror_type->as_inline_klass();
+        if (off == vk->default_value_offset()) {
+          // Loading a special hidden field that contains the oop of the default inline type
+          const Type* const_oop = TypeInstPtr::make(vk->default_instance());
+          return (bt == T_NARROWOOP) ? const_oop->make_narrowoop() : const_oop;
+        }
+      }
+      const Type* con_type = Type::make_constant_from_field(const_oop->as_instance(), off, is_unsigned(), bt);
       if (con_type != NULL) {
         return con_type;
       }
     }
   } else if (tp->base() == Type::KlassPtr) {
     assert( off != Type::OffsetBot ||
             // arrays can be cast to Objects
+            tp->is_klassptr()->klass() == NULL ||
             tp->is_klassptr()->klass()->is_java_lang_Object() ||
             // also allow array-loading from the primary supertype
             // array during subtype checks
             Opcode() == Op_LoadKlass,
             "Field accesses must be precise" );
     // For klass/static loads, we expect the _type to be precise
-  } else if (tp->base() == Type::RawPtr && adr->is_Load() && off == 0) {
-    /* With mirrors being an indirect in the Klass*
-     * the VM is now using two loads. LoadKlass(LoadP(LoadP(Klass, mirror_offset), zero_offset))
-     * The LoadP from the Klass has a RawPtr type (see LibraryCallKit::load_mirror_from_klass).
-     *
-     * So check the type and klass of the node before the LoadP.
-     */
-    Node* adr2 = adr->in(MemNode::Address);
-    const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
-    if (tkls != NULL && !StressReflectiveCode) {
-      ciKlass* klass = tkls->klass();
-      if (klass->is_loaded() && tkls->klass_is_exact() && tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
-        assert(adr->Opcode() == Op_LoadP, "must load an oop from _java_mirror");
-        assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
-        return TypeInstPtr::make(klass->java_mirror());
+  } else if (tp->base() == Type::RawPtr && !StressReflectiveCode) {
+    if (adr->is_Load() && off == 0) {
+      /* With mirrors being an indirect in the Klass*
+       * the VM is now using two loads. LoadKlass(LoadP(LoadP(Klass, mirror_offset), zero_offset))
+       * The LoadP from the Klass has a RawPtr type (see LibraryCallKit::load_mirror_from_klass).
+       *
+       * So check the type and klass of the node before the LoadP.
+       */
+      Node* adr2 = adr->in(MemNode::Address);
+      const TypeKlassPtr* tkls = phase->type(adr2)->isa_klassptr();
+      if (tkls != NULL) {
+        ciKlass* klass = tkls->klass();
+        if (klass != NULL && klass->is_loaded() && tkls->klass_is_exact() && tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
+          assert(adr->Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+          assert(Opcode() == Op_LoadP, "must load an oop from _java_mirror");
+          return TypeInstPtr::make(klass->java_mirror());
+        }
+      }
+    } else {
+      // Check for a load of the default value offset from the InlineKlassFixedBlock:
+      // LoadI(LoadP(inline_klass, adr_inlineklass_fixed_block_offset), default_value_offset_offset)
+      intptr_t offset = 0;
+      Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset);
+      if (base != NULL && base->is_Load() && offset == in_bytes(InlineKlass::default_value_offset_offset())) {
+        const TypeKlassPtr* tkls = phase->type(base->in(MemNode::Address))->isa_klassptr();
+        if (tkls != NULL && tkls->is_loaded() && tkls->klass_is_exact() && tkls->isa_inlinetype() &&
+            tkls->offset() == in_bytes(InstanceKlass::adr_inlineklass_fixed_block_offset())) {
+          assert(base->Opcode() == Op_LoadP, "must load an oop from klass");
+          assert(Opcode() == Op_LoadI, "must load an int from fixed block");
+          return TypeInt::make(tkls->klass()->as_inline_klass()->default_value_offset());
+        }
       }
     }
   }
 
   const TypeKlassPtr *tkls = tp->isa_klassptr();
   if (tkls != NULL && !StressReflectiveCode) {
     ciKlass* klass = tkls->klass();
-    if (klass->is_loaded() && tkls->klass_is_exact()) {
+    if (tkls->is_loaded() && tkls->klass_is_exact()) {
       // We are loading a field from a Klass metaobject whose identity
       // is known at compile time (the type is "exact" or "precise").
       // Check for fields we know are maintained as constants by the VM.
       if (tkls->offset() == in_bytes(Klass::super_check_offset_offset())) {
         // The field is Klass::_super_check_offset.  Return its (constant) value.
@@ -1915,11 +1990,11 @@
     }
 
     // We can still check if we are loading from the primary_supers array at a
     // shallow enough depth.  Even though the klass is not exact, entries less
     // than or equal to its super depth are correct.
-    if (klass->is_loaded() ) {
+    if (tkls->is_loaded()) {
       ciType *inner = klass;
       while( inner->is_obj_array_klass() )
         inner = inner->as_obj_array_klass()->base_element_type();
       if( inner->is_instance_klass() &&
           !inner->as_instance_klass()->flags().is_interface() ) {
@@ -2120,11 +2195,12 @@
 }
 
 //=============================================================================
 //----------------------------LoadKlassNode::make------------------------------
 // Polymorphic factory method:
-Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) {
+Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at,
+                          const TypeKlassPtr* tk) {
   // sanity check the alias category against the created node type
   const TypePtr *adr_type = adr->bottom_type()->isa_ptr();
   assert(adr_type != NULL, "expecting TypeKlassPtr");
 #ifdef _LP64
   if (adr_type->is_ptr_to_narrowklass()) {
@@ -2207,65 +2283,69 @@
         // Return precise klass
         return TypeKlassPtr::make(ik);
       }
 
       // Return root of possible klass
-      return TypeKlassPtr::make(TypePtr::NotNull, ik, 0/*offset*/);
+      return TypeKlassPtr::make(TypePtr::NotNull, ik, Type::Offset(0), tinst->flatten_array());
     }
   }
 
   // Check for loading klass from an array
   const TypeAryPtr *tary = tp->isa_aryptr();
-  if( tary != NULL ) {
+  if (tary != NULL) {
     ciKlass *tary_klass = tary->klass();
     if (tary_klass != NULL   // can be NULL when at BOTTOM or TOP
         && tary->offset() == oopDesc::klass_offset_in_bytes()) {
       if (tary->klass_is_exact()) {
         return TypeKlassPtr::make(tary_klass);
       }
-      ciArrayKlass *ak = tary->klass()->as_array_klass();
+      ciArrayKlass* ak = tary_klass->as_array_klass();
       // If the klass is an object array, we defer the question to the
       // array component klass.
-      if( ak->is_obj_array_klass() ) {
-        assert( ak->is_loaded(), "" );
+      if (ak->is_obj_array_klass()) {
+        assert(ak->is_loaded(), "");
         ciKlass *base_k = ak->as_obj_array_klass()->base_element_klass();
-        if( base_k->is_loaded() && base_k->is_instance_klass() ) {
-          ciInstanceKlass* ik = base_k->as_instance_klass();
+        if (base_k->is_loaded() && base_k->is_instance_klass()) {
+          ciInstanceKlass *ik = base_k->as_instance_klass();
           // See if we can become precise: no subklasses and no interface
           if (!ik->is_interface() && !ik->has_subklass()) {
             // Add a dependence; if any subclass added we need to recompile
             if (!ik->is_final()) {
               phase->C->dependencies()->assert_leaf_type(ik);
             }
             // Return precise array klass
             return TypeKlassPtr::make(ak);
           }
         }
-        return TypeKlassPtr::make(TypePtr::NotNull, ak, 0/*offset*/);
-      } else {                  // Found a type-array?
-        assert( ak->is_type_array_klass(), "" );
+        return TypeKlassPtr::make(TypePtr::NotNull, ak, Type::Offset(0));
+      } else if (ak->is_type_array_klass()) {
         return TypeKlassPtr::make(ak); // These are always precise
       }
     }
   }
 
   // Check for loading klass from an array klass
   const TypeKlassPtr *tkls = tp->isa_klassptr();
   if (tkls != NULL && !StressReflectiveCode) {
-    ciKlass* klass = tkls->klass();
-    if( !klass->is_loaded() )
+    if (!tkls->is_loaded()) {
       return _type;             // Bail out if not loaded
+    }
+    ciKlass* klass = tkls->klass();
     if( klass->is_obj_array_klass() &&
         tkls->offset() == in_bytes(ObjArrayKlass::element_klass_offset())) {
       ciKlass* elem = klass->as_obj_array_klass()->element_klass();
       // // Always returning precise element type is incorrect,
       // // e.g., element type could be object and array may contain strings
       // return TypeKlassPtr::make(TypePtr::Constant, elem, 0);
 
       // The array's TypeKlassPtr was declared 'precise' or 'not precise'
       // according to the element type's subclassing.
-      return TypeKlassPtr::make(tkls->ptr(), elem, 0/*offset*/);
+      return TypeKlassPtr::make(tkls->ptr(), elem, Type::Offset(0));
+    } else if (klass->is_flat_array_klass() &&
+               tkls->offset() == in_bytes(ObjArrayKlass::element_klass_offset())) {
+      ciKlass* elem = klass->as_flat_array_klass()->element_klass();
+      return TypeKlassPtr::make(tkls->ptr(), elem, Type::Offset(0), /* flatten_array= */ true);
     }
     if( klass->is_instance_klass() && tkls->klass_is_exact() &&
         tkls->offset() == in_bytes(Klass::super_offset())) {
       ciKlass* sup = klass->as_instance_klass()->super();
       // The field is Klass::_super.  Return its (constant) value.
@@ -2469,10 +2549,11 @@
   case T_LONG:    return new StoreLNode(ctl, mem, adr, adr_type, val, mo);
   case T_FLOAT:   return new StoreFNode(ctl, mem, adr, adr_type, val, mo);
   case T_DOUBLE:  return new StoreDNode(ctl, mem, adr, adr_type, val, mo);
   case T_METADATA:
   case T_ADDRESS:
+  case T_INLINE_TYPE:
   case T_OBJECT:
 #ifdef _LP64
     if (adr->bottom_type()->is_ptr_to_narrowoop()) {
       val = gvn.transform(new EncodePNode(val, val->bottom_type()->make_narrowoop()));
       return new StoreNNode(ctl, mem, adr, adr_type, val, mo);
@@ -2529,11 +2610,11 @@
   Node* address = in(MemNode::Address);
   // Back-to-back stores to same address?  Fold em up.  Generally
   // unsafe if I have intervening uses...  Also disallowed for StoreCM
   // since they must follow each StoreP operation.  Redundant StoreCMs
   // are eliminated just before matching in final_graph_reshape.
-  {
+  if (phase->C->get_adr_type(phase->C->get_alias_index(adr_type())) != TypeAryPtr::INLINES) {
     Node* st = mem;
     // If Store 'st' has more than one use, we cannot fold 'st' away.
     // For example, 'st' might be the final state at a conditional
     // return.  Or, 'st' might be used by some node which is live at
     // the same time 'st' is live, which might be unschedulable.  So,
@@ -2547,10 +2628,11 @@
              st->Opcode() == Op_StoreVector ||
              Opcode() == Op_StoreVector ||
              phase->C->get_alias_index(adr_type()) == Compile::AliasIdxRaw ||
              (Opcode() == Op_StoreL && st->Opcode() == Op_StoreI) || // expanded ClearArrayNode
              (Opcode() == Op_StoreI && st->Opcode() == Op_StoreL) || // initialization by arraycopy
+             (Opcode() == Op_StoreL && st->Opcode() == Op_StoreN) ||
              (is_mismatched_access() || st->as_Store()->is_mismatched_access()),
              "no mismatched stores, except on raw memory: %s %s", NodeClassNames[Opcode()], NodeClassNames[st->Opcode()]);
 
       if (st->in(MemNode::Address)->eqv_uncast(address) &&
           st->as_Store()->memory_size() <= this->memory_size()) {
@@ -2632,14 +2714,15 @@
   }
 
   // Store of zero anywhere into a freshly-allocated object?
   // Then the store is useless.
   // (It must already have been captured by the InitializeNode.)
-  if (result == this &&
-      ReduceFieldZeroing && phase->type(val)->is_zero_type()) {
+  if (result == this && ReduceFieldZeroing) {
     // a newly allocated object is already all-zeroes everywhere
-    if (mem->is_Proj() && mem->in(0)->is_Allocate()) {
+    if (mem->is_Proj() && mem->in(0)->is_Allocate() &&
+        (phase->type(val)->is_zero_type() || mem->in(0)->in(AllocateNode::DefaultValue) == val)) {
+      assert(!phase->type(val)->is_zero_type() || mem->in(0)->in(AllocateNode::DefaultValue) == NULL, "storing null to inline type array is forbidden");
       result = mem;
     }
 
     if (result == this) {
       // the store may also apply to zero-bits in an earlier object
@@ -2648,11 +2731,19 @@
       if (prev_mem != NULL) {
         Node* prev_val = can_see_stored_value(prev_mem, phase);
         if (prev_val != NULL && phase->eqv(prev_val, val)) {
           // prev_val and val might differ by a cast; it would be good
           // to keep the more informative of the two.
-          result = mem;
+          if (phase->type(val)->is_zero_type()) {
+            result = mem;
+          } else if (prev_mem->is_Proj() && prev_mem->in(0)->is_Initialize()) {
+            InitializeNode* init = prev_mem->in(0)->as_Initialize();
+            AllocateNode* alloc = init->allocation();
+            if (alloc != NULL && alloc->in(AllocateNode::DefaultValue) == val) {
+              result = mem;
+            }
+          }
         }
       }
     }
   }
 
@@ -2957,11 +3048,11 @@
   if (size <= 0 || size % unit != 0)  return NULL;
   intptr_t count = size / unit;
   // Length too long; communicate this to matchers and assemblers.
   // Assemblers are responsible to produce fast hardware clears for it.
   if (size > InitArrayShortSize) {
-    return new ClearArrayNode(in(0), in(1), in(2), in(3), true);
+    return new ClearArrayNode(in(0), in(1), in(2), in(3), in(4), true);
   }
   Node *mem = in(1);
   if( phase->type(mem)==Type::TOP ) return NULL;
   Node *adr = in(3);
   const Type* at = phase->type(adr);
@@ -2972,18 +3063,18 @@
   else              atp = atp->add_offset(Type::OffsetBot);
   // Get base for derived pointer purposes
   if( adr->Opcode() != Op_AddP ) Unimplemented();
   Node *base = adr->in(1);
 
-  Node *zero = phase->makecon(TypeLong::ZERO);
+  Node *val = in(4);
   Node *off  = phase->MakeConX(BytesPerLong);
-  mem = new StoreLNode(in(0),mem,adr,atp,zero,MemNode::unordered,false);
+  mem = new StoreLNode(in(0), mem, adr, atp, val, MemNode::unordered, false);
   count--;
   while( count-- ) {
     mem = phase->transform(mem);
     adr = phase->transform(new AddPNode(base,adr,off));
-    mem = new StoreLNode(in(0),mem,adr,atp,zero,MemNode::unordered,false);
+    mem = new StoreLNode(in(0), mem, adr, atp, val, MemNode::unordered, false);
   }
   return mem;
 }
 
 //----------------------------step_through----------------------------------
@@ -3013,31 +3104,40 @@
 }
 
 //----------------------------clear_memory-------------------------------------
 // Generate code to initialize object storage to zero.
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
+                                   Node* val,
+                                   Node* raw_val,
                                    intptr_t start_offset,
                                    Node* end_offset,
                                    PhaseGVN* phase) {
   intptr_t offset = start_offset;
 
   int unit = BytesPerLong;
   if ((offset % unit) != 0) {
     Node* adr = new AddPNode(dest, dest, phase->MakeConX(offset));
     adr = phase->transform(adr);
     const TypePtr* atp = TypeRawPtr::BOTTOM;
-    mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
+    if (val != NULL) {
+      assert(phase->type(val)->isa_narrowoop(), "should be narrow oop");
+      mem = new StoreNNode(ctl, mem, adr, atp, val, MemNode::unordered);
+    } else {
+      assert(raw_val == NULL, "val may not be null");
+      mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
+    }
     mem = phase->transform(mem);
     offset += BytesPerInt;
   }
   assert((offset % unit) == 0, "");
 
   // Initialize the remaining stuff, if any, with a ClearArray.
-  return clear_memory(ctl, mem, dest, phase->MakeConX(offset), end_offset, phase);
+  return clear_memory(ctl, mem, dest, raw_val, phase->MakeConX(offset), end_offset, phase);
 }
 
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
+                                   Node* raw_val,
                                    Node* start_offset,
                                    Node* end_offset,
                                    PhaseGVN* phase) {
   if (start_offset == end_offset) {
     // nothing to do
@@ -3056,15 +3156,20 @@
   }
 
   // Bulk clear double-words
   Node* zsize = phase->transform(new SubXNode(zend, zbase) );
   Node* adr = phase->transform(new AddPNode(dest, dest, start_offset) );
-  mem = new ClearArrayNode(ctl, mem, zsize, adr, false);
+  if (raw_val == NULL) {
+    raw_val = phase->MakeConX(0);
+  }
+  mem = new ClearArrayNode(ctl, mem, zsize, adr, raw_val, false);
   return phase->transform(mem);
 }
 
 Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
+                                   Node* val,
+                                   Node* raw_val,
                                    intptr_t start_offset,
                                    intptr_t end_offset,
                                    PhaseGVN* phase) {
   if (start_offset == end_offset) {
     // nothing to do
@@ -3075,18 +3180,24 @@
   intptr_t done_offset = end_offset;
   if ((done_offset % BytesPerLong) != 0) {
     done_offset -= BytesPerInt;
   }
   if (done_offset > start_offset) {
-    mem = clear_memory(ctl, mem, dest,
+    mem = clear_memory(ctl, mem, dest, val, raw_val,
                        start_offset, phase->MakeConX(done_offset), phase);
   }
   if (done_offset < end_offset) { // emit the final 32-bit store
     Node* adr = new AddPNode(dest, dest, phase->MakeConX(done_offset));
     adr = phase->transform(adr);
     const TypePtr* atp = TypeRawPtr::BOTTOM;
-    mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
+    if (val != NULL) {
+      assert(phase->type(val)->isa_narrowoop(), "should be narrow oop");
+      mem = new StoreNNode(ctl, mem, adr, atp, val, MemNode::unordered);
+    } else {
+      assert(raw_val == NULL, "val may not be null");
+      mem = StoreNode::make(*phase, ctl, mem, adr, atp, phase->zerocon(T_INT), T_INT, MemNode::unordered);
+    }
     mem = phase->transform(mem);
     done_offset += BytesPerInt;
   }
   assert(done_offset == end_offset, "");
   return mem;
@@ -3221,11 +3332,11 @@
   return TypeTuple::MEMBAR;
 }
 
 //------------------------------match------------------------------------------
 // Construct projections for memory.
-Node *MemBarNode::match( const ProjNode *proj, const Matcher *m ) {
+Node *MemBarNode::match(const ProjNode *proj, const Matcher *m, const RegMask* mask) {
   switch (proj->_con) {
   case TypeFunc::Control:
   case TypeFunc::Memory:
     return new MachProjNode(this,proj->_con,RegMask::Empty,MachProjNode::unmatched_proj);
   }
@@ -3507,11 +3618,13 @@
 
 // convenience function
 // return false if the init contains any stores already
 bool AllocateNode::maybe_set_complete(PhaseGVN* phase) {
   InitializeNode* init = initialization();
-  if (init == NULL || init->is_complete())  return false;
+  if (init == NULL || init->is_complete()) {
+    return false;
+  }
   init->remove_extra_zeroes();
   // for now, if this allocation has already collected any inits, bail:
   if (init->is_non_zero())  return false;
   init->set_complete(phase);
   return true;
@@ -4265,10 +4378,12 @@
       if (zeroes_needed > zeroes_done) {
         intptr_t zsize = zeroes_needed - zeroes_done;
         // Do some incremental zeroing on rawmem, in parallel with inits.
         zeroes_done = align_down(zeroes_done, BytesPerInt);
         rawmem = ClearArrayNode::clear_memory(rawctl, rawmem, rawptr,
+                                              allocation()->in(AllocateNode::DefaultValue),
+                                              allocation()->in(AllocateNode::RawDefaultValue),
                                               zeroes_done, zeroes_needed,
                                               phase);
         zeroes_done = zeroes_needed;
         if (zsize > InitArrayShortSize && ++big_init_gaps > 2)
           do_zeroing = false;   // leave the hole, next time
@@ -4324,10 +4439,12 @@
           zeroes_done = size_limit;
       }
     }
     if (zeroes_done < size_limit) {
       rawmem = ClearArrayNode::clear_memory(rawctl, rawmem, rawptr,
+                                            allocation()->in(AllocateNode::DefaultValue),
+                                            allocation()->in(AllocateNode::RawDefaultValue),
                                             zeroes_done, size_in_bytes, phase);
     }
   }
 
   set_complete(phase);
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
@@ -240,16 +240,23 @@
     _code_offsets(),
     _node_bundling_limit(0),
     _node_bundling_base(NULL),
     _orig_pc_slot(0),
     _orig_pc_slot_offset_in_bytes(0),
+    _sp_inc_slot(0),
+    _sp_inc_slot_offset_in_bytes(0),
     _buf_sizes(),
     _block(NULL),
     _index(0) {
   C->set_output(this);
   if (C->stub_name() == NULL) {
-    _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;
+      _sp_inc_slot = fixed_slots;
+    }
+    _orig_pc_slot = fixed_slots - (sizeof(address) / VMRegImpl::stack_slot_size);
   }
 }
 
 PhaseOutput::~PhaseOutput() {
   C->set_output(NULL);
@@ -284,28 +291,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())       ||
@@ -341,10 +358,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;
   }
 
@@ -498,11 +540,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() != NULL) {
+            mcall->method_set((intptr_t)mcall->entry_point());
+          }
 
           if (mcall->is_MachCallJava() && mcall->as_MachCallJava()->_method) {
             stub_size  += CompiledStaticCall::to_interp_stub_size();
             reloc_size += CompiledStaticCall::reloc_to_interp_stub();
 #if INCLUDE_AOT
@@ -931,10 +975,11 @@
   MachCallNode      *mcall;
 
   int safepoint_pc_offset = current_offset;
   bool is_method_handle_invoke = false;
   bool return_oop = false;
+  bool return_vt = false;
 
   // Add the safepoint in the DebugInfoRecorder
   if( !mach->is_MachCall() ) {
     mcall = NULL;
     C->debug_info()->add_safepoint(safepoint_pc_offset, sfn->_oop_map);
@@ -948,13 +993,16 @@
         is_method_handle_invoke = true;
       }
     }
 
     // Check if a call returns an object.
-    if (mcall->returns_pointer()) {
+    if (mcall->returns_pointer() || mcall->returns_vt()) {
       return_oop = true;
     }
+    if (mcall->returns_vt()) {
+      return_vt = 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
@@ -1065,11 +1113,11 @@
     assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI");
     assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest");
     // Now we can describe the scope.
     methodHandle null_mh;
     bool rethrow_exception = false;
-    C->debug_info()->describe_scope(safepoint_pc_offset, null_mh, scope_method, jvms->bci(), jvms->should_reexecute(), rethrow_exception, is_method_handle_invoke, return_oop, locvals, expvals, monvals);
+    C->debug_info()->describe_scope(safepoint_pc_offset, null_mh, scope_method, jvms->bci(), jvms->should_reexecute(), rethrow_exception, is_method_handle_invoke, return_oop, return_vt, locvals, expvals, monvals);
   } // End jvms loop
 
   // Mark the end of the scope set.
   C->debug_info()->end_safepoint(safepoint_pc_offset);
 }
@@ -1170,10 +1218,14 @@
 
   // Compute the byte offset where we can store the deopt pc.
   if (C->fixed_slots() != 0) {
     _orig_pc_slot_offset_in_bytes = C->regalloc()->reg2offset(OptoReg::stack2reg(_orig_pc_slot));
   }
+  if (C->needs_stack_repair()) {
+    // Compute the byte offset of the stack increment value
+    _sp_inc_slot_offset_in_bytes = C->regalloc()->reg2offset(OptoReg::stack2reg(_sp_inc_slot));
+  }
 
   // Compute prolog code size
   _method_size = 0;
   _frame_slots = OptoReg::reg2stack(C->matcher()->_old_SP) + C->regalloc()->_framesize;
 #if defined(IA64) && !defined(AIX)
@@ -1446,12 +1498,14 @@
 
         // 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() != NULL) {
+            // 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();
 
           if (mcall->is_MachCallLeaf()) {
@@ -3178,10 +3232,16 @@
     }
 
     ResourceMark rm;
     _scratch_const_size = const_size;
     int size = C2Compiler::initial_code_buffer_size(const_size);
+#ifdef ASSERT
+    if (C->has_scalarized_args()) {
+      // Oop verification for loading object fields from scalarized inline types in the new entry point requires lots of space
+      size += 5120;
+    }
+#endif
     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() == NULL) {
@@ -3242,18 +3302,30 @@
   if (is_branch) {
     MacroAssembler masm(&buf);
     masm.bind(fakeL);
     n->as_MachBranch()->save_label(&saveL, &save_bnum);
     n->as_MachBranch()->label_set(&fakeL, 0);
+  } else if (n->is_MachProlog()) {
+    saveL = ((MachPrologNode*)n)->_verified_entry;
+    ((MachPrologNode*)n)->_verified_entry = &fakeL;
+  } else if (n->is_MachVEP()) {
+    saveL = ((MachVEPNode*)n)->_verified_entry;
+    ((MachVEPNode*)n)->_verified_entry = &fakeL;
   }
   n->emit(buf, C->regalloc());
 
   // Emitting into the scratch buffer should not fail
   assert (!C->failing(), "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);
+  } else if (n->is_MachProlog()) {
+    ((MachPrologNode*)n)->_verified_entry = saveL;
+  } else if (n->is_MachVEP()) {
+    ((MachVEPNode*)n)->_verified_entry = saveL;
+  }
 
   // End scratch_emit_size section.
   set_in_scratch_emit_size(false);
 
   return buf.insts_size();
@@ -3294,26 +3366,35 @@
     if (C->is_osr_compilation()) {
       _code_offsets.set_value(CodeOffsets::Verified_Entry, 0);
       _code_offsets.set_value(CodeOffsets::OSR_Entry, _first_block_size);
     } else {
       _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->rtm_state());
+                              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->rtm_state());
 
     if (C->log() != NULL) { // Print code cache state into compiler log
       C->log()->code_cache_state();
     }
   }
diff a/src/hotspot/share/opto/stringopts.cpp b/src/hotspot/share/opto/stringopts.cpp
--- a/src/hotspot/share/opto/stringopts.cpp
+++ b/src/hotspot/share/opto/stringopts.cpp
@@ -320,41 +320,41 @@
 }
 
 
 void StringConcat::eliminate_call(CallNode* call) {
   Compile* C = _stringopts->C;
-  CallProjections projs;
-  call->extract_projections(&projs, false);
-  if (projs.fallthrough_catchproj != NULL) {
-    C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control));
+  CallProjections* projs = call->extract_projections(false);
+  if (projs->fallthrough_catchproj != NULL) {
+    C->gvn_replace_by(projs->fallthrough_catchproj, call->in(TypeFunc::Control));
   }
-  if (projs.fallthrough_memproj != NULL) {
-    C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory));
+  if (projs->fallthrough_memproj != NULL) {
+    C->gvn_replace_by(projs->fallthrough_memproj, call->in(TypeFunc::Memory));
   }
-  if (projs.catchall_memproj != NULL) {
-    C->gvn_replace_by(projs.catchall_memproj, C->top());
+  if (projs->catchall_memproj != NULL) {
+    C->gvn_replace_by(projs->catchall_memproj, C->top());
   }
-  if (projs.fallthrough_ioproj != NULL) {
-    C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O));
+  if (projs->fallthrough_ioproj != NULL) {
+    C->gvn_replace_by(projs->fallthrough_ioproj, call->in(TypeFunc::I_O));
   }
-  if (projs.catchall_ioproj != NULL) {
-    C->gvn_replace_by(projs.catchall_ioproj, C->top());
+  if (projs->catchall_ioproj != NULL) {
+    C->gvn_replace_by(projs->catchall_ioproj, C->top());
   }
-  if (projs.catchall_catchproj != NULL) {
+  if (projs->catchall_catchproj != NULL) {
     // EA can't cope with the partially collapsed graph this
     // creates so put it on the worklist to be collapsed later.
-    for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) {
+    for (SimpleDUIterator i(projs->catchall_catchproj); i.has_next(); i.next()) {
       Node *use = i.get();
       int opc = use->Opcode();
       if (opc == Op_CreateEx || opc == Op_Region) {
         _stringopts->record_dead_node(use);
       }
     }
-    C->gvn_replace_by(projs.catchall_catchproj, C->top());
+    C->gvn_replace_by(projs->catchall_catchproj, C->top());
   }
-  if (projs.resproj != NULL) {
-    C->gvn_replace_by(projs.resproj, C->top());
+  if (projs->resproj[0] != NULL) {
+    assert(projs->nb_resproj == 1, "unexpected number of results");
+    C->gvn_replace_by(projs->resproj[0], C->top());
   }
   C->gvn_replace_by(call, C->top());
 }
 
 void StringConcat::eliminate_initialize(InitializeNode* init) {
diff a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp
--- a/src/hotspot/share/opto/subnode.cpp
+++ b/src/hotspot/share/opto/subnode.cpp
@@ -745,21 +745,53 @@
     }
   }
   return NULL;                  // No change
 }
 
-Node *CmpLNode::Ideal( PhaseGVN *phase, bool can_reshape ) {
+//------------------------------Ideal------------------------------------------
+Node* CmpLNode::Ideal(PhaseGVN* phase, bool can_reshape) {
+  Node* a = NULL;
+  Node* b = NULL;
+  if (is_double_null_check(phase, a, b) && (phase->type(a)->is_zero_type() || phase->type(b)->is_zero_type())) {
+    // Degraded to a simple null check, use old acmp
+    return new CmpPNode(a, b);
+  }
   const TypeLong *t2 = phase->type(in(2))->isa_long();
   if (Opcode() == Op_CmpL && in(1)->Opcode() == Op_ConvI2L && t2 && t2->is_con()) {
     const jlong con = t2->get_con();
     if (con >= min_jint && con <= max_jint) {
       return new CmpINode(in(1)->in(1), phase->intcon((jint)con));
     }
   }
   return NULL;
 }
 
+// Match double null check emitted by Compile::optimize_acmp()
+bool CmpLNode::is_double_null_check(PhaseGVN* phase, Node*& a, Node*& b) const {
+  if (in(1)->Opcode() == Op_OrL &&
+      in(1)->in(1)->Opcode() == Op_CastP2X &&
+      in(1)->in(2)->Opcode() == Op_CastP2X &&
+      in(2)->bottom_type()->is_zero_type()) {
+    assert(EnableValhalla, "unexpected double null check");
+    a = in(1)->in(1)->in(1);
+    b = in(1)->in(2)->in(1);
+    return true;
+  }
+  return false;
+}
+
+//------------------------------Value------------------------------------------
+const Type* CmpLNode::Value(PhaseGVN* phase) const {
+  Node* a = NULL;
+  Node* b = NULL;
+  if (is_double_null_check(phase, a, b) && (!phase->type(a)->maybe_null() || !phase->type(b)->maybe_null())) {
+    // One operand is never NULL, emit constant false
+    return TypeInt::CC_GT;
+  }
+  return SubNode::Value(phase);
+}
+
 //=============================================================================
 // Simplify a CmpL (compare 2 longs ) node, based on local information.
 // If both inputs are constants, compare them.
 const Type *CmpLNode::sub( const Type *t1, const Type *t2 ) const {
   const TypeLong *r0 = t1->is_long(); // Handy access
@@ -914,10 +946,18 @@
         // If klass0's type is PRECISE, then classes are unrelated.
         unrelated_classes = xklass0;
       } else {                  // Neither subtypes the other
         unrelated_classes = true;
       }
+      if (!unrelated_classes) {
+        // Handle inline type arrays
+        if ((r0->flatten_array() && (!r1->can_be_inline_type() || (klass1->is_inlinetype() && !klass1->flatten_array()))) ||
+            (r1->flatten_array() && (!r0->can_be_inline_type() || (klass0->is_inlinetype() && !klass0->flatten_array())))) {
+          // One type is flattened in arrays but the other type is not. Must be unrelated.
+          unrelated_classes = true;
+        }
+      }
       if (unrelated_classes) {
         // The oops classes are known to be unrelated. If the joined PTRs of
         // two oops is not Null and not Bottom, then we are sure that one
         // of the two oops is non-null, and the comparison will always fail.
         TypePtr::PTR jp = r0->join_ptr(r1->_ptr);
@@ -999,11 +1039,11 @@
 //
 // Also check for the case of comparing an unknown klass loaded from the primary
 // super-type array vs a known klass with no subtypes.  This amounts to
 // checking to see an unknown klass subtypes a known klass with no subtypes;
 // this only happens on an exact match.  We can shorten this test by 1 load.
-Node *CmpPNode::Ideal( PhaseGVN *phase, bool can_reshape ) {
+Node* CmpPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
   // Normalize comparisons between Java mirrors into comparisons of the low-
   // level klass, where a dependent load could be shortened.
   //
   // The new pattern has a nice effect of matching the same pattern used in the
   // fast path of instanceof/checkcast/Class.isInstance(), which allows
diff a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp
--- a/src/hotspot/share/opto/type.cpp
+++ b/src/hotspot/share/opto/type.cpp
@@ -21,10 +21,13 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "ci/ciFlatArrayKlass.hpp"
+#include "ci/ciField.hpp"
+#include "ci/ciInlineKlass.hpp"
 #include "ci/ciMethodData.hpp"
 #include "ci/ciTypeFlow.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "compiler/compileLog.hpp"
@@ -45,10 +48,56 @@
 
 // Optimization - Graph Style
 
 // Dictionary of types shared among compilations.
 Dict* Type::_shared_type_dict = NULL;
+const Type::Offset Type::Offset::top(Type::OffsetTop);
+const Type::Offset Type::Offset::bottom(Type::OffsetBot);
+
+const Type::Offset Type::Offset::meet(const Type::Offset other) const {
+  // Either is 'TOP' offset?  Return the other offset!
+  int offset = other._offset;
+  if (_offset == OffsetTop) return Offset(offset);
+  if (offset == OffsetTop) return Offset(_offset);
+  // If either is different, return 'BOTTOM' offset
+  if (_offset != offset) return bottom;
+  return Offset(_offset);
+}
+
+const Type::Offset Type::Offset::dual() const {
+  if (_offset == OffsetTop) return bottom;// Map 'TOP' into 'BOTTOM'
+  if (_offset == OffsetBot) return top;// Map 'BOTTOM' into 'TOP'
+  return Offset(_offset);               // Map everything else into self
+}
+
+const Type::Offset Type::Offset::add(intptr_t offset) const {
+  // Adding to 'TOP' offset?  Return 'TOP'!
+  if (_offset == OffsetTop || offset == OffsetTop) return top;
+  // Adding to 'BOTTOM' offset?  Return 'BOTTOM'!
+  if (_offset == OffsetBot || offset == OffsetBot) return bottom;
+  // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'!
+  offset += (intptr_t)_offset;
+  if (offset != (int)offset || offset == OffsetTop) return bottom;
+
+  // assert( _offset >= 0 && _offset+offset >= 0, "" );
+  // It is possible to construct a negative offset during PhaseCCP
+
+  return Offset((int)offset);        // Sum valid offsets
+}
+
+void Type::Offset::dump2(outputStream *st) const {
+  if (_offset == 0) {
+    return;
+  } else if (_offset == OffsetTop) {
+    st->print("+top");
+  }
+  else if (_offset == OffsetBot) {
+    st->print("+bot");
+  } else if (_offset) {
+    st->print("+%d", _offset);
+  }
+}
 
 // Array which maps compiler types to Basic Types
 const Type::TypeInfo Type::_type_info[Type::lastype] = {
   { Bad,             T_ILLEGAL,    "bad",           false, Node::NotAMachineReg, relocInfo::none          },  // Bad
   { Control,         T_ILLEGAL,    "control",       false, 0,                    relocInfo::none          },  // Control
@@ -78,10 +127,11 @@
   { Bad,             T_ILLEGAL,    "vectord:",      false, Op_VecD,              relocInfo::none          },  // VectorD
   { Bad,             T_ILLEGAL,    "vectorx:",      false, Op_VecX,              relocInfo::none          },  // VectorX
   { Bad,             T_ILLEGAL,    "vectory:",      false, Op_VecY,              relocInfo::none          },  // VectorY
   { Bad,             T_ILLEGAL,    "vectorz:",      false, Op_VecZ,              relocInfo::none          },  // VectorZ
 #endif
+  { Bad,             T_INLINE_TYPE, "inline:",      false, Node::NotAMachineReg, relocInfo::none          },  // InlineType
   { Bad,             T_ADDRESS,    "anyptr:",       false, Op_RegP,              relocInfo::none          },  // AnyPtr
   { Bad,             T_ADDRESS,    "rawptr:",       false, Op_RegP,              relocInfo::none          },  // RawPtr
   { Bad,             T_OBJECT,     "oop:",          true,  Op_RegP,              relocInfo::oop_type      },  // OopPtr
   { Bad,             T_OBJECT,     "inst:",         true,  Op_RegP,              relocInfo::oop_type      },  // InstPtr
   { Bad,             T_OBJECT,     "ary:",          true,  Op_RegP,              relocInfo::oop_type      },  // AryPtr
@@ -208,10 +258,19 @@
 
   case T_ADDRESS:
     assert(type->is_return_address(), "");
     return TypeRawPtr::make((address)(intptr_t)type->as_return_address()->bci());
 
+  case T_INLINE_TYPE: {
+    ciInlineKlass* vk = type->as_inline_klass();
+    if (vk->is_scalarizable()) {
+      return TypeInlineType::make(vk);
+    } else {
+      return TypeOopPtr::make_from_klass(vk)->join_speculative(TypePtr::NOTNULL);
+    }
+  }
+
   default:
     // make sure we did not mix up the cases:
     assert(type != ciTypeFlow::StateVector::bottom_type(), "");
     assert(type != ciTypeFlow::StateVector::top_type(), "");
     assert(type != ciTypeFlow::StateVector::null_type(), "");
@@ -236,10 +295,11 @@
     case T_INT:      return TypeInt::make(constant.as_int());
     case T_LONG:     return TypeLong::make(constant.as_long());
     case T_FLOAT:    return TypeF::make(constant.as_float());
     case T_DOUBLE:   return TypeD::make(constant.as_double());
     case T_ARRAY:
+    case T_INLINE_TYPE:
     case T_OBJECT: {
         const Type* con_type = NULL;
         ciObject* oop_constant = constant.as_object();
         if (oop_constant->is_null_object()) {
           con_type = Type::get_zero_type(T_OBJECT);
@@ -273,16 +333,18 @@
 static ciConstant check_mismatched_access(ciConstant con, BasicType loadbt, bool is_unsigned) {
   BasicType conbt = con.basic_type();
   switch (conbt) {
     case T_BOOLEAN: conbt = T_BYTE;   break;
     case T_ARRAY:   conbt = T_OBJECT; break;
+    case T_INLINE_TYPE: conbt = T_OBJECT; break;
     default:                          break;
   }
   switch (loadbt) {
     case T_BOOLEAN:   loadbt = T_BYTE;   break;
     case T_NARROWOOP: loadbt = T_OBJECT; break;
     case T_ARRAY:     loadbt = T_OBJECT; break;
+    case T_INLINE_TYPE: loadbt = T_OBJECT; break;
     case T_ADDRESS:   loadbt = T_OBJECT; break;
     default:                             break;
   }
   if (conbt == loadbt) {
     if (is_unsigned && conbt == T_BYTE) {
@@ -506,13 +568,13 @@
   const Type **floop =(const Type**)shared_type_arena->Amalloc_4(2*sizeof(Type*));
   floop[0] = Type::CONTROL;
   floop[1] = TypeInt::INT;
   TypeTuple::LOOPBODY = TypeTuple::make( 2, floop );
 
-  TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, 0);
-  TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, OffsetBot);
-  TypePtr::BOTTOM  = TypePtr::make(AnyPtr, TypePtr::BotPTR, OffsetBot);
+  TypePtr::NULL_PTR= TypePtr::make(AnyPtr, TypePtr::Null, Offset(0));
+  TypePtr::NOTNULL = TypePtr::make(AnyPtr, TypePtr::NotNull, Offset::bottom);
+  TypePtr::BOTTOM  = TypePtr::make(AnyPtr, TypePtr::BotPTR, Offset::bottom);
 
   TypeRawPtr::BOTTOM = TypeRawPtr::make( TypePtr::BotPTR );
   TypeRawPtr::NOTNULL= TypeRawPtr::make( TypePtr::NotNull );
 
   const Type **fmembar = TypeTuple::fields(0);
@@ -525,16 +587,18 @@
 
   TypeInstPtr::NOTNULL = TypeInstPtr::make(TypePtr::NotNull, current->env()->Object_klass());
   TypeInstPtr::BOTTOM  = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass());
   TypeInstPtr::MIRROR  = TypeInstPtr::make(TypePtr::NotNull, current->env()->Class_klass());
   TypeInstPtr::MARK    = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
-                                           false, 0, oopDesc::mark_offset_in_bytes());
+                                           false, 0, Offset(oopDesc::mark_offset_in_bytes()));
   TypeInstPtr::KLASS   = TypeInstPtr::make(TypePtr::BotPTR,  current->env()->Object_klass(),
-                                           false, 0, oopDesc::klass_offset_in_bytes());
-  TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
+                                           false, 0, Offset(oopDesc::klass_offset_in_bytes()));
+  TypeOopPtr::BOTTOM  = TypeOopPtr::make(TypePtr::BotPTR, Offset::bottom, TypeOopPtr::InstanceBot);
+
+  TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, Offset::bottom);
 
-  TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot);
+  TypeInlineType::BOTTOM = TypeInlineType::make(NULL);
 
   TypeNarrowOop::NULL_PTR = TypeNarrowOop::make( TypePtr::NULL_PTR );
   TypeNarrowOop::BOTTOM   = TypeNarrowOop::make( TypeInstPtr::BOTTOM );
 
   TypeNarrowKlass::NULL_PTR = TypeNarrowKlass::make( TypePtr::NULL_PTR );
@@ -547,47 +611,49 @@
   mreg2type[Op_RegF] = Type::FLOAT;
   mreg2type[Op_RegD] = Type::DOUBLE;
   mreg2type[Op_RegL] = TypeLong::LONG;
   mreg2type[Op_RegFlags] = TypeInt::CC;
 
-  TypeAryPtr::RANGE   = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes());
+  TypeAryPtr::RANGE   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), NULL /* current->env()->Object_klass() */, false, Offset(arrayOopDesc::length_offset_in_bytes()));
 
-  TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/,  false,  Type::OffsetBot);
+  TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), NULL /*ciArrayKlass::make(o)*/,  false,  Offset::bottom);
 
 #ifdef _LP64
   if (UseCompressedOops) {
     assert(TypeAryPtr::NARROWOOPS->is_ptr_to_narrowoop(), "array of narrow oops must be ptr to narrow oop");
     TypeAryPtr::OOPS  = TypeAryPtr::NARROWOOPS;
   } else
 #endif
   {
     // There is no shared klass for Object[].  See note in TypeAryPtr::klass().
-    TypeAryPtr::OOPS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/,  false,  Type::OffsetBot);
+    TypeAryPtr::OOPS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInstPtr::BOTTOM,TypeInt::POS), NULL /*ciArrayKlass::make(o)*/,  false,  Offset::bottom);
   }
-  TypeAryPtr::BYTES   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE      ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE),   true,  Type::OffsetBot);
-  TypeAryPtr::SHORTS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT     ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT),  true,  Type::OffsetBot);
-  TypeAryPtr::CHARS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR      ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR),   true,  Type::OffsetBot);
-  TypeAryPtr::INTS    = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT       ,TypeInt::POS), ciTypeArrayKlass::make(T_INT),    true,  Type::OffsetBot);
-  TypeAryPtr::LONGS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG     ,TypeInt::POS), ciTypeArrayKlass::make(T_LONG),   true,  Type::OffsetBot);
-  TypeAryPtr::FLOATS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT        ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT),  true,  Type::OffsetBot);
-  TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE       ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true,  Type::OffsetBot);
+  TypeAryPtr::BYTES   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::BYTE      ,TypeInt::POS), ciTypeArrayKlass::make(T_BYTE),   true,  Offset::bottom);
+  TypeAryPtr::SHORTS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::SHORT     ,TypeInt::POS), ciTypeArrayKlass::make(T_SHORT),  true,  Offset::bottom);
+  TypeAryPtr::CHARS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::CHAR      ,TypeInt::POS), ciTypeArrayKlass::make(T_CHAR),   true,  Offset::bottom);
+  TypeAryPtr::INTS    = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInt::INT       ,TypeInt::POS), ciTypeArrayKlass::make(T_INT),    true,  Offset::bottom);
+  TypeAryPtr::LONGS   = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeLong::LONG     ,TypeInt::POS), ciTypeArrayKlass::make(T_LONG),   true,  Offset::bottom);
+  TypeAryPtr::FLOATS  = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::FLOAT        ,TypeInt::POS), ciTypeArrayKlass::make(T_FLOAT),  true,  Offset::bottom);
+  TypeAryPtr::DOUBLES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::DOUBLE       ,TypeInt::POS), ciTypeArrayKlass::make(T_DOUBLE), true,  Offset::bottom);
+  TypeAryPtr::INLINES = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeInlineType::BOTTOM,TypeInt::POS), NULL, false,  Offset::bottom);
 
   // Nobody should ask _array_body_type[T_NARROWOOP]. Use NULL as assert.
   TypeAryPtr::_array_body_type[T_NARROWOOP] = NULL;
   TypeAryPtr::_array_body_type[T_OBJECT]  = TypeAryPtr::OOPS;
+  TypeAryPtr::_array_body_type[T_INLINE_TYPE] = TypeAryPtr::OOPS;
   TypeAryPtr::_array_body_type[T_ARRAY]   = TypeAryPtr::OOPS; // arrays are stored in oop arrays
   TypeAryPtr::_array_body_type[T_BYTE]    = TypeAryPtr::BYTES;
   TypeAryPtr::_array_body_type[T_BOOLEAN] = TypeAryPtr::BYTES;  // boolean[] is a byte array
   TypeAryPtr::_array_body_type[T_SHORT]   = TypeAryPtr::SHORTS;
   TypeAryPtr::_array_body_type[T_CHAR]    = TypeAryPtr::CHARS;
   TypeAryPtr::_array_body_type[T_INT]     = TypeAryPtr::INTS;
   TypeAryPtr::_array_body_type[T_LONG]    = TypeAryPtr::LONGS;
   TypeAryPtr::_array_body_type[T_FLOAT]   = TypeAryPtr::FLOATS;
   TypeAryPtr::_array_body_type[T_DOUBLE]  = TypeAryPtr::DOUBLES;
 
-  TypeKlassPtr::OBJECT = TypeKlassPtr::make( TypePtr::NotNull, current->env()->Object_klass(), 0 );
-  TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make( TypePtr::BotPTR, current->env()->Object_klass(), 0 );
+  TypeKlassPtr::OBJECT = TypeKlassPtr::make(TypePtr::NotNull, current->env()->Object_klass(), Offset(0));
+  TypeKlassPtr::OBJECT_OR_NULL = TypeKlassPtr::make(TypePtr::BotPTR, current->env()->Object_klass(), Offset(0));
 
   const Type **fi2c = TypeTuple::fields(2);
   fi2c[TypeFunc::Parms+0] = TypeInstPtr::BOTTOM; // Method*
   fi2c[TypeFunc::Parms+1] = TypeRawPtr::BOTTOM; // argument pointer
   TypeTuple::START_I2C = TypeTuple::make(TypeFunc::Parms+2, fi2c);
@@ -622,10 +688,11 @@
   _const_basic_type[T_LONG]        = TypeLong::LONG;
   _const_basic_type[T_FLOAT]       = Type::FLOAT;
   _const_basic_type[T_DOUBLE]      = Type::DOUBLE;
   _const_basic_type[T_OBJECT]      = TypeInstPtr::BOTTOM;
   _const_basic_type[T_ARRAY]       = TypeInstPtr::BOTTOM; // there is no separate bottom for arrays
+  _const_basic_type[T_INLINE_TYPE] = TypeInstPtr::BOTTOM;
   _const_basic_type[T_VOID]        = TypePtr::NULL_PTR;   // reflection represents void this way
   _const_basic_type[T_ADDRESS]     = TypeRawPtr::BOTTOM;  // both interpreter return addresses & random raw ptrs
   _const_basic_type[T_CONFLICT]    = Type::BOTTOM;        // why not?
 
   _zero_type[T_NARROWOOP]   = TypeNarrowOop::NULL_PTR;
@@ -638,10 +705,11 @@
   _zero_type[T_LONG]        = TypeLong::ZERO;
   _zero_type[T_FLOAT]       = TypeF::ZERO;
   _zero_type[T_DOUBLE]      = TypeD::ZERO;
   _zero_type[T_OBJECT]      = TypePtr::NULL_PTR;
   _zero_type[T_ARRAY]       = TypePtr::NULL_PTR; // null array is null oop
+  _zero_type[T_INLINE_TYPE] = TypePtr::NULL_PTR;
   _zero_type[T_ADDRESS]     = TypePtr::NULL_PTR; // raw pointers use the same null
   _zero_type[T_VOID]        = Type::TOP;         // the only void value is no value at all
 
   // get_zero_type() should not happen for T_CONFLICT
   _zero_type[T_CONFLICT]= NULL;
@@ -813,11 +881,11 @@
 
   // Interface meet Oop is Not Symmetric:
   // Interface:AnyNull meet Oop:AnyNull == Interface:AnyNull
   // Interface:NotNull meet Oop:NotNull == java/lang/Object:NotNull
 
-  if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this->_dual) ) {
+  if( !interface_vs_oop(t) && (t2t != t->_dual || t2this != this->_dual)) {
     tty->print_cr("=== Meet Not Symmetric ===");
     tty->print("t   =                   ");              t->dump(); tty->cr();
     tty->print("this=                   ");                 dump(); tty->cr();
     tty->print("mt=(t meet this)=       ");             mt->dump(); tty->cr();
 
@@ -917,10 +985,13 @@
     return t->xmeet(this);
 
   case NarrowKlass:
     return t->xmeet(this);
 
+  case InlineType:
+    return t->xmeet(this);
+
   case Bad:                     // Type check
   default:                      // Bogus type not in lattice
     typerr(t);
     return Type::BOTTOM;
 
@@ -984,10 +1055,11 @@
   Bad,          // VectorS - handled in v-call
   Bad,          // VectorD - handled in v-call
   Bad,          // VectorX - handled in v-call
   Bad,          // VectorY - handled in v-call
   Bad,          // VectorZ - handled in v-call
+  Bad,          // InlineType - handled in v-call
 
   Bad,          // AnyPtr - handled in v-call
   Bad,          // RawPtr - handled in v-call
   Bad,          // OopPtr - handled in v-call
   Bad,          // InstPtr - handled in v-call
@@ -1879,16 +1951,38 @@
 const TypeTuple *TypeTuple::INT_PAIR;
 const TypeTuple *TypeTuple::LONG_PAIR;
 const TypeTuple *TypeTuple::INT_CC_PAIR;
 const TypeTuple *TypeTuple::LONG_CC_PAIR;
 
+static void collect_inline_fields(ciInlineKlass* vk, const Type** field_array, uint& pos, ExtendedSignature& sig_cc) {
+  for (int j = 0; j < vk->nof_nonstatic_fields(); j++) {
+    ciField* field = vk->nonstatic_field_at(j);
+    BasicType bt = field->type()->basic_type();
+    const Type* ft = Type::get_const_type(field->type());
+    field_array[pos++] = ft;
+    if (type2size[bt] == 2) {
+      field_array[pos++] = Type::HALF;
+    }
+    // Skip reserved arguments
+    while (SigEntry::next_is_reserved(sig_cc, bt)) {
+      field_array[pos++] = Type::get_const_basic_type(bt);
+      if (type2size[bt] == 2) {
+        field_array[pos++] = Type::HALF;
+      }
+    }
+  }
+}
 
 //------------------------------make-------------------------------------------
 // Make a TypeTuple from the range of a method signature
-const TypeTuple *TypeTuple::make_range(ciSignature* sig) {
+const TypeTuple *TypeTuple::make_range(ciSignature* sig, bool ret_vt_fields) {
   ciType* return_type = sig->return_type();
   uint arg_cnt = return_type->size();
+  if (ret_vt_fields) {
+    arg_cnt = return_type->as_inline_klass()->inline_arg_slots() + 1;
+  }
+
   const Type **field_array = fields(arg_cnt);
   switch (return_type->basic_type()) {
   case T_LONG:
     field_array[TypeFunc::Parms]   = TypeLong::LONG;
     field_array[TypeFunc::Parms+1] = Type::HALF;
@@ -1905,38 +1999,63 @@
   case T_BYTE:
   case T_SHORT:
   case T_INT:
     field_array[TypeFunc::Parms] = get_const_type(return_type);
     break;
+  case T_INLINE_TYPE:
+    if (ret_vt_fields) {
+      uint pos = TypeFunc::Parms;
+      field_array[pos] = TypePtr::BOTTOM;
+      pos++;
+      ExtendedSignature sig = ExtendedSignature(NULL, SigEntryFilter());
+      collect_inline_fields(return_type->as_inline_klass(), field_array, pos, sig);
+    } else {
+      field_array[TypeFunc::Parms] = get_const_type(return_type)->join_speculative(TypePtr::NOTNULL);
+    }
+    break;
   case T_VOID:
     break;
   default:
     ShouldNotReachHere();
   }
   return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
 }
 
 // Make a TypeTuple from the domain of a method signature
-const TypeTuple *TypeTuple::make_domain(ciInstanceKlass* recv, ciSignature* sig) {
-  uint arg_cnt = sig->size();
+const TypeTuple *TypeTuple::make_domain(ciMethod* method, bool vt_fields_as_args) {
+  ciSignature* sig = method->signature();
+  ExtendedSignature sig_cc = ExtendedSignature(vt_fields_as_args ? method->get_sig_cc() : NULL, SigEntryFilter());
+
+  uint arg_cnt = sig->size() + (method->is_static() ? 0 : 1);
+  if (vt_fields_as_args) {
+    for (arg_cnt = 0; !sig_cc.at_end(); ++sig_cc) {
+      arg_cnt += type2size[(*sig_cc)._bt];
+    }
+    sig_cc = ExtendedSignature(method->get_sig_cc(), SigEntryFilter());
+  }
 
   uint pos = TypeFunc::Parms;
-  const Type **field_array;
-  if (recv != NULL) {
-    arg_cnt++;
-    field_array = fields(arg_cnt);
-    // Use get_const_type here because it respects UseUniqueSubclasses:
-    field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL);
-  } else {
-    field_array = fields(arg_cnt);
+  const Type** field_array = fields(arg_cnt);
+  if (!method->is_static()) {
+    ciInstanceKlass* recv = method->holder();
+    if (vt_fields_as_args && recv->is_inlinetype() && recv->as_inline_klass()->can_be_passed_as_fields()) {
+      collect_inline_fields(recv->as_inline_klass(), field_array, pos, sig_cc);
+    } else {
+      field_array[pos++] = get_const_type(recv)->join_speculative(TypePtr::NOTNULL);
+      if (vt_fields_as_args) {
+        ++sig_cc;
+      }
+    }
   }
 
   int i = 0;
   while (pos < TypeFunc::Parms + arg_cnt) {
     ciType* type = sig->type_at(i);
+    BasicType bt = type->basic_type();
+    bool is_flattened = false;
 
-    switch (type->basic_type()) {
+    switch (bt) {
     case T_LONG:
       field_array[pos++] = TypeLong::LONG;
       field_array[pos++] = Type::HALF;
       break;
     case T_DOUBLE:
@@ -1953,15 +2072,32 @@
     case T_CHAR:
     case T_BYTE:
     case T_SHORT:
       field_array[pos++] = TypeInt::INT;
       break;
+    case T_INLINE_TYPE: {
+      if (vt_fields_as_args && type->as_inline_klass()->can_be_passed_as_fields()) {
+        is_flattened = true;
+        collect_inline_fields(type->as_inline_klass(), field_array, pos, sig_cc);
+      } else {
+        field_array[pos++] = get_const_type(type)->join_speculative(TypePtr::NOTNULL);
+      }
+      break;
+    }
     default:
       ShouldNotReachHere();
     }
+    // Skip reserved arguments
+    while (!is_flattened && SigEntry::next_is_reserved(sig_cc, bt)) {
+      field_array[pos++] = Type::get_const_basic_type(bt);
+      if (type2size[bt] == 2) {
+        field_array[pos++] = Type::HALF;
+      }
+    }
     i++;
   }
+  assert(pos == TypeFunc::Parms + arg_cnt, "wrong number of arguments");
 
   return (TypeTuple*)(new TypeTuple(TypeFunc::Parms + arg_cnt, field_array))->hashcons();
 }
 
 const TypeTuple *TypeTuple::make( uint cnt, const Type **fields ) {
@@ -2092,16 +2228,17 @@
   else
     return size;
 }
 
 //------------------------------make-------------------------------------------
-const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable) {
+const TypeAry* TypeAry::make(const Type* elem, const TypeInt* size, bool stable,
+                             bool not_flat, bool not_null_free) {
   if (UseCompressedOops && elem->isa_oopptr()) {
     elem = elem->make_narrowoop();
   }
   size = normalize_array_size(size);
-  return (TypeAry*)(new TypeAry(elem,size,stable))->hashcons();
+  return (TypeAry*)(new TypeAry(elem, size, stable, not_flat, not_null_free))->hashcons();
 }
 
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
 const Type *TypeAry::xmeet( const Type *t ) const {
@@ -2119,11 +2256,13 @@
 
   case Array: {                 // Meeting 2 arrays?
     const TypeAry *a = t->is_ary();
     return TypeAry::make(_elem->meet_speculative(a->_elem),
                          _size->xmeet(a->_size)->is_int(),
-                         _stable && a->_stable);
+                         _stable && a->_stable,
+                         _not_flat && a->_not_flat,
+                         _not_null_free && a->_not_null_free);
   }
   case Top:
     break;
   }
   return this;                  // Return the double constant
@@ -2132,20 +2271,23 @@
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const Type *TypeAry::xdual() const {
   const TypeInt* size_dual = _size->dual()->is_int();
   size_dual = normalize_array_size(size_dual);
-  return new TypeAry(_elem->dual(), size_dual, !_stable);
+  return new TypeAry(_elem->dual(), size_dual, !_stable, !_not_flat, !_not_null_free);
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeAry::eq( const Type *t ) const {
   const TypeAry *a = (const TypeAry*)t;
   return _elem == a->_elem &&
     _stable == a->_stable &&
-    _size == a->_size;
+    _size == a->_size &&
+    _not_flat == a->_not_flat &&
+    _not_null_free == a->_not_null_free;
+
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeAry::hash(void) const {
@@ -2154,18 +2296,18 @@
 
 /**
  * Return same type without a speculative part in the element
  */
 const Type* TypeAry::remove_speculative() const {
-  return make(_elem->remove_speculative(), _size, _stable);
+  return make(_elem->remove_speculative(), _size, _stable, _not_flat, _not_null_free);
 }
 
 /**
  * Return same type with cleaned up speculative part of element
  */
 const Type* TypeAry::cleanup_speculative() const {
-  return make(_elem->cleanup_speculative(), _size, _stable);
+  return make(_elem->cleanup_speculative(), _size, _stable, _not_flat, _not_null_free);
 }
 
 /**
  * Return same type but with a different inline depth (used for speculation)
  *
@@ -2195,10 +2337,14 @@
 
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeAry::dump2( Dict &d, uint depth, outputStream *st ) const {
   if (_stable)  st->print("stable:");
+  if (Verbose) {
+    if (_not_flat) st->print("not flat:");
+    if (_not_null_free) st->print("not null free:");
+  }
   _elem->dump2(d, depth, st);
   st->print("[");
   _size->dump2(d, depth, st);
   st->print("]");
 }
@@ -2248,10 +2394,134 @@
   if (tap)
     return tap->ary()->ary_must_be_exact();
   return false;
 }
 
+//==============================TypeInlineType=======================================
+
+const TypeInlineType* TypeInlineType::BOTTOM;
+
+//------------------------------make-------------------------------------------
+const TypeInlineType* TypeInlineType::make(ciInlineKlass* vk, bool larval) {
+  return (TypeInlineType*)(new TypeInlineType(vk, larval))->hashcons();
+}
+
+//------------------------------meet-------------------------------------------
+// Compute the MEET of two types.  It returns a new Type object.
+const Type* TypeInlineType::xmeet(const Type* t) const {
+  // Perform a fast test for common case; meeting the same types together.
+  if(this == t) return this;  // Meeting same type-rep?
+
+  // Current "this->_base" is InlineType
+  switch (t->base()) {          // switch on original type
+
+  case Int:
+  case Long:
+  case FloatTop:
+  case FloatCon:
+  case FloatBot:
+  case DoubleTop:
+  case DoubleCon:
+  case DoubleBot:
+  case NarrowKlass:
+  case Bottom:
+    return Type::BOTTOM;
+
+  case OopPtr:
+  case MetadataPtr:
+  case KlassPtr:
+  case RawPtr:
+    return TypePtr::BOTTOM;
+
+  case Top:
+    return this;
+
+  case NarrowOop: {
+    const Type* res = t->make_ptr()->xmeet(this);
+    if (res->isa_ptr()) {
+      return res->make_narrowoop();
+    }
+    return res;
+  }
+
+  case AryPtr:
+  case InstPtr: {
+    return t->xmeet(this);
+  }
+
+  case InlineType: {
+    // All inline types inherit from Object
+    const TypeInlineType* other = t->is_inlinetype();
+    if (_vk == NULL) {
+      return this;
+    } else if (other->_vk == NULL) {
+      return other;
+    } else if (_vk == other->_vk) {
+      if (_larval == other->_larval ||
+          !_larval) {
+        return this;
+      } else {
+        return t;
+      }
+    }
+    return TypeInstPtr::NOTNULL;
+  }
+
+  default:                      // All else is a mistake
+    typerr(t);
+
+  }
+  return this;
+}
+
+//------------------------------xdual------------------------------------------
+const Type* TypeInlineType::xdual() const {
+  return this;
+}
+
+//------------------------------eq---------------------------------------------
+// Structural equality check for Type representations
+bool TypeInlineType::eq(const Type* t) const {
+  const TypeInlineType* vt = t->is_inlinetype();
+  return (_vk == vt->inline_klass() && _larval == vt->larval());
+}
+
+//------------------------------hash-------------------------------------------
+// Type-specific hashing function.
+int TypeInlineType::hash(void) const {
+  return (intptr_t)_vk;
+}
+
+//------------------------------singleton--------------------------------------
+// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple constants.
+bool TypeInlineType::singleton(void) const {
+  return false;
+}
+
+//------------------------------empty------------------------------------------
+// TRUE if Type is a type with no values, FALSE otherwise.
+bool TypeInlineType::empty(void) const {
+  return false;
+}
+
+//------------------------------dump2------------------------------------------
+#ifndef PRODUCT
+void TypeInlineType::dump2(Dict &d, uint depth, outputStream* st) const {
+  if (_vk == NULL) {
+    st->print("BOTTOM inlinetype");
+    return;
+  }
+  int count = _vk->nof_declared_nonstatic_fields();
+  st->print("inlinetype[%d]:{", count);
+  st->print("%s", count != 0 ? _vk->declared_nonstatic_field_at(0)->type()->name() : "empty");
+  for (int i = 1; i < count; ++i) {
+    st->print(", %s", _vk->declared_nonstatic_field_at(i)->type()->name());
+  }
+  st->print("}%s", _larval?" : larval":"");
+}
+#endif
+
 //==============================TypeVect=======================================
 // Convenience common pre-built types.
 const TypeVect *TypeVect::VECTS = NULL; //  32-bit vectors
 const TypeVect *TypeVect::VECTD = NULL; //  64-bit vectors
 const TypeVect *TypeVect::VECTX = NULL; // 128-bit vectors
@@ -2389,11 +2659,11 @@
   { /* NotNull */ NotNull,   NotNull,   NotNull,  BotPTR, NotNull, BotPTR,},
   { /* BotPTR  */ BotPTR,    BotPTR,    BotPTR,   BotPTR, BotPTR,  BotPTR,}
 };
 
 //------------------------------make-------------------------------------------
-const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) {
+const TypePtr* TypePtr::make(TYPES t, enum PTR ptr, Offset offset, const TypePtr* speculative, int inline_depth) {
   return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons();
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
 const Type *TypePtr::cast_to_ptr_type(PTR ptr) const {
@@ -2403,11 +2673,11 @@
 }
 
 //------------------------------get_con----------------------------------------
 intptr_t TypePtr::get_con() const {
   assert( _ptr == Null, "" );
-  return _offset;
+  return offset();
 }
 
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
 const Type *TypePtr::xmeet(const Type *t) const {
@@ -2472,24 +2742,17 @@
   }
   return this;
 }
 
 //------------------------------meet_offset------------------------------------
-int TypePtr::meet_offset( int offset ) const {
-  // Either is 'TOP' offset?  Return the other offset!
-  if( _offset == OffsetTop ) return offset;
-  if( offset == OffsetTop ) return _offset;
-  // If either is different, return 'BOTTOM' offset
-  if( _offset != offset ) return OffsetBot;
-  return _offset;
+Type::Offset TypePtr::meet_offset(int offset) const {
+  return _offset.meet(Offset(offset));
 }
 
 //------------------------------dual_offset------------------------------------
-int TypePtr::dual_offset( ) const {
-  if( _offset == OffsetTop ) return OffsetBot;// Map 'TOP' into 'BOTTOM'
-  if( _offset == OffsetBot ) return OffsetTop;// Map 'BOTTOM' into 'TOP'
-  return _offset;               // Map everything else into self
+Type::Offset TypePtr::dual_offset() const {
+  return _offset.dual();
 }
 
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = {
@@ -2498,23 +2761,12 @@
 const Type *TypePtr::xdual() const {
   return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth());
 }
 
 //------------------------------xadd_offset------------------------------------
-int TypePtr::xadd_offset( intptr_t offset ) const {
-  // Adding to 'TOP' offset?  Return 'TOP'!
-  if( _offset == OffsetTop || offset == OffsetTop ) return OffsetTop;
-  // Adding to 'BOTTOM' offset?  Return 'BOTTOM'!
-  if( _offset == OffsetBot || offset == OffsetBot ) return OffsetBot;
-  // Addition overflows or "accidentally" equals to OffsetTop? Return 'BOTTOM'!
-  offset += (intptr_t)_offset;
-  if (offset != (int)offset || offset == OffsetTop) return OffsetBot;
-
-  // assert( _offset >= 0 && _offset+offset >= 0, "" );
-  // It is possible to construct a negative offset during PhaseCCP
-
-  return (int)offset;        // Sum valid offsets
+Type::Offset TypePtr::xadd_offset(intptr_t offset) const {
+  return _offset.add(offset);
 }
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypePtr::add_offset( intptr_t offset ) const {
   return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth);
@@ -2522,17 +2774,17 @@
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypePtr::eq( const Type *t ) const {
   const TypePtr *a = (const TypePtr*)t;
-  return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth;
+  return _ptr == a->ptr() && _offset == a->_offset && eq_speculative(a) && _inline_depth == a->_inline_depth;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypePtr::hash(void) const {
-  return java_add(java_add((jint)_ptr, (jint)_offset), java_add((jint)hash_speculative(), (jint)_inline_depth));
+  return java_add(java_add((jint)_ptr, (jint)offset()), java_add((jint)hash_speculative(), (jint)_inline_depth));
 ;
 }
 
 /**
  * Return same type without a speculative part
@@ -2788,13 +3040,11 @@
 
 #ifndef PRODUCT
 void TypePtr::dump2( Dict &d, uint depth, outputStream *st ) const {
   if( _ptr == Null ) st->print("NULL");
   else st->print("%s *", ptr_msg[_ptr]);
-  if( _offset == OffsetTop ) st->print("+top");
-  else if( _offset == OffsetBot ) st->print("+bot");
-  else if( _offset ) st->print("+%d", _offset);
+  _offset.dump2(st);
   dump_inline_depth(st);
   dump_speculative(st);
 }
 
 /**
@@ -2825,15 +3075,15 @@
 //------------------------------singleton--------------------------------------
 // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
 // constants
 bool TypePtr::singleton(void) const {
   // TopPTR, Null, AnyNull, Constant are all singletons
-  return (_offset != OffsetBot) && !below_centerline(_ptr);
+  return (_offset != Offset::bottom) && !below_centerline(_ptr);
 }
 
 bool TypePtr::empty(void) const {
-  return (_offset == OffsetTop) || above_centerline(_ptr);
+  return (_offset == Offset::top) || above_centerline(_ptr);
 }
 
 //=============================================================================
 // Convenience common pre-built types.
 const TypeRawPtr *TypeRawPtr::BOTTOM;
@@ -2971,63 +3221,76 @@
 //=============================================================================
 // Convenience common pre-built type.
 const TypeOopPtr *TypeOopPtr::BOTTOM;
 
 //------------------------------TypeOopPtr-------------------------------------
-TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
+TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset offset, Offset field_offset,
                        int instance_id, const TypePtr* speculative, int inline_depth)
   : TypePtr(t, ptr, offset, speculative, inline_depth),
     _const_oop(o), _klass(k),
     _klass_is_exact(xk),
     _is_ptr_to_narrowoop(false),
     _is_ptr_to_narrowklass(false),
     _is_ptr_to_boxed_value(false),
     _instance_id(instance_id) {
   if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
-      (offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
-    _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
+      (offset.get() > 0) && xk && (k != 0) && k->is_instance_klass()) {
+    _is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset.get());
   }
 #ifdef _LP64
-  if (_offset > 0 || _offset == Type::OffsetTop || _offset == Type::OffsetBot) {
-    if (_offset == oopDesc::klass_offset_in_bytes()) {
+  if (this->offset() > 0 || this->offset() == Type::OffsetTop || this->offset() == Type::OffsetBot) {
+    if (this->offset() == oopDesc::klass_offset_in_bytes()) {
       _is_ptr_to_narrowklass = UseCompressedClassPointers;
     } else if (klass() == NULL) {
       // Array with unknown body type
       assert(this->isa_aryptr(), "only arrays without klass");
       _is_ptr_to_narrowoop = UseCompressedOops;
-    } else if (this->isa_aryptr()) {
-      _is_ptr_to_narrowoop = (UseCompressedOops && klass()->is_obj_array_klass() &&
-                             _offset != arrayOopDesc::length_offset_in_bytes());
+    } else if (UseCompressedOops && this->isa_aryptr() && this->offset() != arrayOopDesc::length_offset_in_bytes()) {
+      if (klass()->is_obj_array_klass()) {
+        _is_ptr_to_narrowoop = true;
+      } else if (klass()->is_flat_array_klass() && field_offset != Offset::top && field_offset != Offset::bottom) {
+        // Check if the field of the inline type array element contains oops
+        ciInlineKlass* vk = klass()->as_flat_array_klass()->element_klass()->as_inline_klass();
+        int foffset = field_offset.get() + vk->first_field_offset();
+        ciField* field = vk->get_field_by_offset(foffset, false);
+        assert(field != NULL, "missing field");
+        BasicType bt = field->layout_type();
+        _is_ptr_to_narrowoop = (bt == T_OBJECT || bt == T_ARRAY || T_INLINE_TYPE);
+      }
     } else if (klass()->is_instance_klass()) {
-      ciInstanceKlass* ik = klass()->as_instance_klass();
-      ciField* field = NULL;
       if (this->isa_klassptr()) {
         // Perm objects don't use compressed references
-      } else if (_offset == OffsetBot || _offset == OffsetTop) {
+      } else if (_offset == Offset::bottom || _offset == Offset::top) {
         // unsafe access
         _is_ptr_to_narrowoop = UseCompressedOops;
       } else { // exclude unsafe ops
         assert(this->isa_instptr(), "must be an instance ptr.");
-
-        if (klass() == ciEnv::current()->Class_klass() &&
-            (_offset == java_lang_Class::klass_offset() ||
+        if (klass() == ciEnv::current()->Class_klass() &&
+            (this->offset() == java_lang_Class::klass_offset() ||
              _offset == java_lang_Class::array_klass_offset())) {
           // Special hidden fields from the Class.
           assert(this->isa_instptr(), "must be an instance ptr.");
           _is_ptr_to_narrowoop = false;
         } else if (klass() == ciEnv::current()->Class_klass() &&
-                   _offset >= InstanceMirrorKlass::offset_of_static_fields()) {
+                   this->offset() >= InstanceMirrorKlass::offset_of_static_fields()) {
           // Static fields
           assert(o != NULL, "must be constant");
-          ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass();
-          ciField* field = k->get_field_by_offset(_offset, true);
-          assert(field != NULL, "missing field");
-          BasicType basic_elem_type = field->layout_type();
+          ciInstanceKlass* ik = o->as_instance()->java_lang_Class_klass()->as_instance_klass();
+          BasicType basic_elem_type;
+          if (ik->is_inlinetype() && this->offset() == ik->as_inline_klass()->default_value_offset()) {
+            // Special hidden field that contains the oop of the default inline type
+            basic_elem_type = T_INLINE_TYPE;
+          } else {
+            ciField* field = ik->get_field_by_offset(this->offset(), true);
+            assert(field != NULL, "missing field");
+            basic_elem_type = field->layout_type();
+          }
           _is_ptr_to_narrowoop = UseCompressedOops && is_reference_type(basic_elem_type);
         } else {
           // Instance fields which contains a compressed oop references.
-          field = ik->get_field_by_offset(_offset, false);
+          ciInstanceKlass* ik = klass()->as_instance_klass();
+          ciField* field = ik->get_field_by_offset(this->offset(), false);
           if (field != NULL) {
             BasicType basic_elem_type = field->layout_type();
             _is_ptr_to_narrowoop = UseCompressedOops && is_reference_type(basic_elem_type);
           } else if (klass()->equals(ciEnv::current()->Object_klass())) {
             // Compile::find_alias_type() cast exactness on all types to verify
@@ -3043,17 +3306,17 @@
   }
 #endif
 }
 
 //------------------------------make-------------------------------------------
-const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id,
-                                     const TypePtr* speculative, int inline_depth) {
+const TypeOopPtr *TypeOopPtr::make(PTR ptr, Offset offset, int instance_id,
+                                   const TypePtr* speculative, int inline_depth) {
   assert(ptr != Constant, "no constant generic pointers");
   ciKlass*  k = Compile::current()->env()->Object_klass();
   bool      xk = false;
   ciObject* o = NULL;
-  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, instance_id, speculative, inline_depth))->hashcons();
+  return (TypeOopPtr*)(new TypeOopPtr(OopPtr, ptr, k, xk, o, offset, Offset::bottom, instance_id, speculative, inline_depth))->hashcons();
 }
 
 
 //------------------------------cast_to_ptr_type-------------------------------
 const Type *TypeOopPtr::cast_to_ptr_type(PTR ptr) const {
@@ -3074,23 +3337,10 @@
   // There is no such thing as an exact general oop.
   // Return self unchanged.
   return this;
 }
 
-
-//------------------------------as_klass_type----------------------------------
-// Return the klass type corresponding to this instance or array type.
-// It is the type that is loaded from an object of this type.
-const TypeKlassPtr* TypeOopPtr::as_klass_type() const {
-  ciKlass* k = klass();
-  bool    xk = klass_is_exact();
-  if (k == NULL)
-    return TypeKlassPtr::OBJECT;
-  else
-    return TypeKlassPtr::make(xk? Constant: NotNull, k, 0);
-}
-
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
 const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
   // Perform a fast test for common case; meeting the same types together.
   if( this == t ) return this;  // Meeting same type-rep?
@@ -3122,11 +3372,11 @@
     return TypePtr::BOTTOM;     // Oop meet raw is not well defined
 
   case AnyPtr: {
     // Found an AnyPtr type vs self-OopPtr type
     const TypePtr *tp = t->is_ptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
     switch (tp->ptr()) {
     case Null:
@@ -3164,17 +3414,17 @@
 //------------------------------xdual------------------------------------------
 // Dual of a pure heap pointer.  No relevant klass or oop information.
 const Type *TypeOopPtr::xdual() const {
   assert(klass() == Compile::current()->env()->Object_klass(), "no klasses here");
   assert(const_oop() == NULL,             "no constants here");
-  return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
+  return new TypeOopPtr(_base, dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), Offset::bottom, dual_instance_id(), dual_speculative(), dual_inline_depth());
 }
 
 //--------------------------make_from_klass_common-----------------------------
 // Computes the element-type given a klass.
 const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_change, bool try_for_exact) {
-  if (klass->is_instance_klass()) {
+  if (klass->is_instance_klass() || klass->is_inlinetype()) {
     Compile* C = Compile::current();
     Dependencies* deps = C->dependencies();
     assert((deps != NULL) == (C->method() != NULL && C->method()->code_size() > 0), "sanity");
     // Element is an instance
     bool klass_is_exact = false;
@@ -3196,28 +3446,46 @@
         // Add a dependence; if concrete subclass added we need to recompile
         deps->assert_leaf_type(ik);
         klass_is_exact = true;
       }
     }
-    return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, 0);
+    return TypeInstPtr::make(TypePtr::BotPTR, klass, klass_is_exact, NULL, Offset(0));
   } else if (klass->is_obj_array_klass()) {
-    // Element is an object array. Recursively call ourself.
-    const TypeOopPtr *etype = TypeOopPtr::make_from_klass_common(klass->as_obj_array_klass()->element_klass(), false, try_for_exact);
+    // Element is an object or inline type array. Recursively call ourself.
+    const TypeOopPtr* etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ false, try_for_exact);
+    if (etype->is_inlinetypeptr()) {
+      etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr();
+    }
+    // Determine null-free/flattened properties
+    const TypeOopPtr* exact_etype = etype;
+    if (etype->can_be_inline_type()) {
+      // Use exact type if element can be an inline type
+      exact_etype = TypeOopPtr::make_from_klass_common(klass->as_array_klass()->element_klass(), /* klass_change= */ true, /* try_for_exact= */ true);
+    }
+    bool not_null_free = !exact_etype->can_be_inline_type();
+    bool not_flat = !UseFlatArray || not_null_free || (exact_etype->is_inlinetypeptr() && !exact_etype->inline_klass()->flatten_array());
+
     bool xk = etype->klass_is_exact();
-    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
+    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS, false, not_flat, not_null_free);
     // We used to pass NotNull in here, asserting that the sub-arrays
     // are all not-null.  This is not true in generally, as code can
     // slam NULLs down in the subarrays.
-    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, 0);
+    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, xk, Offset(0));
     return arr;
   } else if (klass->is_type_array_klass()) {
     // Element is an typeArray
     const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
-    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
+    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS,
+                                        /* stable= */ false, /* not_flat= */ true, /* not_null_free= */ true);
     // We used to pass NotNull in here, asserting that the array pointer
     // is not-null. That was not true in general.
-    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, 0);
+    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0));
+    return arr;
+  } else if (klass->is_flat_array_klass()) {
+    ciInlineKlass* vk = klass->as_array_klass()->element_klass()->as_inline_klass();
+    const TypeAry* arr0 = TypeAry::make(TypeInlineType::make(vk), TypeInt::POS);
+    const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::BotPTR, arr0, klass, true, Offset(0));
     return arr;
   } else {
     ShouldNotReachHere();
     return NULL;
   }
@@ -3229,54 +3497,70 @@
   assert(!o->is_null_object(), "null object not yet handled here.");
 
   const bool make_constant = require_constant || o->should_be_constant();
 
   ciKlass* klass = o->klass();
-  if (klass->is_instance_klass()) {
-    // Element is an instance
+  if (klass->is_instance_klass() || klass->is_inlinetype()) {
+    // Element is an instance or inline type
     if (make_constant) {
       return TypeInstPtr::make(o);
     } else {
-      return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, 0);
+      return TypeInstPtr::make(TypePtr::NotNull, klass, true, NULL, Offset(0));
     }
   } else if (klass->is_obj_array_klass()) {
     // Element is an object array. Recursively call ourself.
-    const TypeOopPtr *etype =
-      TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
-    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
+    const TypeOopPtr* etype = TypeOopPtr::make_from_klass_raw(klass->as_array_klass()->element_klass());
+    bool null_free = false;
+    if (etype->is_inlinetypeptr()) {
+      null_free = true;
+      etype = etype->join_speculative(TypePtr::NOTNULL)->is_oopptr();
+    }
+    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()),
+                                        /* stable= */ false, /* not_flat= */ true, /* not_null_free= */ !null_free);
     // We used to pass NotNull in here, asserting that the sub-arrays
     // are all not-null.  This is not true in generally, as code can
     // slam NULLs down in the subarrays.
     if (make_constant) {
-      return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
+      return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
     } else {
-      return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+      return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
     }
   } else if (klass->is_type_array_klass()) {
     // Element is an typeArray
-    const Type* etype =
-      (Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
-    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
+    const Type* etype = (Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
+    const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()),
+                                        /* stable= */ false, /* not_flat= */ true, /* not_null_free= */ true);
     // We used to pass NotNull in here, asserting that the array pointer
     // is not-null. That was not true in general.
     if (make_constant) {
-      return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
+      return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
     } else {
-      return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
+      return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
+    }
+  } else if (klass->is_flat_array_klass()) {
+    ciInlineKlass* vk = klass->as_array_klass()->element_klass()->as_inline_klass();
+    const TypeAry* arr0 = TypeAry::make(TypeInlineType::make(vk), TypeInt::make(o->as_array()->length()));
+    // We used to pass NotNull in here, asserting that the sub-arrays
+    // are all not-null.  This is not true in generally, as code can
+    // slam NULLs down in the subarrays.
+    if (make_constant) {
+      return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, Offset(0));
+    } else {
+      return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, Offset(0));
     }
   }
 
   fatal("unhandled object type");
   return NULL;
 }
 
 //------------------------------get_con----------------------------------------
 intptr_t TypeOopPtr::get_con() const {
   assert( _ptr == Null || _ptr == Constant, "" );
-  assert( _offset >= 0, "" );
+  assert(offset() >= 0, "");
 
-  if (_offset != 0) {
+  if (offset() != 0) {
     // After being ported to the compiler interface, the compiler no longer
     // directly manipulates the addresses of oops.  Rather, it only has a pointer
     // to a handle at compile time.  This handle is embedded in the generated
     // code and dereferenced at the time the nmethod is made.  Until that time,
     // it is not reasonable to do arithmetic with the addresses of oops (we don't
@@ -3365,16 +3649,11 @@
 #ifndef PRODUCT
 void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
   st->print("oopptr:%s", ptr_msg[_ptr]);
   if( _klass_is_exact ) st->print(":exact");
   if( const_oop() ) st->print(INTPTR_FORMAT, p2i(const_oop()));
-  switch( _offset ) {
-  case OffsetTop: st->print("+top"); break;
-  case OffsetBot: st->print("+any"); break;
-  case         0: break;
-  default:        st->print("+%d",_offset); break;
-  }
+  _offset.dump2(st);
   if (_instance_id == InstanceTop)
     st->print(",iid=top");
   else if (_instance_id != InstanceBot)
     st->print(",iid=%d",_instance_id);
 
@@ -3387,11 +3666,11 @@
 // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
 // constants
 bool TypeOopPtr::singleton(void) const {
   // detune optimizer to not generate constant oop + constant offset as a constant!
   // TopPTR, Null, AnyNull, Constant are all singletons
-  return (_offset == 0) && !below_centerline(_ptr);
+  return (offset() == 0) && !below_centerline(_ptr);
 }
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypeOopPtr::add_offset(intptr_t offset) const {
   return make(_ptr, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
@@ -3479,25 +3758,29 @@
 const TypeInstPtr *TypeInstPtr::MIRROR;
 const TypeInstPtr *TypeInstPtr::MARK;
 const TypeInstPtr *TypeInstPtr::KLASS;
 
 //------------------------------TypeInstPtr-------------------------------------
-TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off,
-                         int instance_id, const TypePtr* speculative, int inline_depth)
-  : TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth),
-    _name(k->name()) {
-   assert(k != NULL &&
-          (k->is_loaded() || o == NULL),
-          "cannot have constants with non-loaded klass");
+TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, Offset off,
+                         bool flatten_array, int instance_id, const TypePtr* speculative,
+                         int inline_depth)
+  : TypeOopPtr(InstPtr, ptr, k, xk, o, off, Offset::bottom, instance_id, speculative, inline_depth),
+    _name(k->name()), _flatten_array(flatten_array) {
+  assert(k != NULL &&
+         (k->is_loaded() || o == NULL),
+         "cannot have constants with non-loaded klass");
+  assert(!klass()->flatten_array() || flatten_array, "Should be flat in array");
+  assert(!flatten_array || can_be_inline_type(), "Only inline types can be flat in array");
 };
 
 //------------------------------make-------------------------------------------
 const TypeInstPtr *TypeInstPtr::make(PTR ptr,
                                      ciKlass* k,
                                      bool xk,
                                      ciObject* o,
-                                     int offset,
+                                     Offset offset,
+                                     bool flatten_array,
                                      int instance_id,
                                      const TypePtr* speculative,
                                      int inline_depth) {
   assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
   // Either const_oop() is NULL or else ptr is Constant
@@ -3514,13 +3797,16 @@
     ciInstanceKlass* ik = k->as_instance_klass();
     if (!xk && ik->is_final())     xk = true;   // no inexact final klass
     if (xk && ik->is_interface())  xk = false;  // no exact interface
   }
 
+  // Check if this type is known to be flat in arrays
+  flatten_array = flatten_array || k->flatten_array();
+
   // Now hash this baby
   TypeInstPtr *result =
-    (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o ,offset, instance_id, speculative, inline_depth))->hashcons();
+    (TypeInstPtr*)(new TypeInstPtr(ptr, k, xk, o, offset, flatten_array, instance_id, speculative, inline_depth))->hashcons();
 
   return result;
 }
 
 /**
@@ -3549,35 +3835,35 @@
 //------------------------------cast_to_ptr_type-------------------------------
 const Type *TypeInstPtr::cast_to_ptr_type(PTR ptr) const {
   if( ptr == _ptr ) return this;
   // Reconstruct _sig info here since not a problem with later lazy
   // construction, _sig will show up on demand.
-  return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr, klass(), klass_is_exact(), const_oop(), _offset, _flatten_array, _instance_id, _speculative, _inline_depth);
 }
 
 
 //-----------------------------cast_to_exactness-------------------------------
 const Type *TypeInstPtr::cast_to_exactness(bool klass_is_exact) const {
   if( klass_is_exact == _klass_is_exact ) return this;
   if (!_klass->is_loaded())  return this;
   ciInstanceKlass* ik = _klass->as_instance_klass();
   if( (ik->is_final() || _const_oop) )  return this;  // cannot clear xk
   if( ik->is_interface() )              return this;  // cannot set xk
-  return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr(), klass(), klass_is_exact, const_oop(), _offset, _flatten_array, _instance_id, _speculative, _inline_depth);
 }
 
 //-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr *TypeInstPtr::cast_to_instance_id(int instance_id) const {
   if( instance_id == _instance_id ) return this;
-  return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, klass(), _klass_is_exact, const_oop(), _offset, _flatten_array, instance_id, _speculative, _inline_depth);
 }
 
 //------------------------------xmeet_unloaded---------------------------------
 // Compute the MEET of two InstPtrs when at least one is unloaded.
 // Assume classes are different since called after check for same name/class-loader
 const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
-    int off = meet_offset(tinst->offset());
+    Offset off = meet_offset(tinst->offset());
     PTR ptr = meet_ptr(tinst->ptr());
     int instance_id = meet_instance_id(tinst->instance_id());
     const TypePtr* speculative = xmeet_speculative(tinst);
     int depth = meet_inline_depth(tinst->inline_depth());
 
@@ -3598,11 +3884,11 @@
       //  BOTTOM  | ........................Object-BOTTOM ..................|
       //
       assert(loaded->ptr() != TypePtr::Null, "insanity check");
       //
       if(      loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
-      else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, instance_id, speculative, depth); }
+      else if (loaded->ptr() == TypePtr::AnyNull) { return TypeInstPtr::make(ptr, unloaded->klass(), false, NULL, off, false, instance_id, speculative, depth); }
       else if (loaded->ptr() == TypePtr::BotPTR ) { return TypeInstPtr::BOTTOM; }
       else if (loaded->ptr() == TypePtr::Constant || loaded->ptr() == TypePtr::NotNull) {
         if (unloaded->ptr() == TypePtr::BotPTR  ) { return TypeInstPtr::BOTTOM;  }
         else                                      { return TypeInstPtr::NOTNULL; }
       }
@@ -3651,28 +3937,28 @@
   case KlassPtr:
   case RawPtr: return TypePtr::BOTTOM;
 
   case AryPtr: {                // All arrays inherit from Object class
     const TypeAryPtr *tp = t->is_aryptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     int instance_id = meet_instance_id(tp->instance_id());
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
     switch (ptr) {
     case TopPTR:
     case AnyNull:                // Fall 'down' to dual of object klass
       // For instances when a subclass meets a superclass we fall
       // below the centerline when the superclass is exact. We need to
       // do the same here.
-      if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
-        return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth);
+      if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact() && !flatten_array()) {
+        return TypeAryPtr::make(ptr, tp->ary(), tp->klass(), tp->klass_is_exact(), offset, tp->field_offset(), instance_id, speculative, depth);
       } else {
         // cannot subclass, so the meet has to fall badly below the centerline
         ptr = NotNull;
         instance_id = InstanceBot;
-        return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
+        return TypeInstPtr::make( ptr, ciEnv::current()->Object_klass(), false, NULL, offset, false, instance_id, speculative, depth);
       }
     case Constant:
     case NotNull:
     case BotPTR:                // Fall down to object klass
       // LCA is object_klass, but if we subclass from the top we can do better
@@ -3680,39 +3966,39 @@
         // If 'this' (InstPtr) is above the centerline and it is Object class
         // then we can subclass in the Java class hierarchy.
         // For instances when a subclass meets a superclass we fall
         // below the centerline when the superclass is exact. We need
         // to do the same here.
-        if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
+        if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact() && !flatten_array()) {
           // that is, tp's array type is a subtype of my klass
           return TypeAryPtr::make(ptr, (ptr == Constant ? tp->const_oop() : NULL),
-                                  tp->ary(), tp->klass(), tp->klass_is_exact(), offset, instance_id, speculative, depth);
+                                  tp->ary(), tp->klass(), tp->klass_is_exact(), offset, tp->field_offset(), instance_id, speculative, depth);
         }
       }
       // The other case cannot happen, since I cannot be a subtype of an array.
       // The meet falls down to Object class below centerline.
       if( ptr == Constant )
          ptr = NotNull;
       instance_id = InstanceBot;
-      return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
+      return make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, false, instance_id, speculative, depth);
     default: typerr(t);
     }
   }
 
   case OopPtr: {                // Meeting to OopPtrs
     // Found a OopPtr type vs self-InstPtr type
     const TypeOopPtr *tp = t->is_oopptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     switch (tp->ptr()) {
     case TopPTR:
     case AnyNull: {
       int instance_id = meet_instance_id(InstanceTop);
       const TypePtr* speculative = xmeet_speculative(tp);
       int depth = meet_inline_depth(tp->inline_depth());
       return make(ptr, klass(), klass_is_exact(),
-                  (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
+                  (ptr == Constant ? const_oop() : NULL), offset, flatten_array(), instance_id, speculative, depth);
     }
     case NotNull:
     case BotPTR: {
       int instance_id = meet_instance_id(tp->instance_id());
       const TypePtr* speculative = xmeet_speculative(tp);
@@ -3724,11 +4010,11 @@
   }
 
   case AnyPtr: {                // Meeting to AnyPtrs
     // Found an AnyPtr type vs self-InstPtr type
     const TypePtr *tp = t->is_ptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     int instance_id = meet_instance_id(InstanceTop);
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
     switch (tp->ptr()) {
@@ -3736,11 +4022,11 @@
       if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
       // else fall through to AnyNull
     case TopPTR:
     case AnyNull: {
       return make(ptr, klass(), klass_is_exact(),
-                  (ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
+                  (ptr == Constant ? const_oop() : NULL), offset, flatten_array(), instance_id, speculative, depth);
     }
     case NotNull:
     case BotPTR:
       return TypePtr::make(AnyPtr, ptr, offset, speculative,depth);
     default: typerr(t);
@@ -3764,29 +4050,32 @@
   */
 
   case InstPtr: {                // Meeting 2 Oops?
     // Found an InstPtr sub-type vs self-InstPtr type
     const TypeInstPtr *tinst = t->is_instptr();
-    int off = meet_offset( tinst->offset() );
+    Offset off = meet_offset( tinst->offset() );
     PTR ptr = meet_ptr( tinst->ptr() );
     int instance_id = meet_instance_id(tinst->instance_id());
     const TypePtr* speculative = xmeet_speculative(tinst);
     int depth = meet_inline_depth(tinst->inline_depth());
 
     // Check for easy case; klasses are equal (and perhaps not loaded!)
     // If we have constants, then we created oops so classes are loaded
     // and we can handle the constants further down.  This case handles
     // both-not-loaded or both-loaded classes
-    if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact()) {
-      return make(ptr, klass(), klass_is_exact(), NULL, off, instance_id, speculative, depth);
+    if (ptr != Constant && klass()->equals(tinst->klass()) && klass_is_exact() == tinst->klass_is_exact() &&
+        flatten_array() == tinst->flatten_array()) {
+      return make(ptr, klass(), klass_is_exact(), NULL, off, flatten_array(), instance_id, speculative, depth);
     }
 
     // Classes require inspection in the Java klass hierarchy.  Must be loaded.
     ciKlass* tinst_klass = tinst->klass();
     ciKlass* this_klass  = this->klass();
     bool tinst_xk = tinst->klass_is_exact();
     bool this_xk  = this->klass_is_exact();
+    bool tinst_flatten_array = tinst->flatten_array();
+    bool this_flatten_array  = this->flatten_array();
     if (!tinst_klass->is_loaded() || !this_klass->is_loaded() ) {
       // One of these classes has not been loaded
       const TypeInstPtr *unloaded_meet = xmeet_unloaded(tinst);
 #ifndef PRODUCT
       if( PrintOpto && Verbose ) {
@@ -3805,10 +4094,13 @@
       tinst_klass = this_klass;
       this_klass = tmp;
       bool tmp2 = tinst_xk;
       tinst_xk = this_xk;
       this_xk = tmp2;
+      tmp2 = tinst_flatten_array;
+      tinst_flatten_array = this_flatten_array;
+      this_flatten_array = tmp2;
     }
     if (tinst_klass->is_interface() &&
         !(this_klass->is_interface() ||
           // Treat java/lang/Object as an honorary interface,
           // because we need a bottom for the interface hierarchy.
@@ -3816,34 +4108,37 @@
       // Oop meets interface!
 
       // See if the oop subtypes (implements) interface.
       ciKlass *k;
       bool xk;
+      bool flat_array;
       if( this_klass->is_subtype_of( tinst_klass ) ) {
         // Oop indeed subtypes.  Now keep oop or interface depending
         // on whether we are both above the centerline or either is
         // below the centerline.  If we are on the centerline
         // (e.g., Constant vs. AnyNull interface), use the constant.
         k  = below_centerline(ptr) ? tinst_klass : this_klass;
         // If we are keeping this_klass, keep its exactness too.
         xk = below_centerline(ptr) ? tinst_xk    : this_xk;
+        flat_array = below_centerline(ptr) ? tinst_flatten_array    : this_flatten_array;
       } else {                  // Does not implement, fall to Object
         // Oop does not implement interface, so mixing falls to Object
         // just like the verifier does (if both are above the
         // centerline fall to interface)
         k = above_centerline(ptr) ? tinst_klass : ciEnv::current()->Object_klass();
         xk = above_centerline(ptr) ? tinst_xk : false;
+        flat_array = above_centerline(ptr) ? tinst_flatten_array : false;
         // Watch out for Constant vs. AnyNull interface.
         if (ptr == Constant)  ptr = NotNull;   // forget it was a constant
         instance_id = InstanceBot;
       }
       ciObject* o = NULL;  // the Constant value, if any
       if (ptr == Constant) {
         // Find out which constant.
         o = (this_klass == klass()) ? const_oop() : tinst->const_oop();
       }
-      return make(ptr, k, xk, o, off, instance_id, speculative, depth);
+      return make(ptr, k, xk, o, off, flat_array, instance_id, speculative, depth);
     }
 
     // Either oop vs oop or interface vs interface or interface vs Object
 
     // !!! Here's how the symmetry requirement breaks down into invariants:
@@ -3871,33 +4166,41 @@
     // centerline and or-ed above it.  (N.B. Constants are always exact.)
 
     // Check for subtyping:
     ciKlass *subtype = NULL;
     bool subtype_exact = false;
-    if( tinst_klass->equals(this_klass) ) {
+    bool flat_array = false;
+    if (tinst_klass->equals(this_klass)) {
       subtype = this_klass;
       subtype_exact = below_centerline(ptr) ? (this_xk && tinst_xk) : (this_xk || tinst_xk);
-    } else if( !tinst_xk && this_klass->is_subtype_of( tinst_klass ) ) {
+      flat_array = below_centerline(ptr) ? (this_flatten_array && tinst_flatten_array) : (this_flatten_array || tinst_flatten_array);
+    } else if(!tinst_xk && this_klass->is_subtype_of(tinst_klass) && (!tinst_flatten_array || this_flatten_array)) {
       subtype = this_klass;     // Pick subtyping class
       subtype_exact = this_xk;
-    } else if( !this_xk && tinst_klass->is_subtype_of( this_klass ) ) {
+      flat_array = this_flatten_array;
+    } else if(!this_xk && tinst_klass->is_subtype_of(this_klass) && (!this_flatten_array || tinst_flatten_array)) {
       subtype = tinst_klass;    // Pick subtyping class
       subtype_exact = tinst_xk;
+      flat_array = tinst_flatten_array;
     }
 
-    if( subtype ) {
-      if( above_centerline(ptr) ) { // both are up?
+    if (subtype) {
+      if (above_centerline(ptr)) { // both are up?
         this_klass = tinst_klass = subtype;
         this_xk = tinst_xk = subtype_exact;
-      } else if( above_centerline(this ->_ptr) && !above_centerline(tinst->_ptr) ) {
+        this_flatten_array = tinst_flatten_array = flat_array;
+      } else if (above_centerline(this ->_ptr) && !above_centerline(tinst->_ptr)) {
         this_klass = tinst_klass; // tinst is down; keep down man
         this_xk = tinst_xk;
-      } else if( above_centerline(tinst->_ptr) && !above_centerline(this ->_ptr) ) {
+        this_flatten_array = tinst_flatten_array;
+      } else if (above_centerline(tinst->_ptr) && !above_centerline(this ->_ptr)) {
         tinst_klass = this_klass; // this is down; keep down man
         tinst_xk = this_xk;
+        tinst_flatten_array = this_flatten_array;
       } else {
         this_xk = subtype_exact;  // either they are equal, or we'll do an LCA
+        this_flatten_array = flat_array;
       }
     }
 
     // Check for classes now being equal
     if (tinst_klass->equals(this_klass)) {
@@ -3916,11 +4219,11 @@
         else if (above_centerline(tinst ->_ptr))
           o = this_oop;
         else
           ptr = NotNull;
       }
-      return make(ptr, this_klass, this_xk, o, off, instance_id, speculative, depth);
+      return make(ptr, this_klass, this_xk, o, off, this_flatten_array, instance_id, speculative, depth);
     } // Else classes are not equal
 
     // Since klasses are different, we require a LCA in the Java
     // class hierarchy - which means we have to fall to at least NotNull.
     if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
@@ -3928,13 +4231,34 @@
 
     instance_id = InstanceBot;
 
     // Now we find the LCA of Java classes
     ciKlass* k = this_klass->least_common_ancestor(tinst_klass);
-    return make(ptr, k, false, NULL, off, instance_id, speculative, depth);
+    return make(ptr, k, false, NULL, off, false, instance_id, speculative, depth);
   } // End of case InstPtr
 
+  case InlineType: {
+    const TypeInlineType* tv = t->is_inlinetype();
+    if (above_centerline(ptr())) {
+      if (tv->inline_klass()->is_subtype_of(_klass)) {
+        return t;
+      } else {
+        return TypeInstPtr::NOTNULL;
+      }
+    } else {
+      PTR ptr = this->_ptr;
+      if (ptr == Constant) {
+        ptr = NotNull;
+      }
+      if (tv->inline_klass()->is_subtype_of(_klass)) {
+        return TypeInstPtr::make(ptr, _klass);
+      } else {
+        return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass());
+      }
+    }
+  }
+
   } // End of switch
   return this;                  // Return the double constant
 }
 
 
@@ -3943,35 +4267,35 @@
   // must be a singleton type
   if( const_oop() == NULL )  return NULL;
 
   // must be of type java.lang.Class
   if( klass() != ciEnv::current()->Class_klass() )  return NULL;
-
   return const_oop()->as_instance()->java_mirror_type();
 }
 
 
 //------------------------------xdual------------------------------------------
 // Dual: do NOT dual on klasses.  This means I do NOT understand the Java
 // inheritance mechanism.
 const Type *TypeInstPtr::xdual() const {
-  return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), dual_instance_id(), dual_speculative(), dual_inline_depth());
+  return new TypeInstPtr(dual_ptr(), klass(), klass_is_exact(), const_oop(), dual_offset(), flatten_array(), dual_instance_id(), dual_speculative(), dual_inline_depth());
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeInstPtr::eq( const Type *t ) const {
   const TypeInstPtr *p = t->is_instptr();
   return
     klass()->equals(p->klass()) &&
+    flatten_array() == p->flatten_array() &&
     TypeOopPtr::eq(p);          // Check sub-type stuff
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeInstPtr::hash(void) const {
-  int hash = java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash());
+  int hash = java_add(java_add((jint)klass()->hash(), (jint)TypeOopPtr::hash()), (jint)flatten_array());
   return hash;
 }
 
 //------------------------------dump2------------------------------------------
 // Dump oop Type
@@ -3999,17 +4323,18 @@
     break;
   default:
     break;
   }
 
-  if( _offset ) {               // Dump offset, if any
-    if( _offset == OffsetBot )      st->print("+any");
-    else if( _offset == OffsetTop ) st->print("+unknown");
-    else st->print("+%d", _offset);
-  }
+  _offset.dump2(st);
 
   st->print(" *");
+
+  if (flatten_array() && !klass()->is_inlinetype()) {
+    st->print(" (flatten array)");
+  }
+
   if (_instance_id == InstanceTop)
     st->print(",iid=top");
   else if (_instance_id != InstanceBot)
     st->print(",iid=%d",_instance_id);
 
@@ -4018,35 +4343,40 @@
 }
 #endif
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const {
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset),
+  return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), flatten_array(),
               _instance_id, add_offset_speculative(offset), _inline_depth);
 }
 
 const Type *TypeInstPtr::remove_speculative() const {
   if (_speculative == NULL) {
     return this;
   }
   assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset,
+  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(),
               _instance_id, NULL, _inline_depth);
 }
 
 const TypePtr *TypeInstPtr::with_inline_depth(int depth) const {
   if (!UseInlineDepthForSpeculativeTypes) {
     return this;
   }
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, _speculative, depth);
+  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(), _instance_id, _speculative, depth);
 }
 
 const TypePtr *TypeInstPtr::with_instance_id(int instance_id) const {
   assert(is_known_instance(), "should be known");
-  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, flatten_array(), instance_id, _speculative, _inline_depth);
+}
+
+const TypeInstPtr *TypeInstPtr::cast_to_flatten_array() const {
+  return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, true, _instance_id, _speculative, _inline_depth);
 }
 
+
 //=============================================================================
 // Convenience common pre-built types.
 const TypeAryPtr *TypeAryPtr::RANGE;
 const TypeAryPtr *TypeAryPtr::OOPS;
 const TypeAryPtr *TypeAryPtr::NARROWOOPS;
@@ -4055,51 +4385,58 @@
 const TypeAryPtr *TypeAryPtr::CHARS;
 const TypeAryPtr *TypeAryPtr::INTS;
 const TypeAryPtr *TypeAryPtr::LONGS;
 const TypeAryPtr *TypeAryPtr::FLOATS;
 const TypeAryPtr *TypeAryPtr::DOUBLES;
+const TypeAryPtr *TypeAryPtr::INLINES;
 
 //------------------------------make-------------------------------------------
-const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,
+const TypeAryPtr* TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset,
                                    int instance_id, const TypePtr* speculative, int inline_depth) {
   assert(!(k == NULL && ary->_elem->isa_int()),
          "integral arrays must be pre-equipped with a class");
   if (!xk)  xk = ary->ary_must_be_exact();
   assert(instance_id <= 0 || xk, "instances are always exactly typed");
-  return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, instance_id, false, speculative, inline_depth))->hashcons();
+  return (TypeAryPtr*)(new TypeAryPtr(ptr, NULL, ary, k, xk, offset, field_offset, instance_id, false, speculative, inline_depth))->hashcons();
 }
 
 //------------------------------make-------------------------------------------
-const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset,
+const TypeAryPtr* TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, Offset offset, Offset field_offset,
                                    int instance_id, const TypePtr* speculative, int inline_depth,
                                    bool is_autobox_cache) {
   assert(!(k == NULL && ary->_elem->isa_int()),
          "integral arrays must be pre-equipped with a class");
   assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
   if (!xk)  xk = (o != NULL) || ary->ary_must_be_exact();
   assert(instance_id <= 0 || xk, "instances are always exactly typed");
-  return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
+  return (TypeAryPtr*)(new TypeAryPtr(ptr, o, ary, k, xk, offset, field_offset, instance_id, is_autobox_cache, speculative, inline_depth))->hashcons();
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
 const Type *TypeAryPtr::cast_to_ptr_type(PTR ptr) const {
   if( ptr == _ptr ) return this;
-  return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr, const_oop(), _ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
 }
 
 
 //-----------------------------cast_to_exactness-------------------------------
 const Type *TypeAryPtr::cast_to_exactness(bool klass_is_exact) const {
   if( klass_is_exact == _klass_is_exact ) return this;
   if (_ary->ary_must_be_exact())  return this;  // cannot clear xk
-  return make(ptr(), const_oop(), _ary, klass(), klass_is_exact, _offset, _instance_id, _speculative, _inline_depth);
+
+  const TypeAry* new_ary = _ary;
+  if (klass() != NULL && klass()->is_obj_array_klass() && klass_is_exact) {
+    // An object array can't be flat or null-free if the klass is exact
+    new_ary = TypeAry::make(elem(), size(), is_stable(), /* not_flat= */ true, /* not_null_free= */ true);
+  }
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact, _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
 }
 
 //-----------------------------cast_to_instance_id----------------------------
 const TypeOopPtr *TypeAryPtr::cast_to_instance_id(int instance_id) const {
   if( instance_id == _instance_id ) return this;
-  return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, const_oop(), _ary, klass(), _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth, _is_autobox_cache);
 }
 
 
 //-----------------------------max_array_length-------------------------------
 // A wrapper around arrayOopDesc::max_array_length(etype) with some input normalization.
@@ -4151,12 +4488,46 @@
 //-------------------------------cast_to_size----------------------------------
 const TypeAryPtr* TypeAryPtr::cast_to_size(const TypeInt* new_size) const {
   assert(new_size != NULL, "");
   new_size = narrow_size_type(new_size);
   if (new_size == size())  return this;
-  const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable());
-  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
+  const TypeAry* new_ary = TypeAry::make(elem(), new_size, is_stable(), is_not_flat(), is_not_null_free());
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+}
+
+//-------------------------------cast_to_not_flat------------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_not_flat(bool not_flat) const {
+  if (not_flat == is_not_flat()) {
+    return this;
+  }
+  const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), not_flat, is_not_null_free());
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+}
+
+//-------------------------------cast_to_not_null_free-------------------------
+const TypeAryPtr* TypeAryPtr::cast_to_not_null_free(bool not_null_free) const {
+  if (not_null_free == is_not_null_free()) {
+    return this;
+  }
+  // Not null free implies not flat
+  const TypeAry* new_ary = TypeAry::make(elem(), size(), is_stable(), not_null_free ? true : is_not_flat(), not_null_free);
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+}
+
+//---------------------------------update_properties---------------------------
+const TypeAryPtr* TypeAryPtr::update_properties(const TypeAryPtr* from) const {
+  if ((from->is_flat()          && is_not_flat()) ||
+      (from->is_not_flat()      && is_flat()) ||
+      (from->is_null_free()     && is_not_null_free()) ||
+      (from->is_not_null_free() && is_null_free())) {
+    return NULL; // Inconsistent properties
+  } else if (from->is_not_null_free()) {
+    return cast_to_not_null_free(); // Implies not flat
+  } else if (from->is_not_flat()) {
+    return cast_to_not_flat();
+  }
+  return this;
 }
 
 //------------------------------cast_to_stable---------------------------------
 const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension) const {
   if (stable_dimension <= 0 || (stable_dimension == 1 && stable == this->is_stable()))
@@ -4168,13 +4539,13 @@
   if (stable_dimension > 1 && elem_ptr != NULL && elem_ptr->isa_aryptr()) {
     // If this is widened from a narrow oop, TypeAry::make will re-narrow it.
     elem = elem_ptr = elem_ptr->is_aryptr()->cast_to_stable(stable, stable_dimension - 1);
   }
 
-  const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
+  const TypeAry* new_ary = TypeAry::make(elem, size(), stable, is_not_flat(), is_not_null_free());
 
-  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, _is_autobox_cache);
 }
 
 //-----------------------------stable_dimension--------------------------------
 int TypeAryPtr::stable_dimension() const {
   if (!is_stable())  return 0;
@@ -4191,27 +4562,28 @@
   const TypeOopPtr* etype = elem()->make_oopptr();
   if (etype == NULL)  return this;
   // The pointers in the autobox arrays are always non-null.
   TypePtr::PTR ptr_type = cache ? TypePtr::NotNull : TypePtr::AnyNull;
   etype = etype->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
-  const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable());
-  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth, cache);
+  const TypeAry* new_ary = TypeAry::make(etype, size(), is_stable(), is_not_flat(), is_not_null_free());
+  return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _field_offset, _instance_id, _speculative, _inline_depth, cache);
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeAryPtr::eq( const Type *t ) const {
   const TypeAryPtr *p = t->is_aryptr();
   return
     _ary == p->_ary &&  // Check array
-    TypeOopPtr::eq(p);  // Check sub-parts
+    TypeOopPtr::eq(p) &&// Check sub-parts
+    _field_offset == p->_field_offset;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeAryPtr::hash(void) const {
-  return (intptr_t)_ary + TypeOopPtr::hash();
+  return (intptr_t)_ary + TypeOopPtr::hash() + _field_offset.get();
 }
 
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
 const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
@@ -4240,20 +4612,20 @@
     typerr(t);
 
   case OopPtr: {                // Meeting to OopPtrs
     // Found a OopPtr type vs self-AryPtr type
     const TypeOopPtr *tp = t->is_oopptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     int depth = meet_inline_depth(tp->inline_depth());
     const TypePtr* speculative = xmeet_speculative(tp);
     switch (tp->ptr()) {
     case TopPTR:
     case AnyNull: {
       int instance_id = meet_instance_id(InstanceTop);
       return make(ptr, (ptr == Constant ? const_oop() : NULL),
-                  _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
+                  _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
     }
     case BotPTR:
     case NotNull: {
       int instance_id = meet_instance_id(tp->instance_id());
       return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
@@ -4263,11 +4635,11 @@
   }
 
   case AnyPtr: {                // Meeting two AnyPtrs
     // Found an AnyPtr type vs self-AryPtr type
     const TypePtr *tp = t->is_ptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
     switch (tp->ptr()) {
     case TopPTR:
@@ -4279,11 +4651,11 @@
       if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
       // else fall through to AnyNull
     case AnyNull: {
       int instance_id = meet_instance_id(InstanceTop);
       return make(ptr, (ptr == Constant ? const_oop() : NULL),
-                  _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
+                  _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
     }
     default: ShouldNotReachHere();
     }
   }
 
@@ -4291,11 +4663,12 @@
   case KlassPtr:
   case RawPtr: return TypePtr::BOTTOM;
 
   case AryPtr: {                // Meeting 2 references?
     const TypeAryPtr *tap = t->is_aryptr();
-    int off = meet_offset(tap->offset());
+    Offset off = meet_offset(tap->offset());
+    Offset field_off = meet_field_offset(tap->field_offset());
     const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary();
     PTR ptr = meet_ptr(tap->ptr());
     int instance_id = meet_instance_id(tap->instance_id());
     const TypePtr* speculative = xmeet_speculative(tap);
     int depth = meet_inline_depth(tap->inline_depth());
@@ -4309,28 +4682,39 @@
         lazy_klass = _klass;
       } else {
         // Something like byte[int+] meets char[int+].
         // This must fall to bottom, not (int[-128..65535])[int+].
         instance_id = InstanceBot;
-        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
+        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable, tary->_not_flat, tary->_not_null_free);
       }
     } else // Non integral arrays.
       // Must fall to bottom if exact klasses in upper lattice
       // are not equal or super klass is exact.
       if ((above_centerline(ptr) || ptr == Constant) && klass() != tap->klass() &&
           // meet with top[] and bottom[] are processed further down:
-          tap->_klass != NULL  && this->_klass != NULL   &&
+          tap->_klass != NULL && this->_klass != NULL &&
           // both are exact and not equal:
           ((tap->_klass_is_exact && this->_klass_is_exact) ||
-           // 'tap'  is exact and super or unrelated:
+           // 'tap' is exact and super or unrelated:
            (tap->_klass_is_exact && !tap->klass()->is_subtype_of(klass())) ||
            // 'this' is exact and super or unrelated:
            (this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
       if (above_centerline(ptr) || (tary->_elem->make_ptr() && above_centerline(tary->_elem->make_ptr()->_ptr))) {
-        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
+        tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable, tary->_not_flat, tary->_not_null_free);
+      }
+      return make(NotNull, NULL, tary, lazy_klass, false, off, field_off, InstanceBot, speculative, depth);
+    } else if (klass() != NULL && tap->klass() != NULL && klass()->is_flat_array_klass() != tap->klass()->is_flat_array_klass()) {
+      // Meeting flattened inline type array with non-flattened array. Adjust (field) offset accordingly.
+      if (tary->_elem->isa_inlinetype()) {
+        // Result is flattened
+        off = Offset(is_flat() ? offset() : tap->offset());
+        field_off = is_flat() ? field_offset() : tap->field_offset();
+      } else if (tary->_elem->make_oopptr() != NULL && tary->_elem->make_oopptr()->isa_instptr() && below_centerline(ptr)) {
+        // Result is non-flattened
+        off = Offset(flattened_offset()).meet(Offset(tap->flattened_offset()));
+        field_off = Offset::bottom;
       }
-      return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth);
     }
 
     bool xk = false;
     switch (tap->ptr()) {
     case AnyNull:
@@ -4339,11 +4723,11 @@
       if (below_centerline(this->_ptr)) {
         xk = this->_klass_is_exact;
       } else {
         xk = (tap->_klass_is_exact || this->_klass_is_exact);
       }
-      return make(ptr, const_oop(), tary, lazy_klass, xk, off, instance_id, speculative, depth);
+      return make(ptr, const_oop(), tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth);
     case Constant: {
       ciObject* o = const_oop();
       if( _ptr == Constant ) {
         if( tap->const_oop() != NULL && !o->equals(tap->const_oop()) ) {
           xk = (klass() == tap->klass());
@@ -4358,45 +4742,45 @@
         xk = true;
       } else {
         // Only precise for identical arrays
         xk = this->_klass_is_exact && (klass() == tap->klass());
       }
-      return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, instance_id, speculative, depth);
+      return TypeAryPtr::make(ptr, o, tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth);
     }
     case NotNull:
     case BotPTR:
       // Compute new klass on demand, do not use tap->_klass
       if (above_centerline(this->_ptr))
             xk = tap->_klass_is_exact;
       else  xk = (tap->_klass_is_exact & this->_klass_is_exact) &&
               (klass() == tap->klass()); // Only precise for identical arrays
-      return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, instance_id, speculative, depth);
+      return TypeAryPtr::make(ptr, NULL, tary, lazy_klass, xk, off, field_off, instance_id, speculative, depth);
     default: ShouldNotReachHere();
     }
   }
 
   // All arrays inherit from Object class
   case InstPtr: {
     const TypeInstPtr *tp = t->is_instptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     int instance_id = meet_instance_id(tp->instance_id());
     const TypePtr* speculative = xmeet_speculative(tp);
     int depth = meet_inline_depth(tp->inline_depth());
     switch (ptr) {
     case TopPTR:
     case AnyNull:                // Fall 'down' to dual of object klass
       // For instances when a subclass meets a superclass we fall
       // below the centerline when the superclass is exact. We need to
       // do the same here.
-      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
-        return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
+      if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact() && !tp->flatten_array()) {
+        return TypeAryPtr::make(ptr, _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
       } else {
         // cannot subclass, so the meet has to fall badly below the centerline
         ptr = NotNull;
         instance_id = InstanceBot;
-        return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth);
+        return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, false, instance_id, speculative, depth);
       }
     case Constant:
     case NotNull:
     case BotPTR:                // Fall down to object klass
       // LCA is object_klass, but if we subclass from the top we can do better
@@ -4404,33 +4788,55 @@
         // If 'tp'  is above the centerline and it is Object class
         // then we can subclass in the Java class hierarchy.
         // For instances when a subclass meets a superclass we fall
         // below the centerline when the superclass is exact. We need
         // to do the same here.
-        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact()) {
+        if (tp->klass()->equals(ciEnv::current()->Object_klass()) && !tp->klass_is_exact() && !tp->flatten_array()) {
           // that is, my array type is a subtype of 'tp' klass
           return make(ptr, (ptr == Constant ? const_oop() : NULL),
-                      _ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
+                      _ary, _klass, _klass_is_exact, offset, _field_offset, instance_id, speculative, depth);
         }
       }
       // The other case cannot happen, since t cannot be a subtype of an array.
       // The meet falls down to Object class below centerline.
       if( ptr == Constant )
          ptr = NotNull;
       instance_id = InstanceBot;
-      return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL,offset, instance_id, speculative, depth);
+      return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, false, instance_id, speculative, depth);
     default: typerr(t);
     }
   }
+
+  case InlineType: {
+    const TypeInlineType* tv = t->is_inlinetype();
+    if (above_centerline(ptr())) {
+      return TypeInstPtr::NOTNULL;
+    } else {
+      PTR ptr = this->_ptr;
+      if (ptr == Constant) {
+        ptr = NotNull;
+      }
+      return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass());
+    }
+  }
   }
   return this;                  // Lint noise
 }
 
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const Type *TypeAryPtr::xdual() const {
-  return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(),_klass, _klass_is_exact, dual_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
+  return new TypeAryPtr(dual_ptr(), _const_oop, _ary->dual()->is_ary(), _klass, _klass_is_exact, dual_offset(), dual_field_offset(), dual_instance_id(), is_autobox_cache(), dual_speculative(), dual_inline_depth());
+}
+
+Type::Offset TypeAryPtr::meet_field_offset(const Type::Offset offset) const {
+  return _field_offset.meet(offset);
+}
+
+//------------------------------dual_offset------------------------------------
+Type::Offset TypeAryPtr::dual_field_offset() const {
+  return _field_offset.dual();
 }
 
 //----------------------interface_vs_oop---------------------------------------
 #ifdef ASSERT
 bool TypeAryPtr::interface_vs_oop(const Type *t) const {
@@ -4463,20 +4869,25 @@
     break;
   default:
     break;
   }
 
-  if( _offset != 0 ) {
+  if (is_flat()) {
+    st->print("(");
+    _field_offset.dump2(st);
+    st->print(")");
+  }
+  if (offset() != 0) {
     int header_size = objArrayOopDesc::header_size() * wordSize;
-    if( _offset == OffsetTop )       st->print("+undefined");
-    else if( _offset == OffsetBot )  st->print("+any");
-    else if( _offset < header_size ) st->print("+%d", _offset);
+    if( _offset == Offset::top )       st->print("+undefined");
+    else if( _offset == Offset::bottom )  st->print("+any");
+    else if( offset() < header_size ) st->print("+%d", offset());
     else {
       BasicType basic_elem_type = elem()->basic_type();
       int array_base = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
       int elem_size = type2aelembytes(basic_elem_type);
-      st->print("[%d]", (_offset - array_base)/elem_size);
+      st->print("[%d]", (offset() - array_base)/elem_size);
     }
   }
   st->print(" *");
   if (_instance_id == InstanceTop)
     st->print(",iid=top");
@@ -4493,35 +4904,99 @@
   return TypeOopPtr::empty();
 }
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypeAryPtr::add_offset(intptr_t offset) const {
-  return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _instance_id, add_offset_speculative(offset), _inline_depth);
+  return make(_ptr, _const_oop, _ary, _klass, _klass_is_exact, xadd_offset(offset), _field_offset, _instance_id, add_offset_speculative(offset), _inline_depth, _is_autobox_cache);
 }
 
 const Type *TypeAryPtr::remove_speculative() const {
   if (_speculative == NULL) {
     return this;
   }
   assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
-  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth);
+  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, NULL, _inline_depth, _is_autobox_cache);
+}
+
+const Type* TypeAryPtr::cleanup_speculative() const {
+  if (speculative() == NULL) {
+    return this;
+  }
+  // Keep speculative part if it contains information about flat-/nullability
+  const TypeAryPtr* spec_aryptr = speculative()->isa_aryptr();
+  if (spec_aryptr != NULL && (spec_aryptr->is_not_flat() || spec_aryptr->is_not_null_free())) {
+    return this;
+  }
+  return TypeOopPtr::cleanup_speculative();
 }
 
 const TypePtr *TypeAryPtr::with_inline_depth(int depth) const {
   if (!UseInlineDepthForSpeculativeTypes) {
     return this;
   }
-  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, _speculative, depth);
+  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, _instance_id, _speculative, depth, _is_autobox_cache);
+}
+
+const TypeAryPtr* TypeAryPtr::with_field_offset(int offset) const {
+  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, Offset(offset), _instance_id, _speculative, _inline_depth, _is_autobox_cache);
+}
+
+const TypePtr* TypeAryPtr::add_field_offset_and_offset(intptr_t offset) const {
+  int adj = 0;
+  if (offset != Type::OffsetBot && offset != Type::OffsetTop) {
+    const Type* elemtype = elem();
+    if (elemtype->isa_inlinetype()) {
+      if (_offset.get() != OffsetBot && _offset.get() != OffsetTop) {
+        adj = _offset.get();
+        offset += _offset.get();
+      }
+      uint header = arrayOopDesc::base_offset_in_bytes(T_OBJECT);
+      if (_field_offset.get() != OffsetBot && _field_offset.get() != OffsetTop) {
+        offset += _field_offset.get();
+        if (_offset.get() == OffsetBot || _offset.get() == OffsetTop) {
+          offset += header;
+        }
+      }
+      if (offset >= (intptr_t)header || offset < 0) {
+        // Try to get the field of the inline type array element we are pointing to
+        ciKlass* arytype_klass = klass();
+        ciFlatArrayKlass* vak = arytype_klass->as_flat_array_klass();
+        ciInlineKlass* vk = vak->element_klass()->as_inline_klass();
+        int shift = vak->log2_element_size();
+        int mask = (1 << shift) - 1;
+        intptr_t field_offset = ((offset - header) & mask);
+        ciField* field = vk->get_field_by_offset(field_offset + vk->first_field_offset(), false);
+        if (field == NULL) {
+          // This may happen with nested AddP(base, AddP(base, base, offset), longcon(16))
+          return add_offset(offset);
+        } else {
+          return with_field_offset(field_offset)->add_offset(offset - field_offset - adj);
+        }
+      }
+    }
+  }
+  return add_offset(offset - adj);
+}
+
+// Return offset incremented by field_offset for flattened inline type arrays
+const int TypeAryPtr::flattened_offset() const {
+  int offset = _offset.get();
+  if (offset != Type::OffsetBot && offset != Type::OffsetTop &&
+      _field_offset != Offset::bottom && _field_offset != Offset::top) {
+    offset += _field_offset.get();
+  }
+  return offset;
 }
 
 const TypePtr *TypeAryPtr::with_instance_id(int instance_id) const {
   assert(is_known_instance(), "should be known");
-  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, instance_id, _speculative, _inline_depth);
+  return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _field_offset, instance_id, _speculative, _inline_depth);
 }
 
 //=============================================================================
 
+
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeNarrowPtr::hash(void) const {
   return _ptrtype->hash() + 7;
 }
@@ -4606,16 +5081,18 @@
   case AryPtr:
   case MetadataPtr:
   case KlassPtr:
   case NarrowOop:
   case NarrowKlass:
-
   case Bottom:                  // Ye Olde Default
     return Type::BOTTOM;
   case Top:
     return this;
 
+  case InlineType:
+    return t->xmeet(this);
+
   default:                      // All else is a mistake
     typerr(t);
 
   } // End of switch
 
@@ -4690,11 +5167,11 @@
 // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
 // constants
 bool TypeMetadataPtr::singleton(void) const {
   // detune optimizer to not generate constant metadata + constant offset as a constant!
   // TopPTR, Null, AnyNull, Constant are all singletons
-  return (_offset == 0) && !below_centerline(_ptr);
+  return (offset() == 0) && !below_centerline(_ptr);
 }
 
 //------------------------------add_offset-------------------------------------
 const TypePtr *TypeMetadataPtr::add_offset( intptr_t offset ) const {
   return make( _ptr, _metadata, xadd_offset(offset));
@@ -4710,13 +5187,13 @@
 }
 
  //------------------------------get_con----------------------------------------
 intptr_t TypeMetadataPtr::get_con() const {
   assert( _ptr == Null || _ptr == Constant, "" );
-  assert( _offset >= 0, "" );
+  assert(offset() >= 0, "");
 
-  if (_offset != 0) {
+  if (offset() != 0) {
     // After being ported to the compiler interface, the compiler no longer
     // directly manipulates the addresses of oops.  Rather, it only has a pointer
     // to a handle at compile time.  This handle is embedded in the generated
     // code and dereferenced at the time the nmethod is made.  Until that time,
     // it is not reasonable to do arithmetic with the addresses of oops (we don't
@@ -4763,11 +5240,11 @@
     typerr(t);
 
   case AnyPtr: {
     // Found an AnyPtr type vs self-OopPtr type
     const TypePtr *tp = t->is_ptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     switch (tp->ptr()) {
     case Null:
       if (ptr == Null)  return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
       // else fall through:
@@ -4789,11 +5266,11 @@
   case AryPtr:
     return TypePtr::BOTTOM;     // Oop meet raw is not well defined
 
   case MetadataPtr: {
     const TypeMetadataPtr *tp = t->is_metadataptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR tptr = tp->ptr();
     PTR ptr = meet_ptr(tptr);
     ciMetadata* md = (tptr == TopPTR) ? metadata() : tp->metadata();
     if (tptr == TopPTR || _ptr == TopPTR ||
         metadata()->equals(tp->metadata())) {
@@ -4822,38 +5299,38 @@
 //------------------------------dump2------------------------------------------
 #ifndef PRODUCT
 void TypeMetadataPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
   st->print("metadataptr:%s", ptr_msg[_ptr]);
   if( metadata() ) st->print(INTPTR_FORMAT, p2i(metadata()));
-  switch( _offset ) {
+  switch (offset()) {
   case OffsetTop: st->print("+top"); break;
   case OffsetBot: st->print("+any"); break;
   case         0: break;
-  default:        st->print("+%d",_offset); break;
+  default:        st->print("+%d",offset()); break;
   }
 }
 #endif
 
 
 //=============================================================================
 // Convenience common pre-built type.
 const TypeMetadataPtr *TypeMetadataPtr::BOTTOM;
 
-TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, int offset):
+TypeMetadataPtr::TypeMetadataPtr(PTR ptr, ciMetadata* metadata, Offset offset):
   TypePtr(MetadataPtr, ptr, offset), _metadata(metadata) {
 }
 
 const TypeMetadataPtr* TypeMetadataPtr::make(ciMethod* m) {
-  return make(Constant, m, 0);
+  return make(Constant, m, Offset(0));
 }
 const TypeMetadataPtr* TypeMetadataPtr::make(ciMethodData* m) {
-  return make(Constant, m, 0);
+  return make(Constant, m, Offset(0));
 }
 
 //------------------------------make-------------------------------------------
 // Create a meta data constant
-const TypeMetadataPtr *TypeMetadataPtr::make(PTR ptr, ciMetadata* m, int offset) {
+const TypeMetadataPtr* TypeMetadataPtr::make(PTR ptr, ciMetadata* m, Offset offset) {
   assert(m == NULL || !m->is_klass(), "wrong type");
   return (TypeMetadataPtr*)(new TypeMetadataPtr(ptr, m, offset))->hashcons();
 }
 
 
@@ -4863,47 +5340,45 @@
 // Not-null object klass or below
 const TypeKlassPtr *TypeKlassPtr::OBJECT;
 const TypeKlassPtr *TypeKlassPtr::OBJECT_OR_NULL;
 
 //------------------------------TypeKlassPtr-----------------------------------
-TypeKlassPtr::TypeKlassPtr( PTR ptr, ciKlass* klass, int offset )
-  : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant) {
+TypeKlassPtr::TypeKlassPtr(PTR ptr, ciKlass* klass, Offset offset, bool flatten_array)
+  : TypePtr(KlassPtr, ptr, offset), _klass(klass), _klass_is_exact(ptr == Constant), _flatten_array(flatten_array) {
+  assert(!klass->flatten_array() || flatten_array, "Should be flat in array");
+  assert(!flatten_array || can_be_inline_type(), "Only inline types can be flat in array");
 }
 
 //------------------------------make-------------------------------------------
 // ptr to klass 'k', if Constant, or possibly to a sub-klass if not a Constant
-const TypeKlassPtr *TypeKlassPtr::make( PTR ptr, ciKlass* k, int offset ) {
-  assert( k != NULL, "Expect a non-NULL klass");
-  assert(k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop");
-  TypeKlassPtr *r =
-    (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset))->hashcons();
-
-  return r;
+const TypeKlassPtr* TypeKlassPtr::make(PTR ptr, ciKlass* k, Offset offset, bool flatten_array) {
+  assert(k == NULL || k->is_instance_klass() || k->is_array_klass(), "Incorrect type of klass oop");
+  // Check if this type is known to be flat in arrays
+  flatten_array = flatten_array || k->flatten_array();
+  return (TypeKlassPtr*)(new TypeKlassPtr(ptr, k, offset, flatten_array))->hashcons();
 }
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeKlassPtr::eq( const Type *t ) const {
   const TypeKlassPtr *p = t->is_klassptr();
-  return
-    klass()->equals(p->klass()) &&
-    TypePtr::eq(p);
+  return klass() == p->klass() && TypePtr::eq(p) && flatten_array() == p->flatten_array();
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeKlassPtr::hash(void) const {
-  return java_add((jint)klass()->hash(), (jint)TypePtr::hash());
+  return java_add(java_add(klass() != NULL ? klass()->hash() : (jint)0, (jint)TypePtr::hash()), (jint)flatten_array());
 }
 
 //------------------------------singleton--------------------------------------
 // TRUE if Type is a singleton type, FALSE otherwise.   Singletons are simple
 // constants
 bool TypeKlassPtr::singleton(void) const {
   // detune optimizer to not generate constant klass + constant offset as a constant!
   // TopPTR, Null, AnyNull, Constant are all singletons
-  return (_offset == 0) && !below_centerline(_ptr);
+  return (offset() == 0) && !below_centerline(_ptr);
 }
 
 // Do not allow interface-vs.-noninterface joins to collapse to top.
 const Type *TypeKlassPtr::filter_helper(const Type *kills, bool include_speculative) const {
   // logic here mirrors the one from TypeOopPtr::filter. See comments
@@ -4911,11 +5386,11 @@
   const Type* ft = join_helper(kills, include_speculative);
   const TypeKlassPtr* ftkp = ft->isa_klassptr();
   const TypeKlassPtr* ktkp = kills->isa_klassptr();
 
   if (ft->empty()) {
-    if (!empty() && ktkp != NULL && ktkp->klass()->is_loaded() && ktkp->klass()->is_interface())
+    if (!empty() && ktkp != NULL && ktkp->is_loaded() && ktkp->klass()->is_interface())
       return kills;             // Uplift to interface
 
     return Type::TOP;           // Canonical empty value
   }
 
@@ -4934,21 +5409,25 @@
 //----------------------compute_klass------------------------------------------
 // Compute the defining klass for this class
 ciKlass* TypeAryPtr::compute_klass(DEBUG_ONLY(bool verify)) const {
   // Compute _klass based on element type.
   ciKlass* k_ary = NULL;
-  const TypeInstPtr *tinst;
   const TypeAryPtr *tary;
   const Type* el = elem();
   if (el->isa_narrowoop()) {
     el = el->make_ptr();
   }
 
   // Get element klass
-  if ((tinst = el->isa_instptr()) != NULL) {
-    // Compute array klass from element klass
-    k_ary = ciObjArrayKlass::make(tinst->klass());
+  if (el->isa_instptr()) {
+    // Compute object array klass from element klass
+    k_ary = ciArrayKlass::make(el->is_oopptr()->klass());
+  } else if (el->isa_inlinetype()) {
+    // If element type is TypeInlineType::BOTTOM, inline_klass() will be null.
+    if (el->inline_klass() != NULL) {
+      k_ary = ciArrayKlass::make(el->inline_klass());
+    }
   } else if ((tary = el->isa_aryptr()) != NULL) {
     // Compute array klass from element klass
     ciKlass* k_elem = tary->klass();
     // If element type is something like bottom[], k_elem will be null.
     if (k_elem != NULL)
@@ -5009,49 +5488,53 @@
     // Recomputing the underlying ciKlass for each request is
     // a bit less efficient than caching, but calls to
     // TypeAryPtr::OOPS->klass() are not common enough to matter.
     ((TypeAryPtr*)this)->_klass = k_ary;
     if (UseCompressedOops && k_ary != NULL && k_ary->is_obj_array_klass() &&
-        _offset != 0 && _offset != arrayOopDesc::length_offset_in_bytes()) {
+        offset() != 0 && offset() != arrayOopDesc::length_offset_in_bytes()) {
       ((TypeAryPtr*)this)->_is_ptr_to_narrowoop = true;
     }
   }
   return k_ary;
 }
 
 
 //------------------------------add_offset-------------------------------------
 // Access internals of klass object
 const TypePtr *TypeKlassPtr::add_offset( intptr_t offset ) const {
-  return make( _ptr, klass(), xadd_offset(offset) );
+  return make(_ptr, klass(), xadd_offset(offset), flatten_array());
 }
 
 //------------------------------cast_to_ptr_type-------------------------------
 const Type *TypeKlassPtr::cast_to_ptr_type(PTR ptr) const {
   assert(_base == KlassPtr, "subclass must override cast_to_ptr_type");
   if( ptr == _ptr ) return this;
-  return make(ptr, _klass, _offset);
+  return make(ptr, _klass, _offset, _flatten_array);
 }
 
 
 //-----------------------------cast_to_exactness-------------------------------
 const Type *TypeKlassPtr::cast_to_exactness(bool klass_is_exact) const {
   if( klass_is_exact == _klass_is_exact ) return this;
-  return make(klass_is_exact ? Constant : NotNull, _klass, _offset);
+  return make(klass_is_exact ? Constant : NotNull, _klass, _offset, _flatten_array);
 }
 
 
 //-----------------------------as_instance_type--------------------------------
 // Corresponding type for an instance of the given class.
 // It will be NotNull, and exact if and only if the klass type is exact.
 const TypeOopPtr* TypeKlassPtr::as_instance_type() const {
   ciKlass* k = klass();
+  assert(k != NULL, "klass should not be NULL");
   bool    xk = klass_is_exact();
   //return TypeInstPtr::make(TypePtr::NotNull, k, xk, NULL, 0);
   const TypeOopPtr* toop = TypeOopPtr::make_from_klass_raw(k);
   guarantee(toop != NULL, "need type for given klass");
   toop = toop->cast_to_ptr_type(TypePtr::NotNull)->is_oopptr();
+  if (flatten_array() && !klass()->is_inlinetype()) {
+    toop = toop->is_instptr()->cast_to_flatten_array();
+  }
   return toop->cast_to_exactness(xk)->is_oopptr();
 }
 
 
 //------------------------------xmeet------------------------------------------
@@ -5082,19 +5565,19 @@
     typerr(t);
 
   case AnyPtr: {                // Meeting to AnyPtrs
     // Found an AnyPtr type vs self-KlassPtr type
     const TypePtr *tp = t->is_ptr();
-    int offset = meet_offset(tp->offset());
+    Offset offset = meet_offset(tp->offset());
     PTR ptr = meet_ptr(tp->ptr());
     switch (tp->ptr()) {
     case TopPTR:
       return this;
     case Null:
       if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
     case AnyNull:
-      return make( ptr, klass(), offset );
+      return make(ptr, klass(), offset, flatten_array());
     case BotPTR:
     case NotNull:
       return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
     default: typerr(t);
     }
@@ -5123,26 +5606,37 @@
   //             A-bot         }
   //
 
   case KlassPtr: {  // Meet two KlassPtr types
     const TypeKlassPtr *tkls = t->is_klassptr();
-    int  off     = meet_offset(tkls->offset());
+    Offset  off  = meet_offset(tkls->offset());
     PTR  ptr     = meet_ptr(tkls->ptr());
 
+    if (klass() == NULL || tkls->klass() == NULL) {
+      ciKlass* k = NULL;
+      if (ptr == Constant) {
+        k = (klass() == NULL) ? tkls->klass() : klass();
+      }
+      return make(ptr, k, off);
+    }
+
     // Check for easy case; klasses are equal (and perhaps not loaded!)
     // If we have constants, then we created oops so classes are loaded
     // and we can handle the constants further down.  This case handles
     // not-loaded classes
-    if( ptr != Constant && tkls->klass()->equals(klass()) ) {
-      return make( ptr, klass(), off );
+    if (ptr != Constant && tkls->klass()->equals(klass()) && flatten_array() == tkls->flatten_array()) {
+      return make(ptr, klass(), off, flatten_array());
     }
 
     // Classes require inspection in the Java klass hierarchy.  Must be loaded.
     ciKlass* tkls_klass = tkls->klass();
     ciKlass* this_klass = this->klass();
     assert( tkls_klass->is_loaded(), "This class should have been loaded.");
     assert( this_klass->is_loaded(), "This class should have been loaded.");
+    bool tkls_flatten_array = tkls->flatten_array();
+    bool this_flatten_array  = this->flatten_array();
+    bool flatten_array = below_centerline(ptr) ? (this_flatten_array && tkls_flatten_array) : (this_flatten_array || tkls_flatten_array);
 
     // If 'this' type is above the centerline and is a superclass of the
     // other, we can treat 'this' as having the same type as the other.
     if ((above_centerline(this->ptr())) &&
         tkls_klass->is_subtype_of(this_klass)) {
@@ -5166,38 +5660,38 @@
         else if (above_centerline(this->ptr()));
         else if (above_centerline(tkls->ptr()));
         else
           ptr = NotNull;
       }
-      return make( ptr, this_klass, off );
+      return make(ptr, this_klass, off, flatten_array);
     } // Else classes are not equal
 
     // Since klasses are different, we require the LCA in the Java
     // class hierarchy - which means we have to fall to at least NotNull.
     if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
       ptr = NotNull;
     // Now we find the LCA of Java classes
     ciKlass* k = this_klass->least_common_ancestor(tkls_klass);
-    return   make( ptr, k, off );
+    return   make(ptr, k, off);
   } // End of case KlassPtr
 
   } // End of switch
   return this;                  // Return the double constant
 }
 
 //------------------------------xdual------------------------------------------
 // Dual: compute field-by-field dual
 const Type    *TypeKlassPtr::xdual() const {
-  return new TypeKlassPtr( dual_ptr(), klass(), dual_offset() );
+  return new TypeKlassPtr(dual_ptr(), klass(), dual_offset(), flatten_array());
 }
 
 //------------------------------get_con----------------------------------------
 intptr_t TypeKlassPtr::get_con() const {
   assert( _ptr == Null || _ptr == Constant, "" );
-  assert( _offset >= 0, "" );
+  assert(offset() >= 0, "");
 
-  if (_offset != 0) {
+  if (offset() != 0) {
     // After being ported to the compiler interface, the compiler no longer
     // directly manipulates the addresses of oops.  Rather, it only has a pointer
     // to a handle at compile time.  This handle is embedded in the generated
     // code and dereferenced at the time the nmethod is made.  Until that time,
     // it is not reasonable to do arithmetic with the addresses of oops (we don't
@@ -5216,15 +5710,15 @@
   switch( _ptr ) {
   case Constant:
     st->print("precise ");
   case NotNull:
     {
-      const char *name = klass()->name()->as_utf8();
-      if( name ) {
+      if (klass() != NULL) {
+        const char* name = klass()->name()->as_utf8();
         st->print("klass %s: " INTPTR_FORMAT, name, p2i(klass()));
       } else {
-        ShouldNotReachHere();
+        st->print("klass BOTTOM");
       }
     }
   case BotPTR:
     if( !WizardMode && !Verbose && !_klass_is_exact ) break;
   case TopPTR:
@@ -5234,15 +5728,11 @@
     break;
   default:
     break;
   }
 
-  if( _offset ) {               // Dump offset, if any
-    if( _offset == OffsetBot )      { st->print("+any"); }
-    else if( _offset == OffsetTop ) { st->print("+unknown"); }
-    else                            { st->print("+%d", _offset); }
-  }
+  _offset.dump2(st);
 
   st->print(" *");
 }
 #endif
 
@@ -5250,28 +5740,50 @@
 
 //=============================================================================
 // Convenience common pre-built types.
 
 //------------------------------make-------------------------------------------
-const TypeFunc *TypeFunc::make( const TypeTuple *domain, const TypeTuple *range ) {
-  return (TypeFunc*)(new TypeFunc(domain,range))->hashcons();
+const TypeFunc *TypeFunc::make(const TypeTuple *domain_sig, const TypeTuple* domain_cc,
+                               const TypeTuple *range_sig, const TypeTuple *range_cc) {
+  return (TypeFunc*)(new TypeFunc(domain_sig, domain_cc, range_sig, range_cc))->hashcons();
+}
+
+const TypeFunc *TypeFunc::make(const TypeTuple *domain, const TypeTuple *range) {
+  return make(domain, domain, range, range);
+}
+
+//------------------------------osr_domain-----------------------------
+const TypeTuple* osr_domain() {
+  const Type **fields = TypeTuple::fields(2);
+  fields[TypeFunc::Parms+0] = TypeRawPtr::BOTTOM;  // address of osr buffer
+  return TypeTuple::make(TypeFunc::Parms+1, fields);
 }
 
 //------------------------------make-------------------------------------------
-const TypeFunc *TypeFunc::make(ciMethod* method) {
+const TypeFunc* TypeFunc::make(ciMethod* method, bool is_osr_compilation) {
   Compile* C = Compile::current();
-  const TypeFunc* tf = C->last_tf(method); // check cache
-  if (tf != NULL)  return tf;  // The hit rate here is almost 50%.
-  const TypeTuple *domain;
-  if (method->is_static()) {
-    domain = TypeTuple::make_domain(NULL, method->signature());
-  } else {
-    domain = TypeTuple::make_domain(method->holder(), method->signature());
+  const TypeFunc* tf = NULL;
+  if (!is_osr_compilation) {
+    tf = C->last_tf(method); // check cache
+    if (tf != NULL)  return tf;  // The hit rate here is almost 50%.
+  }
+  // Inline types are not passed/returned by reference, instead each field of
+  // the inline type is passed/returned as an argument. We maintain two views of
+  // the argument/return list here: one based on the signature (with an inline
+  // type argument/return as a single slot), one based on the actual calling
+  // convention (with an inline type argument/return as a list of its fields).
+  bool has_scalar_args = method->has_scalarized_args() && !is_osr_compilation;
+  const TypeTuple* domain_sig = is_osr_compilation ? osr_domain() : TypeTuple::make_domain(method, false);
+  const TypeTuple* domain_cc = has_scalar_args ? TypeTuple::make_domain(method, true) : domain_sig;
+  ciSignature* sig = method->signature();
+  bool has_scalar_ret = sig->return_type()->is_inlinetype() && sig->return_type()->as_inline_klass()->can_be_returned_as_fields();
+  const TypeTuple* range_sig = TypeTuple::make_range(sig, false);
+  const TypeTuple* range_cc = has_scalar_ret ? TypeTuple::make_range(sig, true) : range_sig;
+  tf = TypeFunc::make(domain_sig, domain_cc, range_sig, range_cc);
+  if (!is_osr_compilation) {
+    C->set_last_tf(method, tf);  // fill cache
   }
-  const TypeTuple *range  = TypeTuple::make_range(method->signature());
-  tf = TypeFunc::make(domain, range);
-  C->set_last_tf(method, tf);  // fill cache
   return tf;
 }
 
 //------------------------------meet-------------------------------------------
 // Compute the MEET of two types.  It returns a new Type object.
@@ -5302,46 +5814,48 @@
 
 //------------------------------eq---------------------------------------------
 // Structural equality check for Type representations
 bool TypeFunc::eq( const Type *t ) const {
   const TypeFunc *a = (const TypeFunc*)t;
-  return _domain == a->_domain &&
-    _range == a->_range;
+  return _domain_sig == a->_domain_sig &&
+    _domain_cc == a->_domain_cc &&
+    _range_sig == a->_range_sig &&
+    _range_cc == a->_range_cc;
 }
 
 //------------------------------hash-------------------------------------------
 // Type-specific hashing function.
 int TypeFunc::hash(void) const {
-  return (intptr_t)_domain + (intptr_t)_range;
+  return (intptr_t)_domain_sig + (intptr_t)_domain_cc + (intptr_t)_range_sig + (intptr_t)_range_cc;
 }
 
 //------------------------------dump2------------------------------------------
 // Dump Function Type
 #ifndef PRODUCT
 void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
-  if( _range->cnt() <= Parms )
+  if( _range_sig->cnt() <= Parms )
     st->print("void");
   else {
     uint i;
-    for (i = Parms; i < _range->cnt()-1; i++) {
-      _range->field_at(i)->dump2(d,depth,st);
+    for (i = Parms; i < _range_sig->cnt()-1; i++) {
+      _range_sig->field_at(i)->dump2(d,depth,st);
       st->print("/");
     }
-    _range->field_at(i)->dump2(d,depth,st);
+    _range_sig->field_at(i)->dump2(d,depth,st);
   }
   st->print(" ");
   st->print("( ");
   if( !depth || d[this] ) {     // Check for recursive dump
     st->print("...)");
     return;
   }
   d.Insert((void*)this,(void*)this);    // Stop recursion
-  if (Parms < _domain->cnt())
-    _domain->field_at(Parms)->dump2(d,depth-1,st);
-  for (uint i = Parms+1; i < _domain->cnt(); i++) {
+  if (Parms < _domain_sig->cnt())
+    _domain_sig->field_at(Parms)->dump2(d,depth-1,st);
+  for (uint i = Parms+1; i < _domain_sig->cnt(); i++) {
     st->print(", ");
-    _domain->field_at(i)->dump2(d,depth-1,st);
+    _domain_sig->field_at(i)->dump2(d,depth-1,st);
   }
   st->print(" )");
 }
 #endif
 
@@ -5357,10 +5871,10 @@
   return false;                 // Never empty
 }
 
 
 BasicType TypeFunc::return_type() const{
-  if (range()->cnt() == TypeFunc::Parms) {
+  if (range_sig()->cnt() == TypeFunc::Parms) {
     return T_VOID;
   }
-  return range()->field_at(TypeFunc::Parms)->basic_type();
+  return range_sig()->field_at(TypeFunc::Parms)->basic_type();
 }
diff a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
--- a/src/hotspot/share/prims/jvm.cpp
+++ b/src/hotspot/share/prims/jvm.cpp
@@ -49,10 +49,11 @@
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "oops/access.inline.hpp"
 #include "oops/constantPool.hpp"
 #include "oops/fieldStreams.inline.hpp"
+#include "oops/flatArrayKlass.hpp"
 #include "oops/instanceKlass.hpp"
 #include "oops/method.hpp"
 #include "oops/recordComponent.hpp"
 #include "oops/objArrayKlass.hpp"
 #include "oops/objArrayOop.inline.hpp"
@@ -652,11 +653,32 @@
 
 
 JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
   JVMWrapper("JVM_IHashCode");
   // as implemented in the classic virtual machine; return 0 if object is NULL
-  return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
+  if (handle == NULL) {
+    return 0;
+  }
+  oop obj = JNIHandles::resolve_non_null(handle);
+  if (EnableValhalla && obj->klass()->is_inline_klass()) {
+      JavaValue result(T_INT);
+      JavaCallArguments args;
+      Handle ho(THREAD, obj);
+      args.push_oop(ho);
+      methodHandle method(THREAD, Universe::inline_type_hash_code_method());
+      JavaCalls::call(&result, method, &args, THREAD);
+      if (HAS_PENDING_EXCEPTION) {
+        if (!PENDING_EXCEPTION->is_a(SystemDictionary::Error_klass())) {
+          Handle e(THREAD, PENDING_EXCEPTION);
+          CLEAR_PENDING_EXCEPTION;
+          THROW_MSG_CAUSE_(vmSymbols::java_lang_InternalError(), "Internal error in hashCode", e, false);
+        }
+      }
+      return result.get_jint();
+  } else {
+    return ObjectSynchronizer::FastHashCode(THREAD, obj);
+  }
 JVM_END
 
 
 JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
   JVMWrapper("JVM_MonitorWait");
@@ -708,10 +730,11 @@
 
   // Check if class of obj supports the Cloneable interface.
   // All arrays are considered to be cloneable (See JLS 20.1.5).
   // All j.l.r.Reference classes are considered non-cloneable.
   if (!klass->is_cloneable() ||
+       klass->is_inline_klass() ||
       (klass->is_instance_klass() &&
        InstanceKlass::cast(klass)->reference_type() != REF_NONE)) {
     ResourceMark rm(THREAD);
     THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(), klass->external_name());
   }
@@ -1251,30 +1274,39 @@
 
   Klass* klass = java_lang_Class::as_Klass(mirror);
   // Figure size of result array
   int size;
   if (klass->is_instance_klass()) {
-    size = InstanceKlass::cast(klass)->local_interfaces()->length();
+    InstanceKlass* ik = InstanceKlass::cast(klass);
+    size = ik->local_interfaces()->length();
+    if (ik->has_injected_identityObject()) {
+      size--;
+    }
   } else {
     assert(klass->is_objArray_klass() || klass->is_typeArray_klass(), "Illegal mirror klass");
-    size = 2;
+    size = 3;
   }
 
   // Allocate result array
   objArrayOop r = oopFactory::new_objArray(SystemDictionary::Class_klass(), size, CHECK_NULL);
   objArrayHandle result (THREAD, r);
   // Fill in result
   if (klass->is_instance_klass()) {
     // Regular instance klass, fill in all local interfaces
+    int cursor = 0;
     for (int index = 0; index < size; index++) {
-      Klass* k = InstanceKlass::cast(klass)->local_interfaces()->at(index);
-      result->obj_at_put(index, k->java_mirror());
+      InstanceKlass* ik = InstanceKlass::cast(klass);
+      Klass* k = ik->local_interfaces()->at(index);
+      if (!ik->has_injected_identityObject() || k != SystemDictionary::IdentityObject_klass()) {
+        result->obj_at_put(cursor++, k->java_mirror());
+      }
     }
   } else {
-    // All arrays implement java.lang.Cloneable and java.io.Serializable
+    // All arrays implement java.lang.Cloneable, java.io.Serializable and java.lang.IdentityObject
     result->obj_at_put(0, SystemDictionary::Cloneable_klass()->java_mirror());
     result->obj_at_put(1, SystemDictionary::Serializable_klass()->java_mirror());
+    result->obj_at_put(2, SystemDictionary::IdentityObject_klass()->java_mirror());
   }
   return (jobjectArray) JNIHandles::make_local(env, result());
 JVM_END
 
 
@@ -1890,14 +1922,18 @@
   return (jobjectArray)JNIHandles::make_local(env, result);
 }
 JVM_END
 
 static bool select_method(const methodHandle& method, bool want_constructor) {
+  bool is_ctor = (method->is_object_constructor() ||
+                  method->is_static_init_factory());
   if (want_constructor) {
-    return (method->is_initializer() && !method->is_static());
+    return is_ctor;
   } else {
-    return  (!method->is_initializer() && !method->is_overpass());
+    return (!is_ctor &&
+            !method->is_class_initializer() &&
+            !method->is_overpass());
   }
 }
 
 static jobjectArray get_class_declared_methods_helper(
                                   JNIEnv *env,
@@ -1955,10 +1991,12 @@
       // Otherwise should probably put a method that throws NSME
       result->obj_at_put(i, NULL);
     } else {
       oop m;
       if (want_constructor) {
+        assert(method->is_object_constructor() ||
+               method->is_static_init_factory(), "must be");
         m = Reflection::new_constructor(method, CHECK_NULL);
       } else {
         m = Reflection::new_method(method, false, CHECK_NULL);
       }
       result->obj_at_put(i, m);
@@ -2212,14 +2250,14 @@
   methodHandle m (THREAD, k->find_method(name, sig));
   if (m.is_null()) {
     THROW_MSG_0(vmSymbols::java_lang_RuntimeException(), "Unable to look up method in target class");
   }
   oop method;
-  if (!m->is_initializer() || m->is_static()) {
-    method = Reflection::new_method(m, true, CHECK_NULL);
-  } else {
+  if (m->is_object_constructor() || m->is_static_init_factory()) {
     method = Reflection::new_constructor(m, CHECK_NULL);
+  } else {
+    method = Reflection::new_method(m, true, CHECK_NULL);
   }
   return JNIHandles::make_local(method);
 }
 
 JVM_ENTRY(jobject, JVM_ConstantPoolGetMethodAt(JNIEnv *env, jobject obj, jobject unused, jint index))
@@ -2503,10 +2541,49 @@
   JvmtiVMObjectAllocEventCollector oam;
   oop asd = JavaAssertions::createAssertionStatusDirectives(CHECK_NULL);
   return JNIHandles::make_local(env, asd);
 JVM_END
 
+// Arrays support /////////////////////////////////////////////////////////////
+
+JVM_ENTRY(jboolean, JVM_ArrayIsAccessAtomic(JNIEnv *env, jclass unused, jobject array))
+  JVMWrapper("JVM_ArrayIsAccessAtomic");
+  oop o = JNIHandles::resolve(array);
+  Klass* k = o->klass();
+  if ((o == NULL) || (!k->is_array_klass())) {
+    THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+  }
+  return ArrayKlass::cast(k)->element_access_is_atomic();
+JVM_END
+
+JVM_ENTRY(jobject, JVM_ArrayEnsureAccessAtomic(JNIEnv *env, jclass unused, jobject array))
+  JVMWrapper("JVM_ArrayEnsureAccessAtomic");
+  oop o = JNIHandles::resolve(array);
+  Klass* k = o->klass();
+  if ((o == NULL) || (!k->is_array_klass())) {
+    THROW_0(vmSymbols::java_lang_IllegalArgumentException());
+  }
+  if (k->is_flatArray_klass()) {
+    FlatArrayKlass* vk = FlatArrayKlass::cast(k);
+    if (!vk->element_access_is_atomic()) {
+      /**
+       * Need to decide how to implement:
+       *
+       * 1) Change to objArrayOop layout, therefore oop->klass() differs so
+       * then "<atomic>[Qfoo;" klass needs to subclass "[Qfoo;" to pass through
+       * "checkcast" & "instanceof"
+       *
+       * 2) Use extra header in the flatArrayOop to flag atomicity required and
+       * possibly per instance lock structure. Said info, could be placed in
+       * "trailer" rather than disturb the current arrayOop
+       */
+      Unimplemented();
+    }
+  }
+  return array;
+JVM_END
+
 // Verification ////////////////////////////////////////////////////////////////////////////////
 
 // Reflection for the verifier /////////////////////////////////////////////////////////////////
 
 // RedefineClasses support: bug 6214132 caused verification to fail.
@@ -2682,11 +2759,11 @@
   JVMWrapper("JVM_IsConstructorIx");
   ResourceMark rm(THREAD);
   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls));
   k = JvmtiThreadState::class_to_verify_considering_redefinition(k, thread);
   Method* method = InstanceKlass::cast(k)->methods()->at(method_index);
-  return method->name() == vmSymbols::object_initializer_name();
+  return method->is_object_constructor();
 JVM_END
 
 
 JVM_ENTRY(jboolean, JVM_IsVMGeneratedMethodIx(JNIEnv *env, jclass cls, int method_index))
   JVMWrapper("JVM_IsVMGeneratedMethodIx");
@@ -3677,11 +3754,11 @@
   JVMWrapper("JVM_InvokeMethod");
   Handle method_handle;
   if (thread->stack_available((address) &method_handle) >= JVMInvokeMethodSlack) {
     method_handle = Handle(THREAD, JNIHandles::resolve(method));
     Handle receiver(THREAD, JNIHandles::resolve(obj));
-    objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
+    objArrayHandle args = oopFactory::ensure_objArray(JNIHandles::resolve(args0), CHECK_NULL);
     oop result = Reflection::invoke_method(method_handle(), receiver, args, CHECK_NULL);
     jobject res = JNIHandles::make_local(env, result);
     if (JvmtiExport::should_post_vm_object_alloc()) {
       oop ret_type = java_lang_reflect_Method::return_type(method_handle());
       assert(ret_type != NULL, "sanity check: ret_type oop must not be NULL!");
@@ -3698,12 +3775,12 @@
 JVM_END
 
 
 JVM_ENTRY(jobject, JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0))
   JVMWrapper("JVM_NewInstanceFromConstructor");
+  objArrayHandle args = oopFactory::ensure_objArray(JNIHandles::resolve(args0), CHECK_NULL);
   oop constructor_mirror = JNIHandles::resolve(c);
-  objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0)));
   oop result = Reflection::invoke_constructor(constructor_mirror, args, CHECK_NULL);
   jobject res = JNIHandles::make_local(env, result);
   if (JvmtiExport::should_post_vm_object_alloc()) {
     JvmtiExport::post_vm_object_alloc(JavaThread::current(), result);
   }
diff a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -763,10 +763,28 @@
           "Use SSE2 MOVQ instruction for Arraycopy")                        \
                                                                             \
   notproduct(bool, PrintFieldLayout, false,                                 \
           "Print field layout for each class")                              \
                                                                             \
+  notproduct(bool, PrintInlineLayout, false,                                \
+          "Print field layout for each inline type")                        \
+                                                                            \
+  notproduct(bool, PrintFlatArrayLayout, false,                             \
+          "Print array layout for each inline type array")                  \
+                                                                            \
+  product(intx, FlatArrayElementMaxSize, -1,                                \
+          "Max size for flattening inline array elements, <0 no limit")     \
+                                                                            \
+  product(intx, InlineFieldMaxFlatSize, 128,                                \
+          "Max size for flattening inline type fields, <0 no limit")        \
+                                                                            \
+  product(intx, FlatArrayElementMaxOops, 4,                                 \
+          "Max nof embedded object references in an inline type to flatten, <0 no limit")  \
+                                                                            \
+  product(bool, InlineArrayAtomicAccess, false,                             \
+          "Atomic inline array accesses by-default, for all inline arrays") \
+                                                                            \
   /* Need to limit the extent of the padding to reasonable size.          */\
   /* 8K is well beyond the reasonable HW cache line size, even with       */\
   /* aggressive prefetching, while still leaving the room for segregating */\
   /* among the distinct pages.                                            */\
   product(intx, ContendedPaddingWidth, 128,                                 \
@@ -778,11 +796,11 @@
           "Enable @Contended annotation support")                           \
                                                                             \
   product(bool, RestrictContended, true,                                    \
           "Restrict @Contended to trusted classes")                         \
                                                                             \
-  product(bool, UseBiasedLocking, false,                                    \
+  product(bool, UseBiasedLocking, true,                                     \
           "(Deprecated) Enable biased locking in JVM")                      \
                                                                             \
   product(intx, BiasedLockingStartupDelay, 0,                               \
           "(Deprecated) Number of milliseconds to wait before enabling "    \
           "biased locking")                                                 \
@@ -2453,19 +2471,40 @@
           "Start flight recording with options"))                           \
                                                                             \
   experimental(bool, UseFastUnorderedTimeStamps, false,                     \
           "Use platform unstable time where supported for timestamps only") \
                                                                             \
+  product(bool, EnableValhalla, true,                                       \
+          "Enable experimental Valhalla features")                          \
+                                                                            \
+  product_pd(bool, InlineTypePassFieldsAsArgs,                              \
+          "Pass each inline type field as an argument at calls")            \
+                                                                            \
+  product_pd(bool, InlineTypeReturnedAsFields,                              \
+          "Return fields instead of an inline type reference")              \
+                                                                            \
+  develop(bool, StressInlineTypeReturnedAsFields, false,                    \
+          "Stress return of fields instead of an inline type reference")    \
+                                                                            \
+  develop(bool, ScalarizeInlineTypes, true,                                 \
+          "Scalarize inline types in compiled code")                        \
+                                                                            \
+  diagnostic(ccstrlist, ForceNonTearable, "",                               \
+          "List of inline classes which are forced to be atomic "           \
+          "(whitespace and commas separate names, "                         \
+          "and leading and trailing stars '*' are wildcards)")              \
+                                                                            \
   product(bool, UseNewFieldLayout, true,                                    \
-               "(Deprecated) Use new algorithm to compute field layouts")   \
+                "(Deprecated) Use new algorithm to compute field layouts")  \
                                                                             \
   product(bool, UseEmptySlotsInSupers, true,                                \
                 "Allow allocating fields in empty slots of super-classes")  \
                                                                             \
   diagnostic(bool, DeoptimizeNMethodBarriersALot, false,                    \
                 "Make nmethod barriers deoptimise a lot.")                  \
 
+
 // Interface macros
 #define DECLARE_PRODUCT_FLAG(type, name, value, doc)      extern "C" type name;
 #define DECLARE_PD_PRODUCT_FLAG(type, name, doc)          extern "C" type name;
 #define DECLARE_DIAGNOSTIC_FLAG(type, name, value, doc)   extern "C" type name;
 #define DECLARE_PD_DIAGNOSTIC_FLAG(type, name, doc)       extern "C" type name;
diff a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -56,10 +56,11 @@
 #include "oops/instanceKlass.hpp"
 #include "oops/objArrayOop.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayOop.inline.hpp"
+#include "oops/inlineKlass.hpp"
 #include "oops/verifyOopClosure.hpp"
 #include "prims/jvm_misc.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
 #include "runtime/arguments.hpp"
@@ -1635,10 +1636,11 @@
   set_entry_point(NULL);
   set_jni_functions(jni_functions());
   set_callee_target(NULL);
   set_vm_result(NULL);
   set_vm_result_2(NULL);
+  set_return_buffered_value(NULL);
   set_vframe_array_head(NULL);
   set_vframe_array_last(NULL);
   set_deferred_locals(NULL);
   set_deopt_mark(NULL);
   set_deopt_compiled_method(NULL);
@@ -2840,10 +2842,13 @@
 }
 
 void JavaThread::frames_do(void f(frame*, const RegisterMap* map)) {
   // ignore is there is no stack
   if (!has_last_Java_frame()) return;
+  // Because this method is used to verify oops, it must support
+  // oops in buffered values
+
   // traverse the stack frames. Starts from top frame.
   for (StackFrameStream fst(this); !fst.is_done(); fst.next()) {
     frame* fr = fst.current();
     f(fr, fst.register_map());
   }
diff a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp
--- a/src/hotspot/share/runtime/thread.hpp
+++ b/src/hotspot/share/runtime/thread.hpp
@@ -440,10 +440,11 @@
  public:
   enum {
     is_definitely_current_thread = true
   };
 
+ public:
   // Constructor
   Thread();
   virtual ~Thread() = 0;        // Thread is abstract.
 
   // Manage Thread::current()
@@ -1012,10 +1013,11 @@
 
 class JavaThread: public Thread {
   friend class VMStructs;
   friend class JVMCIVMStructs;
   friend class WhiteBox;
+  friend class VTBuffer;
   friend class ThreadsSMRSupport; // to access _threadObj for exiting_threads_oops_do
  private:
   bool           _on_thread_list;                // Is set when this JavaThread is added to the Threads list
   oop            _threadObj;                     // The Java level thread object
 
@@ -1070,10 +1072,11 @@
   Method*       _callee_target;
 
   // Used to pass back results to the interpreter or generated code running Java code.
   oop           _vm_result;    // oop result is GC-preserved
   Metadata*     _vm_result_2;  // non-oop result
+  oop           _return_buffered_value; // buffered value being returned
 
   // See ReduceInitialCardMarks: this holds the precise space interval of
   // the most recent slow path allocation for which compiled code has
   // elided card-marks for performance along the fast-path.
   MemRegion     _deferred_card_mark;
@@ -1550,10 +1553,13 @@
   void set_vm_result  (oop x)                    { _vm_result   = x; }
 
   Metadata*    vm_result_2() const               { return _vm_result_2; }
   void set_vm_result_2  (Metadata* x)          { _vm_result_2   = x; }
 
+  oop return_buffered_value() const              { return _return_buffered_value; }
+  void set_return_buffered_value(oop val)        { _return_buffered_value = val; }
+
   MemRegion deferred_card_mark() const           { return _deferred_card_mark; }
   void set_deferred_card_mark(MemRegion mr)      { _deferred_card_mark = mr;   }
 
 #if INCLUDE_JVMCI
   int  pending_deoptimization() const             { return _pending_deoptimization; }
@@ -1789,10 +1795,11 @@
     return byte_offset_of(JavaThread, _anchor);
   }
   static ByteSize callee_target_offset()         { return byte_offset_of(JavaThread, _callee_target); }
   static ByteSize vm_result_offset()             { return byte_offset_of(JavaThread, _vm_result); }
   static ByteSize vm_result_2_offset()           { return byte_offset_of(JavaThread, _vm_result_2); }
+  static ByteSize return_buffered_value_offset() { return byte_offset_of(JavaThread, _return_buffered_value); }
   static ByteSize thread_state_offset()          { return byte_offset_of(JavaThread, _thread_state); }
   static ByteSize saved_exception_pc_offset()    { return byte_offset_of(JavaThread, _saved_exception_pc); }
   static ByteSize osthread_offset()              { return byte_offset_of(JavaThread, _osthread); }
 #if INCLUDE_JVMCI
   static ByteSize pending_deoptimization_offset() { return byte_offset_of(JavaThread, _pending_deoptimization); }
diff a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp
--- a/src/hotspot/share/runtime/vmOperations.hpp
+++ b/src/hotspot/share/runtime/vmOperations.hpp
@@ -115,10 +115,11 @@
   template(ICBufferFull)                          \
   template(ScavengeMonitors)                      \
   template(PrintMetadata)                         \
   template(GTestExecuteAtSafepoint)               \
   template(JFROldObject)                          \
+  template(ClassPrintLayout)                      \
 
 class VM_Operation : public StackObj {
  public:
   enum VMOp_Type {
     VM_OPS_DO(VM_OP_ENUM)
@@ -416,10 +417,20 @@
   VM_PrintCompileQueue(outputStream* st) : _out(st) {}
   VMOp_Type type() const { return VMOp_PrintCompileQueue; }
   void doit();
 };
 
+class VM_PrintClassLayout: public VM_Operation {
+ private:
+  outputStream* _out;
+  char* _class_name;
+ public:
+  VM_PrintClassLayout(outputStream* st, char* class_name): _out(st), _class_name(class_name) {}
+  VMOp_Type type() const { return VMOp_PrintClassHierarchy; }
+  void doit();
+};
+
 #if INCLUDE_SERVICES
 class VM_PrintClassHierarchy: public VM_Operation {
  private:
   outputStream* _out;
   bool _print_interfaces;
diff a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp
--- a/src/hotspot/share/services/diagnosticCommand.cpp
+++ b/src/hotspot/share/services/diagnosticCommand.cpp
@@ -94,10 +94,11 @@
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemDictionaryDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHierarchyDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<metaspace::MetaspaceDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintClassLayoutDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<EventLogDCmd>(full_export, true, false));
 #if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
 #endif // INCLUDE_JVMTI
 #endif // INCLUDE_SERVICES
@@ -124,11 +125,10 @@
   uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStatusDCmd>(jmx_agent_export_flags, true,false));
-
   // Debug on cmd (only makes sense with JVMTI since the agentlib needs it).
 #if INCLUDE_JVMTI
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DebugOnCmdStartDCmd>(full_export, true, true));
 #endif // INCLUDE_JVMTI
 
@@ -1027,10 +1027,33 @@
   }
 }
 
 #endif
 
+PrintClassLayoutDCmd::PrintClassLayoutDCmd(outputStream* output, bool heap) :
+                                       DCmdWithParser(output, heap),
+  _classname("classname", "Name of class whose layout should be printed. ",
+             "STRING", true) {
+  _dcmdparser.add_dcmd_argument(&_classname);
+}
+
+void PrintClassLayoutDCmd::execute(DCmdSource source, TRAPS) {
+  VM_PrintClassLayout printClassLayoutOp(output(), _classname.value());
+  VMThread::execute(&printClassLayoutOp);
+}
+
+int PrintClassLayoutDCmd::num_arguments() {
+  ResourceMark rm;
+  PrintClassLayoutDCmd* dcmd = new PrintClassLayoutDCmd(NULL, false);
+  if (dcmd != NULL) {
+    DCmdMark mark(dcmd);
+    return dcmd->_dcmdparser.num_arguments();
+  } else {
+    return 0;
+  }
+}
+
 class VM_DumpTouchedMethods : public VM_Operation {
 private:
   outputStream* _out;
 public:
   VM_DumpTouchedMethods(outputStream* out) {
diff a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp
--- a/src/hotspot/share/utilities/growableArray.hpp
+++ b/src/hotspot/share/utilities/growableArray.hpp
@@ -24,10 +24,12 @@
 
 #ifndef SHARE_UTILITIES_GROWABLEARRAY_HPP
 #define SHARE_UTILITIES_GROWABLEARRAY_HPP
 
 #include "memory/allocation.hpp"
+#include "oops/array.hpp"
+#include "oops/oop.hpp"
 #include "memory/iterator.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/ostream.hpp"
 #include "utilities/powerOfTwo.hpp"
@@ -411,10 +413,16 @@
     for (int i = 0; i < l->length(); i++) {
       this->at_put_grow(this->_len, l->at(i), E());
     }
   }
 
+  void appendAll(const Array<E>* l) {
+    for (int i = 0; i < l->length(); i++) {
+      this->at_put_grow(this->_len, l->at(i), E());
+    }
+  }
+
   // Binary search and insertion utility.  Search array for element
   // matching key according to the static compare function.  Insert
   // that element is not already in the list.  Assumes the list is
   // already sorted according to compare function.
   template <int compare(const E&, const E&)> E insert_sorted(const E& key) {
@@ -751,23 +759,23 @@
   const GrowableArrayView<E>* _array; // GrowableArray we iterate over
   int _position;                      // Current position in the GrowableArray
   UnaryPredicate _predicate;          // Unary predicate the elements of the GrowableArray should satisfy
 
  public:
-  GrowableArrayFilterIterator(const GrowableArrayIterator<E>& begin, UnaryPredicate filter_predicate) :
-      _array(begin._array), _position(begin._position), _predicate(filter_predicate) {
+  GrowableArrayFilterIterator(const GrowableArray<E>* array, UnaryPredicate filter_predicate) :
+      _array(array), _position(0), _predicate(filter_predicate) {
     // Advance to first element satisfying the predicate
-    while(_position != _array->length() && !_predicate(_array->at(_position))) {
+    while(!at_end() && !_predicate(_array->at(_position))) {
       ++_position;
     }
   }
 
   GrowableArrayFilterIterator<E, UnaryPredicate>& operator++() {
     do {
       // Advance to next element satisfying the predicate
       ++_position;
-    } while(_position != _array->length() && !_predicate(_array->at(_position)));
+    } while(!at_end() && !_predicate(_array->at(_position)));
     return *this;
   }
 
   E operator*() { return _array->at(_position); }
 
@@ -788,10 +796,14 @@
 
   bool operator!=(const GrowableArrayFilterIterator<E, UnaryPredicate>& rhs)  {
     assert(_array == rhs._array, "iterator belongs to different array");
     return _position != rhs._position;
   }
+
+  bool at_end() const {
+    return _array == NULL || _position == _array->end()._position;
+  }
 };
 
 // Arrays for basic types
 typedef GrowableArray<int> intArray;
 typedef GrowableArray<int> intStack;
diff a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java
--- a/src/java.base/share/classes/module-info.java
+++ b/src/java.base/share/classes/module-info.java
@@ -127,11 +127,10 @@
     exports javax.security.auth.login;
     exports javax.security.auth.spi;
     exports javax.security.auth.x500;
     exports javax.security.cert;
 
-
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
     exports sun.invoke.util to
         jdk.compiler,
@@ -342,11 +341,10 @@
         java.logging,
         java.prefs;
     exports sun.util.resources to
         jdk.localedata;
 
-
     // the service types defined by the APIs in this module
 
     uses java.lang.System.LoggerFinder;
     uses java.net.ContentHandlerFactory;
     uses java.net.spi.URLStreamHandlerProvider;
diff a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java
@@ -2257,10 +2257,19 @@
                 //when 292 issue is fixed we should remove this and change the backend
                 //code to always generate a method handle to an accessible method
                 return tree.ownerAccessible;
             }
 
+            /* Per our interim inline class translation scheme, the reference projection classes
+               are completely empty, so we want the methods in the value class to be invoked instead.
+               As the lambda meta factory isn't clued into this, it will try to invoke the method in
+               C$ref.class and fail with a NoSuchMethodError. we need to workaround it ourselves.
+            */
+            boolean receiverIsReferenceProjection() {
+                return tree.sym.kind == MTH && tree.sym.owner.isReferenceProjection();
+            }
+
             /**
              * This method should be called only when target release <= 14
              * where LambdaMetaFactory does not spin nestmate classes.
              *
              * This method should be removed when --release 14 is not supported.
@@ -2309,13 +2318,14 @@
                         needsVarArgsConversion() ||
                         isArrayOp() ||
                         (!nestmateLambdas && isPrivateInOtherClass()) ||
                         isProtectedInSuperClassOfEnclosingClassInOtherPackage(tree.sym, owner) ||
                         !receiverAccessible() ||
+                        receiverIsReferenceProjection() ||
                         (tree.getMode() == ReferenceMode.NEW &&
                           tree.kind != ReferenceKind.ARRAY_CTOR &&
-                          (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
+                          (tree.sym.owner.isLocal() || tree.sym.owner.isInner() || tree.sym.owner.isValue()));
             }
 
             Type generatedRefSig() {
                 return types.erasure(tree.sym.type);
             }
diff a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java
@@ -82,10 +82,11 @@
     private HotSpotResolvedObjectTypeImpl javaLangClass;
     private HotSpotResolvedObjectTypeImpl throwableType;
     private HotSpotResolvedObjectTypeImpl serializableType;
     private HotSpotResolvedObjectTypeImpl cloneableType;
     private HotSpotResolvedObjectTypeImpl enumType;
+    private HotSpotResolvedObjectTypeImpl identityObjectType;
 
     HotSpotResolvedObjectTypeImpl getJavaLangObject() {
         if (javaLangObject == null) {
             javaLangObject = (HotSpotResolvedObjectTypeImpl) fromClass(Object.class);
         }
@@ -118,10 +119,17 @@
             serializableType = (HotSpotResolvedObjectTypeImpl) fromClass(Serializable.class);
         }
         return serializableType;
     }
 
+    HotSpotResolvedObjectTypeImpl getJavaLangIdentityObject() {
+        if (identityObjectType == null) {
+            identityObjectType = (HotSpotResolvedObjectTypeImpl) fromClass(IdentityObject.class);
+        }
+        return identityObjectType;
+    }
+
     HotSpotResolvedObjectTypeImpl getJavaLangThrowable() {
         if (throwableType == null) {
             throwableType = (HotSpotResolvedObjectTypeImpl) fromClass(Throwable.class);
         }
         return throwableType;
diff a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java
@@ -417,12 +417,18 @@
 
         if (isJDK14OrHigher()) {
             add(toBeInvestigated,
                             "com/sun/crypto/provider/ElectronicCodeBook.implECBDecrypt([BII[BI)I",
                             "com/sun/crypto/provider/ElectronicCodeBook.implECBEncrypt([BII[BI)I",
+                            "java/lang/Class.asIndirectType()Ljava/lang/Class;",
+                            "java/lang/Class.asPrimaryType()Ljava/lang/Class;",
                             "java/math/BigInteger.shiftLeftImplWorker([I[IIII)V",
-                            "java/math/BigInteger.shiftRightImplWorker([I[IIII)V");
+                            "java/math/BigInteger.shiftRightImplWorker([I[IIII)V",
+                            "jdk/internal/misc/Unsafe.finishPrivateBuffer(Ljava/lang/Object;)Ljava/lang/Object;",
+                            "jdk/internal/misc/Unsafe.getValue(Ljava/lang/Object;JLjava/lang/Class;)Ljava/lang/Object;",
+                            "jdk/internal/misc/Unsafe.makePrivateBuffer(Ljava/lang/Object;)Ljava/lang/Object;",
+                            "jdk/internal/misc/Unsafe.putValue(Ljava/lang/Object;JLjava/lang/Class;Ljava/lang/Object;)V");
         }
 
         if (!config.inlineNotify()) {
             add(ignore, "java/lang/Object.notify()V");
         }
diff a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -66,10 +66,87 @@
 compiler/rtm/locking/TestRTMSpinLoopCount.java 8183263 generic-x64
 compiler/rtm/locking/TestUseRTMDeopt.java 8183263 generic-x64
 compiler/rtm/locking/TestUseRTMXendForLockBusy.java 8183263 generic-x64
 compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64
 
+# Valhalla
+compiler/arguments/CheckCICompilerCount.java                        8205030 generic-all
+compiler/arguments/CheckCompileThresholdScaling.java                8205030 generic-all
+compiler/codecache/CheckSegmentedCodeCache.java                     8205030 generic-all
+compiler/codecache/cli/TestSegmentedCodeCacheOption.java            8205030 generic-all
+compiler/codecache/cli/codeheapsize/TestCodeHeapSizeOptions.java    8205030 generic-all
+compiler/codecache/cli/printcodecache/TestPrintCodeCacheOption.java 8205030 generic-all
+compiler/whitebox/OSRFailureLevel4Test.java                         8205030 generic-all
+
+compiler/aot/cli/DisabledAOTWithLibraryTest.java 8226295 generic-all
+compiler/aot/cli/SingleAOTOptionTest.java 8226295 generic-all
+compiler/aot/cli/MultipleAOTLibraryTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileClassWithDebugTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileModuleTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/AtFileTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/ListOptionWrongFileTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/ClasspathOptionUnknownClassTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileDirectoryTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/ListOptionTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/ListOptionNotExistingTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileClassTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileJarTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/IgnoreErrorsTest.java 8226295 generic-all
+compiler/aot/cli/jaotc/CompileAbsoluteDirectoryTest.java 8226295 generic-all
+compiler/aot/cli/NonExistingAOTLibraryTest.java 8226295 generic-all
+compiler/aot/cli/SingleAOTLibraryTest.java 8226295 generic-all
+compiler/aot/cli/IncorrectAOTLibraryTest.java 8226295 generic-all
+compiler/aot/RecompilationTest.java 8226295 generic-all
+compiler/aot/SharedUsageTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSearchTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/SearchPathTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/module/ModuleSourceProviderTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/ClassSourceTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/directory/DirectorySourceProviderTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/collect/jar/JarSourceProviderTest.java 8226295 generic-all
+compiler/aot/jdk.tools.jaotc.test/src/jdk/tools/jaotc/test/NativeOrderOutputStreamTest.java 8226295 generic-all
+compiler/aot/verification/vmflags/TrackedFlagTest.java 8226295 generic-all
+compiler/aot/verification/vmflags/NotTrackedFlagTest.java 8226295 generic-all
+compiler/aot/verification/ClassAndLibraryNotMatchTest.java 8226295 generic-all
+compiler/aot/DeoptimizationTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeVirtual2NativeTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeStatic2CompiledTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeSpecial2CompiledTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeVirtual2CompiledTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeVirtual2InterpretedTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeDynamic2NativeTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeDynamic2InterpretedTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeStatic2InterpretedTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeInterface2InterpretedTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeVirtual2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeInterface2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeSpecial2NativeTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeDynamic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeInterface2NativeTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeStatic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeInterface2CompiledTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeDynamic2CompiledTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeStatic2NativeTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeSpecial2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromAot/AotInvokeSpecial2InterpretedTest.java 8226295 generic-all
+compiler/aot/calls/fromNative/NativeInvokeStatic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromNative/NativeInvokeSpecial2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromNative/NativeInvokeVirtual2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromCompiled/CompiledInvokeInterface2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromCompiled/CompiledInvokeVirtual2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromCompiled/CompiledInvokeDynamic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromCompiled/CompiledInvokeStatic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromCompiled/CompiledInvokeSpecial2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromInterpreted/InterpretedInvokeDynamic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromInterpreted/InterpretedInvokeStatic2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromInterpreted/InterpretedInvokeVirtual2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromInterpreted/InterpretedInvokeSpecial2AotTest.java 8226295 generic-all
+compiler/aot/calls/fromInterpreted/InterpretedInvokeInterface2AotTest.java 8226295 generic-all
+compiler/aot/fingerprint/SelfChanged.java 8226295 generic-all
+compiler/aot/fingerprint/SelfChangedCDS.java 8226295 generic-all
+compiler/aot/fingerprint/SuperChanged.java 8226295 generic-all
+
 compiler/c2/Test8004741.java 8235801 generic-all
 
 #############################################################################
 
 # :hotspot_gc
@@ -89,10 +166,32 @@
 # :hotspot_runtime
 
 runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64
 runtime/ReservedStack/ReservedStackTest.java 8231031 generic-all
 
+# Valhalla TODO:
+runtime/CompressedOops/CompressedClassPointers.java 8210258 generic-all
+runtime/RedefineTests/RedefineLeak.java 8205032 generic-all
+runtime/SharedArchiveFile/BootAppendTests.java 8210258 generic-all
+runtime/SharedArchiveFile/CdsDifferentCompactStrings.java 8210258 generic-all
+runtime/SharedArchiveFile/CdsDifferentObjectAlignment.java 8210258 generic-all
+runtime/SharedArchiveFile/NonBootLoaderClasses.java 8210258 generic-all
+runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java 8210258 generic-all
+runtime/SharedArchiveFile/SharedArchiveFile.java 8210258 generic-all
+runtime/SharedArchiveFile/SharedStringsDedup.java 8210258 generic-all
+runtime/SharedArchiveFile/SharedStringsRunAuto.java 8210258 generic-all
+runtime/SharedArchiveFile/SharedSymbolTableBucketSize.java 8210258 generic-all
+runtime/SharedArchiveFile/SpaceUtilizationCheck.java 8210258 generic-all
+runtime/SharedArchiveFile/TestInterpreterMethodEntries.java 8210258 generic-all
+runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java 8210258 generic-all
+runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java 8210258 generic-all
+runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java 8210258 generic-all
+runtime/appcds/ClassLoaderTest.java 8210258 generic-all
+runtime/appcds/HelloTest.java 8210258 generic-all
+runtime/appcds/sharedStrings/SharedStringsBasic.java 8210258 generic-all
+
+
 #############################################################################
 
 # :hotspot_serviceability
 
 serviceability/sa/sadebugd/DebugdConnectTest.java 8239062 macosx-x64
@@ -102,10 +201,36 @@
 
 serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 8214032 generic-all
 serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 8224150 generic-all
 serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all
 
+# Valhalla TODO:
+serviceability/sa/ClhsdbCDSCore.java 8190936 generic-all
+serviceability/sa/ClhsdbCDSJstackPrintAll.java 8190936 generic-all
+serviceability/sa/ClhsdbFindPC.java 8190936 generic-all
+serviceability/sa/ClhsdbInspect.java 8190936 generic-all
+serviceability/sa/ClhsdbJdis.java 8190936 generic-all
+serviceability/sa/ClhsdbJstack.java 8190936 generic-all
+serviceability/sa/ClhsdbPrintAll.java 8190936 generic-all
+serviceability/sa/ClhsdbPrintAs.java 8190936 generic-all
+serviceability/sa/ClhsdbPrintStatics.java 8190936 generic-all
+serviceability/sa/ClhsdbSource.java 8190936 generic-all
+serviceability/sa/ClhsdbSymbol.java 8190936 generic-all
+serviceability/sa/ClhsdbWhere.java 8190936 generic-all
+serviceability/sa/JhsdbThreadInfoTest.java 8190936 generic-all
+serviceability/sa/TestClassDump.java 8190936 generic-all
+serviceability/sa/TestClhsdbJstackLock.java 8190936 generic-all
+serviceability/sa/TestCpoolForInvokeDynamic.java 8190936 generic-all
+serviceability/sa/TestHeapDumpForInvokeDynamic.java 8190936 generic-all
+serviceability/sa/TestHeapDumpForLargeArray.java 8190936 generic-all
+serviceability/sa/TestIntConstant.java 8190936 generic-all
+serviceability/sa/TestJhsdbJstackLock.java 8190936 generic-all
+serviceability/sa/TestJmapCore.java 8190936 generic-all
+serviceability/sa/TestJmapCoreMetaspace.java 8190936 generic-all
+serviceability/sa/TestPrintMdo.java 8190936 generic-all
+serviceability/sa/jmap-hprof/JMapHProfLargeHeapTest.java 8190936 generic-all
+
 #############################################################################
 
 # :hotspot_misc
 
 #############################################################################
