diff a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp
--- a/src/hotspot/share/oops/oop.hpp
+++ b/src/hotspot/share/oops/oop.hpp
@@ -60,10 +60,12 @@
 
   // There may be ordering constraints on the initialization of fields that
   // make use of the C++ copy/assign incorrect.
   NONCOPYABLE(oopDesc);
 
+  inline oop cas_set_forwardee(markWord new_mark, markWord old_mark, atomic_memory_order order);
+
  public:
   // Must be trivial; see verifying static assert after the class.
   oopDesc() = default;
 
   inline markWord  mark()          const;
@@ -76,10 +78,15 @@
 
   inline void release_set_mark(markWord m);
   inline markWord cas_set_mark(markWord new_mark, markWord old_mark);
   inline markWord cas_set_mark(markWord new_mark, markWord old_mark, atomic_memory_order order);
 
+  inline markWord resolve_mark() const;
+
+  // Returns the prototype mark that should be used for this object.
+  inline markWord prototype_mark() const;
+
   // Used only to re-initialize the mark word (e.g., of promoted
   // objects during a GC) -- requires a valid klass pointer
   inline void init_mark();
 
   inline Klass* klass() const;
@@ -94,11 +101,17 @@
 
   // For klass field compression
   static inline void set_klass_gap(HeapWord* mem, int z);
 
   // size of object header, aligned to platform wordSize
-  static constexpr int header_size() { return sizeof(oopDesc)/HeapWordSize; }
+  static int header_size() {
+    if (UseCompactObjectHeaders) {
+      return sizeof(markWord) / HeapWordSize;
+    } else {
+      return sizeof(oopDesc)/HeapWordSize;
+    }
+  }
 
   // Returns whether this is an instance of k or an instance of a subclass of k
   inline bool is_a(Klass* k) const;
 
   // Returns the actual oop size of the object in machine words
@@ -106,10 +119,24 @@
 
   // Sometimes (for complicated concurrency-related reasons), it is useful
   // to be able to figure out the size of an object knowing its klass.
   inline size_t size_given_klass(Klass* klass);
 
+  // The following set of methods is used to access the mark-word and related
+  // properties when the object may be forwarded. Be careful where and when
+  // using this method. It assumes that the forwardee is installed in
+  // the header as a plain pointer (or self-forwarded). In particular,
+  // those methods can not deal with the sliding-forwarding that is used
+  // in Serial, G1 and Shenandoah full-GCs.
+private:
+  inline Klass*   forward_safe_klass_impl(markWord m) const;
+public:
+  inline Klass*   forward_safe_klass() const;
+  inline Klass*   forward_safe_klass(markWord m) const;
+  inline size_t   forward_safe_size();
+  inline void     forward_safe_init_mark();
+
   // type test operations (inlined in oop.inline.hpp)
   inline bool is_instance()    const;
   inline bool is_instanceRef() const;
   inline bool is_stackChunk()  const;
   inline bool is_array()       const;
@@ -256,20 +283,26 @@
   // garbage collection
   inline bool is_gc_marked() const;
 
   // Forward pointer operations for scavenge
   inline bool is_forwarded() const;
+  inline bool is_self_forwarded() const;
 
   inline void forward_to(oop p);
+  inline void forward_to_self();
 
   // Like "forward_to", but inserts the forwarding pointer atomically.
   // Exactly one thread succeeds in inserting the forwarding pointer, and
   // this call returns null for that thread; any other thread has the
   // value of the forwarding pointer returned and does not modify "this".
   inline oop forward_to_atomic(oop p, markWord compare, atomic_memory_order order = memory_order_conservative);
+  inline oop forward_to_self_atomic(markWord compare, atomic_memory_order order = memory_order_conservative);
 
   inline oop forwardee() const;
+  inline oop forwardee(markWord header) const;
+
+  inline void unset_self_forwarded();
 
   // Age of object during scavenge
   inline uint age() const;
   inline void incr_age();
 
@@ -309,20 +342,48 @@
 
   static bool has_klass_gap();
 
   // for code generation
   static int mark_offset_in_bytes()      { return (int)offset_of(oopDesc, _mark); }
-  static int klass_offset_in_bytes()     { return (int)offset_of(oopDesc, _metadata._klass); }
+  static int klass_offset_in_bytes()     {
+#ifdef _LP64
+    if (UseCompactObjectHeaders) {
+      constexpr int load_shift = markWord::klass_load_shift;
+      STATIC_ASSERT(load_shift % 8 == 0);
+      return mark_offset_in_bytes() + load_shift / 8;
+    } else
+#endif
+    {
+      return (int)offset_of(oopDesc, _metadata._klass);
+    }
+  }
   static int klass_gap_offset_in_bytes() {
     assert(has_klass_gap(), "only applicable to compressed klass pointers");
+    assert(!UseCompactObjectHeaders, "don't use klass_offset_in_bytes() with compact headers");
     return klass_offset_in_bytes() + sizeof(narrowKlass);
   }
 
+  static int base_offset_in_bytes() {
+#ifdef _LP64
+    if (UseCompactObjectHeaders) {
+      // With compact headers, the Klass* field is not used for the Klass*
+      // and is used for the object fields instead.
+      STATIC_ASSERT(sizeof(markWord) == 8);
+      return sizeof(markWord);
+    } else if (UseCompressedClassPointers) {
+      return sizeof(markWord) + sizeof(narrowKlass);
+    } else
+#endif
+    {
+      return sizeof(oopDesc);
+    }
+  }
+
   // for error reporting
   static void* load_oop_raw(oop obj, int offset);
 
-  DEBUG_ONLY(bool size_might_change();)
+  DEBUG_ONLY(bool size_might_change(Klass* klass);)
 };
 
 // An oopDesc is not initialized via a constructor.  Space is allocated in
 // the Java heap, and static functions provided here on HeapWord* are used
 // to fill in certain parts of that memory.  The allocated memory is then
