diff a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp
--- a/src/hotspot/share/oops/oop.inline.hpp
+++ b/src/hotspot/share/oops/oop.inline.hpp
@@ -58,23 +58,43 @@
 markWord* oopDesc::mark_addr() const {
   return (markWord*) &_mark;
 }
 
 void oopDesc::set_mark(markWord m) {
+  if (UseCompactObjectHeaders) {
+    Atomic::store(reinterpret_cast<uint32_t volatile*>(&_mark), m.value32());
+  } else {
+    Atomic::store(&_mark, m);
+  }
+}
+
+void oopDesc::set_mark_full(markWord m) {
   Atomic::store(&_mark, m);
 }
 
 void oopDesc::set_mark(HeapWord* mem, markWord m) {
-  *(markWord*)(((char*)mem) + mark_offset_in_bytes()) = m;
+  if (UseCompactObjectHeaders) {
+    *(uint32_t*)(((char*)mem) + mark_offset_in_bytes()) = m.value32();
+  } else {
+    *(markWord*)(((char*)mem) + mark_offset_in_bytes()) = m;
+  }
 }
 
 void oopDesc::release_set_mark(HeapWord* mem, markWord m) {
-  Atomic::release_store((markWord*)(((char*)mem) + mark_offset_in_bytes()), m);
+  if (UseCompactObjectHeaders) {
+    Atomic::release_store((uint32_t*)(((char*)mem) + mark_offset_in_bytes()), m.value32());
+  } else {
+    Atomic::release_store((markWord*)(((char*)mem) + mark_offset_in_bytes()), m);
+  }
 }
 
 void oopDesc::release_set_mark(markWord m) {
-  Atomic::release_store(&_mark, m);
+  if (UseCompactObjectHeaders) {
+    Atomic::release_store(reinterpret_cast<uint32_t volatile*>(&_mark), m.value32());
+  } else {
+    Atomic::release_store(&_mark, m);
+  }
 }
 
 markWord oopDesc::cas_set_mark(markWord new_mark, markWord old_mark) {
   return Atomic::cmpxchg(&_mark, old_mark, new_mark);
 }
@@ -90,11 +110,17 @@
     return markWord::prototype();
   }
 }
 
 void oopDesc::init_mark() {
-  set_mark(prototype_mark());
+  if (UseCompactObjectHeaders) {
+    markWord m = prototype_mark().copy_hashctrl_from(mark());
+    assert(m.is_neutral(), "must be neutral");
+    set_mark(m);
+  } else {
+    set_mark(prototype_mark());
+  }
 }
 
 Klass* oopDesc::klass() const {
   switch (ObjLayout::klass_mode()) {
     case ObjLayout::Compact:
@@ -170,15 +196,53 @@
 
 bool oopDesc::is_a(Klass* k) const {
   return klass()->is_subtype_of(k);
 }
 
+size_t oopDesc::size_given_mark_and_klass(markWord mrk, const Klass* kls) {
+  size_t sz = base_size_given_klass(mrk, kls);
+  if (UseCompactObjectHeaders) {
+    assert(!mrk.has_displaced_mark_helper(), "must not be displaced");
+    if (mrk.is_expanded() && kls->expand_for_hash(cast_to_oop(this), mrk)) {
+      sz = align_object_size(sz + 1);
+    }
+  }
+  return sz;
+}
+
+size_t oopDesc::copy_size(size_t size, markWord mark) const {
+  if (UseCompactObjectHeaders) {
+    assert(!mark.has_displaced_mark_helper(), "must not be displaced");
+    Klass* klass = mark.klass();
+    if (mark.is_hashed_not_expanded() && klass->expand_for_hash(cast_to_oop(this), mark)) {
+      size = align_object_size(size + 1);
+    }
+  }
+  assert(is_object_aligned(size), "Oop size is not properly aligned: %zu", size);
+  return size;
+}
+
+size_t oopDesc::copy_size_cds(size_t size, markWord mark) const {
+  if (UseCompactObjectHeaders) {
+    assert(!mark.has_displaced_mark_helper(), "must not be displaced");
+    Klass* klass = mark.klass();
+    if (mark.is_hashed_not_expanded() && klass->expand_for_hash(cast_to_oop(this), mark)) {
+      size = align_object_size(size + 1);
+    }
+    if (mark.is_not_hashed_expanded() && klass->expand_for_hash(cast_to_oop(this), mark)) {
+      size = align_object_size(size - ObjectAlignmentInBytes / HeapWordSize);
+    }
+  }
+  assert(is_object_aligned(size), "Oop size is not properly aligned: %zu", size);
+  return size;
+}
+
 size_t oopDesc::size()  {
-  return size_given_klass(klass());
+  return size_given_mark_and_klass(mark(), klass());
 }
 
-size_t oopDesc::size_given_klass(Klass* klass)  {
+size_t oopDesc::base_size_given_klass(markWord mrk, const Klass* klass)  {
   int lh = klass->layout_helper();
   size_t s;
 
   // lh is now a value computed at class initialization that may hint
   // at the size.  For instances, this is positive and equal to the
@@ -193,32 +257,43 @@
 
   if (lh > Klass::_lh_neutral_value) {
     if (!Klass::layout_helper_needs_slow_path(lh)) {
       s = lh >> LogHeapWordSize;  // deliver size scaled by wordSize
     } else {
-      s = klass->oop_size(this);
+      s = klass->oop_size(this, mrk);
     }
   } else if (lh <= Klass::_lh_neutral_value) {
     // The most common case is instances; fall through if so.
     if (lh < Klass::_lh_neutral_value) {
       // Second most common case is arrays.  We have to fetch the
       // length of the array, shift (multiply) it appropriately,
       // up to wordSize, add the header, and align to object size.
       size_t size_in_bytes;
-      size_t array_length = (size_t) ((arrayOop)this)->length();
+      size_t array_length;
+#ifdef _LP64
+      if (UseCompactObjectHeaders) {
+        array_length = (size_t) mrk.array_length();
+      } else
+#endif
+        array_length = (size_t)((arrayOop)this)->length();
+
       size_in_bytes = array_length << Klass::layout_helper_log2_element_size(lh);
       size_in_bytes += Klass::layout_helper_header_size(lh);
 
       // This code could be simplified, but by keeping array_header_in_bytes
       // in units of bytes and doing it this way we can round up just once,
       // skipping the intermediate round to HeapWordSize.
       s = align_up(size_in_bytes, MinObjAlignmentInBytes) / HeapWordSize;
-
-      assert(s == klass->oop_size(this), "wrong array object size");
+      if (s != klass->oop_size(this, mrk)) {
+        tty->print_cr("length: %zu", array_length);
+        tty->print_cr("log element size: %d", Klass::layout_helper_log2_element_size(lh));
+        tty->print_cr("is_objArray: %s", BOOL_TO_STR(klass->is_objArray_klass()));
+      }
+      assert(s == klass->oop_size(this, mrk), "wrong array object size, s: %zu, oop_size: %zu", s, klass->oop_size(this, mrk));
     } else {
       // Must be zero, so bite the bullet and take the virtual call.
-      s = klass->oop_size(this);
+      s = klass->oop_size(this, mrk);
     }
   }
 
   assert(s > 0, "Oop size must be greater than zero, not %zu", s);
   assert(is_object_aligned(s), "Oop size is not properly aligned: %zu", s);
@@ -297,18 +372,37 @@
 // Used by scavengers
 void oopDesc::forward_to(oop p) {
   assert(cast_from_oop<oopDesc*>(p) != this,
          "must not be used for self-forwarding, use forward_to_self() instead");
   markWord m = markWord::encode_pointer_as_mark(p);
+  if (UseCompactObjectHeaders && p->mark().is_expanded() && !mark().is_expanded()) {
+    m = m.set_forward_expanded();
+  }
   assert(m.decode_pointer() == p, "encoding must be reversible");
-  set_mark(m);
+  set_mark_full(m);
 }
 
 void oopDesc::forward_to_self() {
   set_mark(mark().set_self_forwarded());
 }
 
+void oopDesc::reset_forwarded() {
+  markWord m = mark();
+  if (m.is_self_forwarded()) {
+    unset_self_forwarded();
+  } else if (m.is_forwarded()) {
+    // Restore Klass* and hash-bits in the header,
+    // for correct iteration.
+    markWord fwd_mark = forwardee()->mark();
+    if (m.is_forward_expanded()) {
+      // Un-expand original object.
+      fwd_mark = fwd_mark.set_hashed_expanded();
+    }
+    set_mark_full(fwd_mark);
+  }
+}
+
 oop oopDesc::cas_set_forwardee(markWord new_mark, markWord compare, atomic_memory_order order) {
   markWord old_mark = cas_set_mark(new_mark, compare, order);
   if (old_mark == compare) {
     return nullptr;
   } else {
@@ -383,19 +477,19 @@
 }
 
 template <typename OopClosureType>
 size_t oopDesc::oop_iterate_size(OopClosureType* cl) {
   Klass* k = klass();
-  size_t size = size_given_klass(k);
+  size_t size = size_given_mark_and_klass(mark(), k);
   OopIteratorClosureDispatch::oop_oop_iterate(cl, this, k);
   return size;
 }
 
 template <typename OopClosureType>
 size_t oopDesc::oop_iterate_size(OopClosureType* cl, MemRegion mr) {
   Klass* k = klass();
-  size_t size = size_given_klass(k);
+  size_t size = size_given_mark_and_klass(mark(), k);
   OopIteratorClosureDispatch::oop_oop_iterate(cl, this, k, mr);
   return size;
 }
 
 template <typename OopClosureType>
@@ -415,26 +509,35 @@
 }
 
 intptr_t oopDesc::identity_hash() {
   // Fast case; if the object is unlocked and the hash value is set, no locking is needed
   // Note: The mark must be read into local variable to avoid concurrent updates.
-  markWord mrk = mark();
-  if (mrk.is_unlocked() && !mrk.has_no_hash()) {
-    return mrk.hash();
-  } else if (mrk.is_marked()) {
-    return mrk.hash();
+  if (UseCompactObjectHeaders) {
+    markWord mrk = mark();
+    if (mrk.is_hashed_expanded()) {
+      Klass* klass = mrk.klass();
+      return int_field(klass->hash_offset_in_bytes(cast_to_oop(this), mrk));
+    }
+    // Fall-through to slow-case.
   } else {
-    return slow_identity_hash();
+    markWord mrk = mark();
+    if (mrk.is_unlocked() && !mrk.has_no_hash()) {
+      return mrk.hash();
+    } else if (mrk.is_marked()) {
+      return mrk.hash();
+    }
+    // Fall-through to slow-case.
   }
+  return slow_identity_hash();
 }
 
 // This checks fast simple case of whether the oop has_no_hash,
 // to optimize JVMTI table lookup.
 bool oopDesc::fast_no_hash_check() {
   markWord mrk = mark_acquire();
   assert(!mrk.is_marked(), "should never be marked");
-  return mrk.is_unlocked() && mrk.has_no_hash();
+  return (UseCompactObjectHeaders || mrk.is_unlocked()) && mrk.has_no_hash();
 }
 
 bool oopDesc::has_displaced_mark() const {
   return mark().has_displaced_mark_helper();
 }
@@ -453,6 +556,19 @@
 
 bool oopDesc::mark_must_be_preserved(markWord m) const {
   return m.must_be_preserved();
 }
 
+inline void oopDesc::initialize_hash_if_necessary(oop obj) {
+  if (!UseCompactObjectHeaders) {
+    return;
+  }
+  markWord m = mark();
+  assert(!m.has_displaced_mark_helper(), "must not be displaced header");
+  assert(!m.is_forwarded(), "must not be forwarded header");
+  if (m.is_hashed_not_expanded()) {
+    initialize_hash_if_necessary(obj, m.klass(), m);
+  }
+}
+
+
 #endif // SHARE_OOPS_OOP_INLINE_HPP
