diff a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp
--- a/src/hotspot/cpu/x86/assembler_x86.cpp
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp
@@ -5730,10 +5730,14 @@
 
 void Assembler::rdtsc() {
   emit_int16(0x0F, 0x31);
 }
 
+void Assembler::rdtscp() {
+  emit_int24(0x0F, 0x01, (unsigned char)0xF9);
+}
+
 // copies data from [esi] to [edi] using rcx pointer sized words
 // generic
 void Assembler::rep_mov() {
   // REP
   // MOVSQ
diff a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp
--- a/src/hotspot/cpu/x86/assembler_x86.hpp
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp
@@ -2044,10 +2044,11 @@
   void rcpps(XMMRegister dst, XMMRegister src);
 
   void rcpss(XMMRegister dst, XMMRegister src);
 
   void rdtsc();
+  void rdtscp();
 
   void ret(int imm16);
 
   void roll(Register dst);
 
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
@@ -12640,10 +12640,36 @@
   format %{ "# TLS is in R15" %}
   ins_encode( /*empty encoding*/ );
   ins_pipe(ialu_reg_reg);
 %}
 
+instruct rdtsc(rax_RegL dst, rdx_RegL tmp) %{
+  match(Set dst (Timestamp));
+  effect(DEF dst, KILL tmp);
+
+  format %{ "RDTSC" %}
+  ins_encode %{
+    __ rdtsc();
+    __ shlptr(rdx, 32);
+    __ orptr(rax, rdx);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
+instruct rdtscp(rax_RegL dst, rdx_RegL tmp, rcx_RegL dead) %{
+  match(Set dst (TimestampSerial));
+  effect(DEF dst, KILL tmp, KILL dead);
+
+  format %{ "RDTSCP" %}
+  ins_encode %{
+    __ rdtscp();
+    __ shlptr(rdx, 32);
+    __ orptr(rax, rdx);
+  %}
+  ins_pipe(ialu_reg_reg);
+%}
+
 
 //----------PEEPHOLE RULES-----------------------------------------------------
 // These must follow all instruction definitions as they use the names
 // defined in the instructions definitions.
 //
diff a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp
--- a/src/hotspot/share/c1/c1_Compiler.cpp
+++ b/src/hotspot/share/c1/c1_Compiler.cpp
@@ -233,10 +233,12 @@
   case vmIntrinsics::_putCharStringU:
 #ifdef JFR_HAVE_INTRINSICS
   case vmIntrinsics::_counterTime:
 #endif
   case vmIntrinsics::_getObjectSize:
+  case vmIntrinsics::_shipilev_magic_sizeOf:
+  case vmIntrinsics::_shipilev_magic_addressOf:
     break;
   case vmIntrinsics::_blackhole:
     break;
   default:
     return false; // Intrinsics not on the previous list are not available.
diff a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp
@@ -1335,15 +1335,40 @@
 
   // Get the answer.
   __ move(new LIR_Address(klass, in_bytes(Klass::modifier_flags_offset()), T_INT), result);
 }
 
+void LIRGenerator::do_addressOf(Intrinsic* x) {
+  assert(x->number_of_arguments() == 1, "wrong type");
+  LIR_Opr reg = rlock_result(x);
+
+  LIRItem value(x->argument_at(0), this);
+  value.load_item();
+
+#ifdef _LP64
+  __ move(value.result(), reg, NULL);
+#else
+  LIR_Opr res = new_register(T_INT);
+  __ move(value.result(), res, NULL);
+  __ convert(Bytecodes::_i2l, res, reg);
+#endif
+}
+
+void LIRGenerator::do_sizeOf(Intrinsic* x) {
+  assert(x->number_of_arguments() == 1, "wrong type");
+  do_sizeOf_impl(x, 0);
+}
+
 void LIRGenerator::do_getObjectSize(Intrinsic* x) {
   assert(x->number_of_arguments() == 3, "wrong type");
+  do_sizeOf_impl(x, 2);
+}
+
+void LIRGenerator::do_sizeOf_impl(Intrinsic* x, int arg_idx) {
   LIR_Opr result_reg = rlock_result(x);
 
-  LIRItem value(x->argument_at(2), this);
+  LIRItem value(x->argument_at(arg_idx), this);
   value.load_item();
 
   LIR_Opr klass = new_register(T_METADATA);
   load_klass(value.result(), klass, nullptr);
   LIR_Opr layout = new_register(T_INT);
@@ -2963,10 +2988,12 @@
   case vmIntrinsics::_getClass:       do_getClass(x);      break;
   case vmIntrinsics::_getObjectSize:  do_getObjectSize(x); break;
   case vmIntrinsics::_currentCarrierThread: do_currentCarrierThread(x); break;
   case vmIntrinsics::_currentThread:  do_vthread(x);       break;
   case vmIntrinsics::_scopedValueCache: do_scopedValueCache(x); break;
+  case vmIntrinsics::_shipilev_magic_sizeOf:         do_sizeOf(x);        break;
+  case vmIntrinsics::_shipilev_magic_addressOf:      do_addressOf(x);     break;
 
   case vmIntrinsics::_dlog:           // fall through
   case vmIntrinsics::_dlog10:         // fall through
   case vmIntrinsics::_dabs:           // fall through
   case vmIntrinsics::_dsqrt:          // fall through
diff a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp
@@ -258,10 +258,12 @@
   void do_getObjectSize(Intrinsic* x);
   void do_currentCarrierThread(Intrinsic* x);
   void do_scopedValueCache(Intrinsic* x);
   void do_vthread(Intrinsic* x);
   void do_JavaThreadField(Intrinsic* x, ByteSize offset);
+  void do_sizeOf(Intrinsic* x);
+  void do_addressOf(Intrinsic* x);
   void do_FmaIntrinsic(Intrinsic* x);
   void do_MathIntrinsic(Intrinsic* x);
   void do_LibmIntrinsic(Intrinsic* x);
   void do_ArrayCopy(Intrinsic* x);
   void do_CompareAndSwap(Intrinsic* x, ValueType* type);
@@ -477,10 +479,12 @@
   void profile_arguments(ProfileCall* x);
   void profile_parameters(Base* x);
   void profile_parameters_at_call(ProfileCall* x);
   LIR_Opr mask_boolean(LIR_Opr array, LIR_Opr value, CodeEmitInfo*& null_check_info);
 
+  void do_sizeOf_impl(Intrinsic* x, int arg_idx);
+
  public:
   Compilation*  compilation() const              { return _compilation; }
   FrameMap*     frame_map() const                { return _compilation->frame_map(); }
   ciMethod*     method() const                   { return _method; }
   BlockBegin*   block() const                    { return _block; }
diff a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -5208,10 +5208,11 @@
   // Not yet: supers are done below to support the new subtype-checking fields
   ik->set_nonstatic_field_size(_field_info->_nonstatic_field_size);
   ik->set_has_nonstatic_fields(_field_info->_has_nonstatic_fields);
   assert(_fac != nullptr, "invariant");
   ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+  ik->set_nonstatic_oop_field_count(_fac->count[NONSTATIC_OOP]);
 
   // this transfers ownership of a lot of arrays from
   // the parser onto the InstanceKlass*
   apply_parsed_class_metadata(ik, _java_fields_count);
 
diff a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp
--- a/src/hotspot/share/classfile/vmIntrinsics.hpp
+++ b/src/hotspot/share/classfile/vmIntrinsics.hpp
@@ -596,10 +596,22 @@
   do_intrinsic(_notifyJvmtiVThreadEnd, java_lang_VirtualThread, notifyJvmtiEnd_name, void_method_signature, F_RN)       \
   do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN)     \
   do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \
   do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \
                                                                                                                         \
+  do_intrinsic(_shipilev_magic_timestamp,             net_shipilev_Magic, timestamp_name,            void_long_signature,   F_SN) \
+    do_name(timestamp_name,             "timestamp")                                                                              \
+  do_intrinsic(_shipilev_magic_timestamp_serial,      net_shipilev_Magic, timestampSerial_name,      void_long_signature,   F_SN) \
+    do_name(timestampSerial_name,       "timestampSerial")                                                                        \
+  do_intrinsic(_shipilev_magic_sizeOf,                net_shipilev_Magic, sizeOf_name,               object_long_signature, F_SN) \
+    do_name(sizeOf_name,                "sizeOf0")                                                                                \
+  do_intrinsic(_shipilev_magic_addressOf,             net_shipilev_Magic, addressOf_name,            object_long_signature, F_SN) \
+    do_name(addressOf_name,             "addressOf0")                                                                             \
+  do_intrinsic(_shipilev_magic_getReferencedObjects,  net_shipilev_Magic, getReferencedObjects_name, object_object_array_int_signature, F_SN)  \
+    do_name(getReferencedObjects_name,  "getReferencedObjects")                                                                  \
+    do_class(net_shipilev_Magic,        "net/shipilev/Magic")                                                           \
+                                                                                                                        \
   /* support for UnsafeConstants */                                                                                     \
   do_class(jdk_internal_misc_UnsafeConstants,      "jdk/internal/misc/UnsafeConstants")                                 \
                                                                                                                         \
   /* support for Unsafe */                                                                                              \
   do_class(jdk_internal_misc_Unsafe,               "jdk/internal/misc/Unsafe")                                          \
diff a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp
--- a/src/hotspot/share/classfile/vmSymbols.hpp
+++ b/src/hotspot/share/classfile/vmSymbols.hpp
@@ -155,10 +155,11 @@
   template(sun_net_www_ParseUtil,                     "sun/net/www/ParseUtil")                    \
   template(java_util_Iterator,                        "java/util/Iterator")                       \
   template(java_lang_Record,                          "java/lang/Record")                         \
   template(sun_instrument_InstrumentationImpl,        "sun/instrument/InstrumentationImpl")       \
   template(sun_invoke_util_ValueConversions,          "sun/invoke/util/ValueConversions")         \
+  template(java_lang_Runtime,                         "java/lang/Runtime")                        \
                                                                                                   \
   template(jdk_internal_loader_NativeLibraries,       "jdk/internal/loader/NativeLibraries")      \
   template(jdk_internal_loader_BuiltinClassLoader,    "jdk/internal/loader/BuiltinClassLoader")   \
   template(jdk_internal_loader_ClassLoaders_AppClassLoader,      "jdk/internal/loader/ClassLoaders$AppClassLoader")      \
   template(jdk_internal_loader_ClassLoaders_PlatformClassLoader, "jdk/internal/loader/ClassLoaders$PlatformClassLoader") \
@@ -594,12 +595,14 @@
   template(stackchunk_signature,                      "Ljdk/internal/vm/StackChunk;")             \
   template(vthread_signature,                         "Ljava/lang/VirtualThread;")                \
   template(object_void_signature,                     "(Ljava/lang/Object;)V")                    \
   template(object_int_signature,                      "(Ljava/lang/Object;)I")                    \
   template(long_object_long_signature,                "(JLjava/lang/Object;)J")                   \
+  template(object_long_signature,                     "(Ljava/lang/Object;)J")                    \
   template(object_boolean_signature,                  "(Ljava/lang/Object;)Z")                    \
   template(object_object_signature,                   "(Ljava/lang/Object;)Ljava/lang/Object;")   \
+  template(object_object_array_int_signature,         "(Ljava/lang/Object;[Ljava/lang/Object;)I") \
   template(string_void_signature,                     "(Ljava/lang/String;)V")                    \
   template(string_int_signature,                      "(Ljava/lang/String;)I")                    \
   template(string_byte_array_signature,               "(Ljava/lang/String;)[B")                   \
   template(string_bool_byte_array_signature,          "(Ljava/lang/String;Z)[B")                  \
   template(throwable_signature,                       "Ljava/lang/Throwable;")                    \
diff a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.cpp
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.cpp
@@ -22,24 +22,40 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderDataGraph.hpp"
+#include "code/codeCache.hpp"
 #include "gc/epsilon/epsilonHeap.hpp"
 #include "gc/epsilon/epsilonInitLogger.hpp"
 #include "gc/epsilon/epsilonMemoryPool.hpp"
 #include "gc/epsilon/epsilonThreadLocalData.hpp"
 #include "gc/shared/gcArguments.hpp"
+#include "gc/shared/gcLocker.inline.hpp"
+#include "gc/shared/gcTraceTime.inline.hpp"
 #include "gc/shared/locationPrinter.inline.hpp"
+#include "gc/shared/markBitMap.inline.hpp"
+#include "gc/shared/strongRootsScope.hpp"
+#include "gc/shared/preservedMarks.inline.hpp"
+#include "gc/shared/oopStorageSet.inline.hpp"
 #include "logging/log.hpp"
+#include "nmt/memTracker.hpp"
 #include "memory/allocation.hpp"
-#include "memory/allocation.inline.hpp"
+#include "memory/iterator.inline.hpp"
 #include "memory/metaspaceUtils.hpp"
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
+#include "oops/compressedOops.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/globals.hpp"
+#include "runtime/thread.hpp"
+#include "runtime/threads.hpp"
+#include "runtime/vmOperations.hpp"
+#include "runtime/vmThread.hpp"
+#include "services/management.hpp"
+#include "utilities/stack.inline.hpp"
 
 jint EpsilonHeap::initialize() {
   size_t align = HeapAlignment;
   size_t init_byte_size = align_up(InitialHeapSize, align);
   size_t max_byte_size  = align_up(MaxHeapSize, align);
@@ -67,10 +83,23 @@
   _last_heap_print = 0;
 
   // Install barrier set
   BarrierSet::set_barrier_set(new EpsilonBarrierSet());
 
+  size_t bitmap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size();
+  size_t _bitmap_size = MarkBitMap::compute_size(heap_rs.size());
+  _bitmap_size = align_up(_bitmap_size, bitmap_page_size);
+
+  // Initialize marking bitmap, but not commit it yet
+  if (EpsilonSlidingGC) {
+    ReservedSpace bitmap(_bitmap_size, bitmap_page_size);
+    MemTracker::record_virtual_memory_type(bitmap.base(), mtGC);
+    _bitmap_region = MemRegion((HeapWord *) bitmap.base(), bitmap.size() / HeapWordSize);
+    MemRegion heap_region = MemRegion((HeapWord *) heap_rs.base(), heap_rs.size() / HeapWordSize);
+    _bitmap.initialize(heap_region, _bitmap_region);
+  }
+
   // All done, print out the configuration
   EpsilonInitLogger::print();
 
   return JNI_OK;
 }
@@ -232,11 +261,11 @@
                   ergo_tlab * HeapWordSize / K,
                   size * HeapWordSize / K);
   }
 
   // All prepared, let's do it!
-  HeapWord* res = allocate_work(size);
+  HeapWord* res = allocate_or_collect_work(size);
 
   if (res != nullptr) {
     // Allocation successful
     *actual_size = size;
     if (EpsilonElasticTLABDecay) {
@@ -256,11 +285,11 @@
   return res;
 }
 
 HeapWord* EpsilonHeap::mem_allocate(size_t size, bool *gc_overhead_limit_was_exceeded) {
   *gc_overhead_limit_was_exceeded = false;
-  return allocate_work(size);
+  return allocate_or_collect_work(size);
 }
 
 HeapWord* EpsilonHeap::allocate_loaded_archive_space(size_t size) {
   // Cannot use verbose=true because Metaspace is not initialized
   return allocate_work(size, /* verbose = */false);
@@ -278,11 +307,19 @@
       log_info(gc)("GC request for \"%s\" is handled", GCCause::to_string(cause));
       MetaspaceGC::compute_new_size();
       print_metaspace_info();
       break;
     default:
-      log_info(gc)("GC request for \"%s\" is ignored", GCCause::to_string(cause));
+      if (EpsilonSlidingGC) {
+        if (SafepointSynchronize::is_at_safepoint()) {
+          entry_collect(cause);
+        } else {
+          vmentry_collect(cause);
+        }
+      } else {
+        log_info(gc)("GC request for \"%s\" is ignored", GCCause::to_string(cause));
+      }
   }
   _monitoring_support->update_counters();
 }
 
 void EpsilonHeap::do_full_collection(bool clear_all_soft_refs) {
@@ -322,13 +359,14 @@
   if (reserved != 0) {
     log_info(gc)("Heap: " SIZE_FORMAT "%s reserved, " SIZE_FORMAT "%s (%.2f%%) committed, "
                  SIZE_FORMAT "%s (%.2f%%) used",
             byte_size_in_proper_unit(reserved),  proper_unit_for_byte_size(reserved),
             byte_size_in_proper_unit(committed), proper_unit_for_byte_size(committed),
-            committed * 100.0 / reserved,
+            percent_of(committed, reserved),
             byte_size_in_proper_unit(used),      proper_unit_for_byte_size(used),
-            used * 100.0 / reserved);
+            percent_of(used, reserved)
+    );
   } else {
     log_info(gc)("Heap: no reliable data");
   }
 }
 
@@ -341,12 +379,491 @@
   if (reserved != 0) {
     log_info(gc, metaspace)("Metaspace: " SIZE_FORMAT "%s reserved, " SIZE_FORMAT "%s (%.2f%%) committed, "
                             SIZE_FORMAT "%s (%.2f%%) used",
             byte_size_in_proper_unit(reserved),  proper_unit_for_byte_size(reserved),
             byte_size_in_proper_unit(committed), proper_unit_for_byte_size(committed),
-            committed * 100.0 / reserved,
+            percent_of(committed, reserved),
             byte_size_in_proper_unit(used),      proper_unit_for_byte_size(used),
-            used * 100.0 / reserved);
+            percent_of(used, reserved)
+    );
   } else {
     log_info(gc, metaspace)("Metaspace: no reliable data");
   }
 }
+
+// ------------------ EXPERIMENTAL MARK-COMPACT -------------------------------
+//
+// This implements a trivial Lisp2-style sliding collector:
+//     https://en.wikipedia.org/wiki/Mark-compact_algorithm#LISP2_algorithm
+//
+// The goal for this implementation is to be as simple as possible, ignoring
+// non-trivial performance optimizations. This collector does not implement
+// reference processing: no soft/weak/phantom/finalizeable references are ever
+// cleared. It also does not implement class unloading and other runtime
+// cleanups.
+//
+
+// VM operation that executes collection cycle under safepoint
+class VM_EpsilonCollect: public VM_Operation {
+private:
+  const GCCause::Cause _cause;
+  EpsilonHeap* const _heap;
+  static size_t _req_id;
+public:
+  VM_EpsilonCollect(GCCause::Cause cause) : VM_Operation(),
+                                            _cause(cause),
+                                            _heap(EpsilonHeap::heap()) {};
+
+  VM_Operation::VMOp_Type type() const { return VMOp_EpsilonCollect; }
+  const char* name()             const { return "Epsilon Collection"; }
+
+  virtual bool doit_prologue() {
+    size_t id = Atomic::load_acquire(&_req_id);
+
+    // Need to take the Heap lock before managing backing storage.
+    Heap_lock->lock();
+
+    // Heap lock also naturally serializes GC requests, and allows us to coalesce
+    // back-to-back GC requests from many threads. Avoid the consecutive GCs
+    // if we started waiting when other GC request was being handled.
+    if (id < Atomic::load_acquire(&_req_id)) {
+      Heap_lock->unlock();
+      return false;
+    }
+
+    // No contenders. Start handling a new GC request.
+    Atomic::inc(&_req_id);
+    return true;
+  }
+
+  virtual void doit() {
+    _heap->entry_collect(_cause);
+  }
+
+  virtual void doit_epilogue() {
+    Heap_lock->unlock();
+  }
+};
+
+size_t VM_EpsilonCollect::_req_id = 0;
+
+void EpsilonHeap::vmentry_collect(GCCause::Cause cause) {
+  VM_EpsilonCollect vmop(cause);
+  VMThread::execute(&vmop);
+}
+
+HeapWord* EpsilonHeap::allocate_or_collect_work(size_t size, bool verbose) {
+  HeapWord* res = allocate_work(size);
+  if (res == NULL && EpsilonSlidingGC && EpsilonImplicitGC) {
+    vmentry_collect(GCCause::_allocation_failure);
+    // TODO: This looks incorrect
+    GCLocker::stall_until_clear();
+    res = allocate_work(size, verbose);
+  }
+  return res;
+}
+
+typedef Stack<oop, mtGC> EpsilonMarkStack;
+
+void EpsilonHeap::process_roots(OopClosure* cl) {
+  // Need to tell runtime we are about to walk the roots with 1 thread
+  StrongRootsScope scope(1);
+
+  // Need to adapt oop closure for some special root types.
+  CLDToOopClosure clds(cl, ClassLoaderData::_claim_none);
+  MarkingCodeBlobClosure blobs(cl, CodeBlobToOopClosure::FixRelocations, true); // TODO: Keepalive?
+
+  // Strong roots: always reachable roots
+
+  // General strong roots that are registered in OopStorages
+  for (auto id : EnumRange<OopStorageSet::StrongId>()) {
+    OopStorageSet::storage(id)->oops_do(cl);
+  }
+
+  // Subsystems that still have their own root handling
+  ClassLoaderDataGraph::cld_do(&clds);
+  Threads::possibly_parallel_oops_do(false, cl, &blobs);
+
+  {
+    MutexLocker lock(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+    CodeCache::blobs_do(&blobs);
+  }
+
+  // Weak roots: in an advanced GC these roots would be skipped during
+  // the initial scan, and walked again after the marking is complete.
+  // Then, we could discover which roots are not actually pointing
+  // to surviving Java objects, and either clean the roots, or mark them.
+  // Current simple implementation does not handle weak roots specially,
+  // and therefore, we mark through them as if they are strong roots.
+  for (auto id : EnumRange<OopStorageSet::WeakId>()) {
+    OopStorageSet::storage(id)->oops_do(cl);
+  }
+}
+
+// Walk the marking bitmap and call object closure on every marked object.
+// This is much faster that walking a (very sparse) parsable heap, but it
+// takes up to 1/64-th of heap size for the bitmap.
+void EpsilonHeap::walk_bitmap(ObjectClosure* cl) {
+   HeapWord* limit = _space->top();
+   HeapWord* addr = _bitmap.get_next_marked_addr(_space->bottom(), limit);
+   while (addr < limit) {
+     oop obj = cast_to_oop(addr);
+     assert(_bitmap.is_marked(obj), "sanity");
+     cl->do_object(obj);
+     addr += 1;
+     if (addr < limit) {
+       addr = _bitmap.get_next_marked_addr(addr, limit);
+     }
+   }
+}
+
+class EpsilonScanOopClosure : public BasicOopIterateClosure {
+private:
+  EpsilonMarkStack* const _stack;
+  MarkBitMap* const _bitmap;
+
+  template <class T>
+  void do_oop_work(T* p) {
+    // p is the pointer to memory location where oop is, load the value
+    // from it, unpack the compressed reference, if needed:
+    T o = RawAccess<>::oop_load(p);
+    if (!CompressedOops::is_null(o)) {
+      oop obj = CompressedOops::decode_not_null(o);
+
+      // Object is discovered. See if it is marked already. If not,
+      // mark and push it on mark stack for further traversal. Non-atomic
+      // check and set would do, as this closure is called by single thread.
+      if (!_bitmap->is_marked(obj)) {
+        _bitmap->mark(obj);
+        _stack->push(obj);
+      }
+    }
+  }
+
+public:
+  EpsilonScanOopClosure(EpsilonMarkStack* stack, MarkBitMap* bitmap) :
+                        _stack(stack), _bitmap(bitmap) {}
+  virtual void do_oop(oop* p)       { do_oop_work(p); }
+  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+};
+
+class EpsilonCalcNewLocationObjectClosure : public ObjectClosure {
+private:
+  HeapWord* _compact_point;
+  PreservedMarks* const _preserved_marks;
+
+public:
+  EpsilonCalcNewLocationObjectClosure(HeapWord* start, PreservedMarks* pm) :
+                                      _compact_point(start),
+                                      _preserved_marks(pm) {}
+
+  void do_object(oop obj) {
+    // Record the new location of the object: it is current compaction point.
+    // If object stays at the same location (which is true for objects in
+    // dense prefix, that we would normally get), do not bother recording the
+    // move, letting downstream code ignore it.
+    if (obj != cast_to_oop(_compact_point)) {
+      markWord mark = obj->mark();
+      _preserved_marks->push_if_necessary(obj, mark);
+      obj->forward_to(cast_to_oop(_compact_point));
+    }
+    _compact_point += obj->size();
+  }
+
+  HeapWord* compact_point() {
+    return _compact_point;
+  }
+};
+
+class EpsilonAdjustPointersOopClosure : public BasicOopIterateClosure {
+private:
+  template <class T>
+  void do_oop_work(T* p) {
+    // p is the pointer to memory location where oop is, load the value
+    // from it, unpack the compressed reference, if needed:
+    T o = RawAccess<>::oop_load(p);
+    if (!CompressedOops::is_null(o)) {
+      oop obj = CompressedOops::decode_not_null(o);
+
+      // Rewrite the current pointer to the object with its forwardee.
+      // Skip the write if update is not needed.
+      if (obj->is_forwarded()) {
+        oop fwd = obj->forwardee();
+        assert(fwd != NULL, "just checking");
+        RawAccess<>::oop_store(p, fwd);
+      }
+    }
+  }
+
+public:
+  virtual void do_oop(oop* p)       { do_oop_work(p); }
+  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+};
+
+class EpsilonAdjustPointersObjectClosure : public ObjectClosure {
+private:
+  EpsilonAdjustPointersOopClosure _cl;
+public:
+  void do_object(oop obj) {
+    // Apply the updates to all references reachable from current object:
+    obj->oop_iterate(&_cl);
+  }
+};
+
+class EpsilonMoveObjectsObjectClosure : public ObjectClosure {
+private:
+  size_t _moved;
+public:
+  EpsilonMoveObjectsObjectClosure() : ObjectClosure(), _moved(0) {}
+
+  void do_object(oop obj) {
+    // Copy the object to its new location, if needed. This is final step,
+    // so we have to re-initialize its new mark word, dropping the forwardee
+    // data from it.
+    if (obj->is_forwarded()) {
+      oop fwd = obj->forwardee();
+      assert(fwd != NULL, "just checking");
+      Copy::aligned_conjoint_words(cast_from_oop<HeapWord*>(obj), cast_from_oop<HeapWord*>(fwd), obj->size());
+      fwd->init_mark();
+      _moved++;
+    }
+  }
+
+  size_t moved() {
+    return _moved;
+  }
+};
+
+class EpsilonVerifyOopClosure : public BasicOopIterateClosure {
+private:
+  EpsilonHeap* const _heap;
+  EpsilonMarkStack* const _stack;
+  MarkBitMap* const _bitmap;
+
+  template <class T>
+  void do_oop_work(T* p) {
+    T o = RawAccess<>::oop_load(p);
+    if (!CompressedOops::is_null(o)) {
+      oop obj = CompressedOops::decode_not_null(o);
+      if (!_bitmap->is_marked(obj)) {
+        _bitmap->mark(obj);
+
+        guarantee(_heap->is_in(obj),        "Is in heap: "   PTR_FORMAT, p2i(obj));
+        guarantee(oopDesc::is_oop(obj),     "Is an object: " PTR_FORMAT, p2i(obj));
+        guarantee(!obj->mark().is_marked(), "Mark is gone: " PTR_FORMAT, p2i(obj));
+
+        _stack->push(obj);
+      }
+    }
+  }
+
+public:
+  EpsilonVerifyOopClosure(EpsilonMarkStack* stack, MarkBitMap* bitmap) :
+    _heap(EpsilonHeap::heap()), _stack(stack), _bitmap(bitmap) {}
+  virtual void do_oop(oop* p)       { do_oop_work(p); }
+  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
+};
+
+void EpsilonHeap::entry_collect(GCCause::Cause cause) {
+  if (GCLocker::check_active_before_gc()) {
+    return;
+  }
+
+  GCIdMark mark;
+  GCTraceTime(Info, gc) time("Lisp2-style Mark-Compact", NULL, cause, true);
+
+  // Some statistics, for fun and profit:
+  size_t stat_reachable_roots = 0;
+  size_t stat_reachable_heap = 0;
+  size_t stat_moved = 0;
+  size_t stat_preserved_marks = 0;
+
+  {
+    GCTraceTime(Info, gc) time("Step 0: Prologue", NULL);
+
+    // Commit marking bitmap memory. There are several upsides of doing this
+    // before the cycle: no memory is taken if GC is not happening, the memory
+    // is "cleared" on first touch, and untouched parts of bitmap are mapped
+    // to zero page, boosting performance on sparse heaps.
+    if (!os::commit_memory((char*)_bitmap_region.start(), _bitmap_region.byte_size(), false)) {
+      log_warning(gc)("Could not commit native memory for marking bitmap, GC failed");
+      return;
+    }
+
+    // We do not need parsable heap for this algorithm to work, but we want
+    // threads to give up their TLABs.
+    ensure_parsability(true);
+
+#if COMPILER2_OR_JVMCI
+    // Derived pointers would be re-discovered during the mark.
+    // Clear and activate the table for them.
+    DerivedPointerTable::clear();
+#endif
+  }
+
+  {
+    GCTraceTime(Info, gc) time("Step 1: Mark", NULL);
+
+    // Marking stack and the closure that does most of the work. The closure
+    // would scan the outgoing references, mark them, and push newly-marked
+    // objects to stack for further processing.
+    EpsilonMarkStack stack;
+    EpsilonScanOopClosure cl(&stack, &_bitmap);
+
+    // Seed the marking with roots.
+    process_roots(&cl);
+    stat_reachable_roots = stack.size();
+
+    // Scan the rest of the heap until we run out of objects. Termination is
+    // guaranteed, because all reachable objects would be marked eventually.
+    while (!stack.is_empty()) {
+      oop obj = stack.pop();
+      obj->oop_iterate(&cl);
+      stat_reachable_heap++;
+    }
+
+#if COMPILER2_OR_JVMCI
+    // No more derived pointers discovered after marking is done.
+    DerivedPointerTable::set_active(false);
+#endif
+  }
+
+  // We are going to store forwarding information (where the new copy resides)
+  // in mark words. Some of those mark words need to be carefully preserved.
+  // This is an utility that maintains the list of those special mark words.
+  PreservedMarks preserved_marks;
+
+  // New top of the allocated space.
+  HeapWord* new_top;
+
+  {
+    GCTraceTime(Info, gc) time("Step 2: Calculate new locations", NULL);
+
+    // Walk all alive objects, compute their new addresses and store those
+    // addresses in mark words. Optionally preserve some marks.
+    EpsilonCalcNewLocationObjectClosure cl(_space->bottom(), &preserved_marks);
+    walk_bitmap(&cl);
+
+    // After addresses are calculated, we know the new top for the allocated
+    // space. We cannot set it just yet, because some asserts check that objects
+    // are "in heap" based on current "top".
+    new_top = cl.compact_point();
+
+    stat_preserved_marks = preserved_marks.size();
+  }
+
+  {
+    GCTraceTime(Info, gc) time("Step 3: Adjust pointers", NULL);
+
+    // Walk all alive objects _and their reference fields_, and put "new
+    // addresses" there. We know the new addresses from the forwarding data
+    // in mark words. Take care of the heap objects first.
+    EpsilonAdjustPointersObjectClosure cl;
+    walk_bitmap(&cl);
+
+    // Now do the same, but for all VM roots, which reference the objects on
+    // their own: their references should also be updated.
+    EpsilonAdjustPointersOopClosure cli;
+    process_roots(&cli);
+
+    // Finally, make sure preserved marks know the objects are about to move.
+    preserved_marks.adjust_during_full_gc();
+  }
+
+  {
+    GCTraceTime(Info, gc) time("Step 4: Move objects", NULL);
+
+    // Move all alive objects to their new locations. All the references are
+    // already adjusted at previous step.
+    EpsilonMoveObjectsObjectClosure cl;
+    walk_bitmap(&cl);
+    stat_moved = cl.moved();
+
+    // Now we moved all objects to their relevant locations, we can retract
+    // the "top" of the allocation space to the end of the compacted prefix.
+    _space->set_top(new_top);
+  }
+
+  {
+    GCTraceTime(Info, gc) time("Step 5: Epilogue", NULL);
+
+    // Restore all special mark words.
+    preserved_marks.restore();
+
+#if COMPILER2_OR_JVMCI
+    // Tell the rest of runtime we have finished the GC.
+    DerivedPointerTable::update_pointers();
+#endif
+
+    // Verification code walks entire heap and verifies nothing is broken.
+    if (EpsilonVerify) {
+      // The basic implementation turns heap into entirely parsable one with
+      // only alive objects, which mean we could just walked the heap object
+      // by object and verify it. But, it would be inconvenient for verification
+      // to assume heap has only alive objects. Any future change that leaves
+      // at least one dead object with dead outgoing references would fail the
+      // verification. Therefore, it makes more sense to mark through the heap
+      // again, not assuming objects are all alive.
+      EpsilonMarkStack stack;
+      EpsilonVerifyOopClosure cl(&stack, &_bitmap);
+
+      _bitmap.clear();
+
+      // Verify all roots are correct, and that we have the same number of
+      // object reachable from roots.
+      process_roots(&cl);
+
+      size_t verified_roots = stack.size();
+      guarantee(verified_roots == stat_reachable_roots,
+                "Verification discovered " SIZE_FORMAT " roots out of " SIZE_FORMAT,
+                verified_roots, stat_reachable_roots);
+
+      // Verify the rest of the heap is correct, and that we have the same
+      // number of objects reachable from heap.
+      size_t verified_heap = 0;
+      while (!stack.is_empty()) {
+        oop obj = stack.pop();
+        obj->oop_iterate(&cl);
+        verified_heap++;
+      }
+
+      guarantee(verified_heap == stat_reachable_heap,
+                "Verification discovered " SIZE_FORMAT " heap objects out of " SIZE_FORMAT,
+                verified_heap, stat_reachable_heap);
+
+      // Ask parts of runtime to verify themselves too
+      Universe::verify("Epsilon");
+    }
+
+    // Marking bitmap is not needed anymore
+    if (!os::uncommit_memory((char*)_bitmap_region.start(), _bitmap_region.byte_size())) {
+      log_warning(gc)("Could not uncommit native memory for marking bitmap");
+    }
+
+    // Return all memory back if so requested. On large heaps, this would
+    // take a while.
+    if (EpsilonUncommit) {
+      _virtual_space.shrink_by((_space->end() - new_top) * HeapWordSize);
+      _space->set_end((HeapWord*)_virtual_space.high());
+    }
+  }
+
+  size_t stat_reachable = stat_reachable_roots + stat_reachable_heap;
+  log_info(gc)("GC Stats: " SIZE_FORMAT " (%.2f%%) reachable from roots, " SIZE_FORMAT " (%.2f%%) reachable from heap, "
+               SIZE_FORMAT " (%.2f%%) moved, " SIZE_FORMAT " (%.2f%%) markwords preserved",
+               stat_reachable_roots, percent_of(stat_reachable_roots, stat_reachable),
+               stat_reachable_heap,  percent_of(stat_reachable_heap,  stat_reachable),
+               stat_moved,           percent_of(stat_moved,           stat_reachable),
+               stat_preserved_marks, percent_of(stat_preserved_marks, stat_reachable)
+  );
+
+  print_heap_info(used());
+  print_metaspace_info();
+}
+
+void EpsilonHeap::pin_object(JavaThread* thread, oop obj) {
+  GCLocker::lock_critical(thread);
+}
+
+void EpsilonHeap::unpin_object(JavaThread* thread, oop obj) {
+  GCLocker::unlock_critical(thread);
+}
diff a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
@@ -27,10 +27,11 @@
 #define SHARE_GC_EPSILON_EPSILONHEAP_HPP
 
 #include "gc/epsilon/epsilonBarrierSet.hpp"
 #include "gc/epsilon/epsilonMonitoringSupport.hpp"
 #include "gc/shared/collectedHeap.hpp"
+#include "gc/shared/markBitMap.hpp"
 #include "gc/shared/softRefPolicy.hpp"
 #include "gc/shared/space.hpp"
 #include "memory/virtualspace.hpp"
 #include "services/memoryManager.hpp"
 
@@ -47,10 +48,12 @@
   size_t _step_counter_update;
   size_t _step_heap_print;
   int64_t _decay_time_ns;
   volatile size_t _last_counter_update;
   volatile size_t _last_heap_print;
+  MemRegion  _bitmap_region;
+  MarkBitMap _bitmap;
 
 public:
   static EpsilonHeap* heap();
 
   EpsilonHeap() :
@@ -90,10 +93,11 @@
     return used() == capacity();
   }
 
   // Allocation
   HeapWord* allocate_work(size_t size, bool verbose = true);
+  HeapWord* allocate_or_collect_work(size_t size, bool verbose = true);
   HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override;
   HeapWord* allocate_new_tlab(size_t min_size,
                               size_t requested_size,
                               size_t* actual_size) override;
 
@@ -108,12 +112,12 @@
 
   // Heap walking support
   void object_iterate(ObjectClosure* cl) override;
 
   // Object pinning support: every object is implicitly pinned
-  void pin_object(JavaThread* thread, oop obj) override { }
-  void unpin_object(JavaThread* thread, oop obj) override { }
+  void pin_object(JavaThread* thread, oop obj) override;
+  void unpin_object(JavaThread* thread, oop obj) override;
 
   // No support for block parsing.
   HeapWord* block_start(const void* addr) const { return nullptr;  }
   bool block_is_obj(const HeapWord* addr) const { return false; }
 
@@ -138,12 +142,19 @@
 
   void print_on(outputStream* st) const override;
   void print_tracing_info() const override;
   bool print_location(outputStream* st, void* addr) const override;
 
+  void entry_collect(GCCause::Cause cause);
+
 private:
   void print_heap_info(size_t used) const;
   void print_metaspace_info() const;
 
+  void vmentry_collect(GCCause::Cause cause);
+
+  void process_roots(OopClosure* cl);
+  void walk_bitmap(ObjectClosure* cl);
+
 };
 
 #endif // SHARE_GC_EPSILON_EPSILONHEAP_HPP
diff a/src/hotspot/share/gc/epsilon/epsilon_globals.hpp b/src/hotspot/share/gc/epsilon/epsilon_globals.hpp
--- a/src/hotspot/share/gc/epsilon/epsilon_globals.hpp
+++ b/src/hotspot/share/gc/epsilon/epsilon_globals.hpp
@@ -84,10 +84,23 @@
           range(1, max_intx)                                                \
                                                                             \
   product(size_t, EpsilonMinHeapExpand, 128 * M, EXPERIMENTAL,              \
           "Min expansion step for heap. Larger value improves performance " \
           "at the potential expense of memory waste.")                      \
-          range(1, max_intx)
+          range(1, max_intx)                                                \
+                                                                            \
+  product(bool, EpsilonSlidingGC, false, EXPERIMENTAL,                      \
+          "Actually does sliding mark-compact GC.")                         \
+                                                                            \
+  product(bool, EpsilonImplicitGC, true, EXPERIMENTAL,                      \
+          "Does GC on implicit GC requests, e.g. for allocation failure.")  \
+                                                                            \
+  product(bool, EpsilonUncommit, false, EXPERIMENTAL,                       \
+          "Uncommits all unneeded memory after GC.")                        \
+                                                                            \
+  product(bool, EpsilonVerify, false, EXPERIMENTAL,                         \
+          "Does the additional GC verification step.")                      \
+                                                                            \
 
 // end of GC_EPSILON_FLAGS
 
 #endif // SHARE_GC_EPSILON_EPSILON_GLOBALS_HPP
diff a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp
--- a/src/hotspot/share/oops/instanceKlass.hpp
+++ b/src/hotspot/share/oops/instanceKlass.hpp
@@ -221,10 +221,12 @@
   // The NestHost attribute. The class info index for the class
   // that is the nest-host of this class. This data has not been validated.
   u2              _nest_host_index;
   u2              _this_class_index;        // constant pool entry
   u2              _static_oop_field_count;  // number of static oop fields in this klass
+  u2              _nonstatic_oop_field_count;// number of non-static oop fields in this klass
+  u2              _java_fields_count;       // The number of declared Java fields
 
   volatile u2     _idnum_allocated_count;   // JNI/JVMTI: increments with the addition of methods, old ids don't change
 
   volatile ClassState _init_state;          // state of class
 
@@ -337,10 +339,13 @@
   void set_static_field_size(int size)     { _static_field_size = size; }
 
   int static_oop_field_count() const       { return (int)_static_oop_field_count; }
   void set_static_oop_field_count(u2 size) { _static_oop_field_count = size; }
 
+  int nonstatic_oop_field_count() const       { return (int)_nonstatic_oop_field_count; }
+  void set_nonstatic_oop_field_count(u2 size) { _nonstatic_oop_field_count = size; }
+
   // Java itable
   int  itable_length() const               { return _itable_len; }
   void set_itable_length(int len)          { _itable_len = len; }
 
   // array klasses
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
@@ -786,10 +786,12 @@
   case vmIntrinsics::_profileBoolean:
   case vmIntrinsics::_isCompileConstant:
   case vmIntrinsics::_Preconditions_checkIndex:
   case vmIntrinsics::_Preconditions_checkLongIndex:
   case vmIntrinsics::_getObjectSize:
+  case vmIntrinsics::_shipilev_magic_sizeOf:
+  case vmIntrinsics::_shipilev_magic_addressOf:
     break;
   case vmIntrinsics::_VectorCompressExpand:
   case vmIntrinsics::_VectorUnaryOp:
   case vmIntrinsics::_VectorBinaryOp:
   case vmIntrinsics::_VectorTernaryOp:
@@ -822,11 +824,14 @@
   case vmIntrinsics::_notifyJvmtiVThreadMount:
   case vmIntrinsics::_notifyJvmtiVThreadUnmount:
   case vmIntrinsics::_notifyJvmtiVThreadHideFrames:
 #endif
     break;
-
+  case vmIntrinsics::_shipilev_magic_timestamp:
+    return Matcher::match_rule_supported(Op_Timestamp);
+  case vmIntrinsics::_shipilev_magic_timestamp_serial:
+    return Matcher::match_rule_supported(Op_TimestampSerial);
   default:
     return false;
   }
   return true;
 }
diff a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp
--- a/src/hotspot/share/opto/classes.hpp
+++ b/src/hotspot/share/opto/classes.hpp
@@ -359,10 +359,12 @@
 macro(SubF)
 macro(SubI)
 macro(SubL)
 macro(TailCall)
 macro(TailJump)
+macro(Timestamp)
+macro(TimestampSerial)
 macro(MacroLogicV)
 macro(ThreadLocal)
 macro(Unlock)
 macro(URShiftB)
 macro(URShiftS)
diff a/src/hotspot/share/opto/connode.hpp b/src/hotspot/share/opto/connode.hpp
--- a/src/hotspot/share/opto/connode.hpp
+++ b/src/hotspot/share/opto/connode.hpp
@@ -151,8 +151,22 @@
     virtual int Opcode() const;
     virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM;}
     virtual uint ideal_reg() const { return Op_RegP; }
 };
 
+class TimestampNode : public Node {
+public:
+  TimestampNode(Node* ctrl) : Node(ctrl) {}
+    virtual int Opcode() const;
+    virtual const Type *bottom_type() const { return TypeLong::LONG;}
+    virtual uint ideal_reg() const { return Op_RegL; }
+};
 
+class TimestampSerialNode : public Node {
+public:
+  TimestampSerialNode(Node* ctrl) : Node(ctrl) {}
+    virtual int Opcode() const;
+    virtual const Type *bottom_type() const { return TypeLong::LONG;}
+    virtual uint ideal_reg() const { return Op_RegL; }
+};
 
 #endif // SHARE_OPTO_CONNODE_HPP
diff a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -750,10 +750,19 @@
     return inline_getObjectSize();
 
   case vmIntrinsics::_blackhole:
     return inline_blackhole();
 
+  case vmIntrinsics::_shipilev_magic_timestamp:
+    return inline_timestamp(false);
+  case vmIntrinsics::_shipilev_magic_timestamp_serial:
+    return inline_timestamp(true);
+  case vmIntrinsics::_shipilev_magic_sizeOf:
+    return inline_sizeOf();
+  case vmIntrinsics::_shipilev_magic_addressOf:
+    return inline_addressOf();
+
   default:
     // If you get here, it may be that someone has added a new intrinsic
     // to the list in vmIntrinsics.hpp without implementing it here.
 #ifndef PRODUCT
     if ((PrintMiscellaneous && (Verbose || WizardMode)) || PrintOpto) {
@@ -8149,17 +8158,28 @@
   Node* n = argument(0);
   set_result(n->is_Con() ? intcon(1) : intcon(0));
   return true;
 }
 
-//------------------------------- inline_getObjectSize --------------------------------------
+//------------------------------- inline_getObjectSize/sizeOf --------------------------------------
 //
 // Calculate the runtime size of the object/array.
+//
+//   long java.lang.Runtime.sizeOf(Object obj)
 //   native long sun.instrument.InstrumentationImpl.getObjectSize0(long nativeAgent, Object objectToSize);
 //
+bool LibraryCallKit::inline_sizeOf() {
+  Node* obj = argument(0);
+  return inline_sizeOf_impl(obj);
+}
+
 bool LibraryCallKit::inline_getObjectSize() {
   Node* obj = argument(3);
+  return inline_sizeOf_impl(obj);
+}
+
+bool LibraryCallKit::inline_sizeOf_impl(Node* obj) {
   Node* klass_node = load_object_klass(obj);
 
   jint  layout_con = Klass::_lh_neutral_value;
   Node* layout_val = get_layout_helper(klass_node, layout_con);
   int   layout_is_con = (layout_val == nullptr);
@@ -8291,5 +8311,23 @@
     bh->add_req(argument(i));
   }
 
   return true;
 }
+
+bool LibraryCallKit::inline_timestamp(bool serial) {
+  insert_mem_bar(Op_MemBarCPUOrder);
+  Node* node = serial ?
+          _gvn.transform(new TimestampSerialNode(control())) :
+          _gvn.transform(new TimestampNode(control()));
+  set_result(node);
+  insert_mem_bar(Op_MemBarCPUOrder);
+  return true;
+}
+
+bool LibraryCallKit::inline_addressOf() {
+  Node* obj = argument(0);
+  Node* raw_val = _gvn.transform(new CastP2XNode(NULL, obj));
+  Node* long_val = ConvX2L(raw_val);
+  set_result(long_val);
+  return true;
+}
diff a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp
--- a/src/hotspot/share/opto/library_call.hpp
+++ b/src/hotspot/share/opto/library_call.hpp
@@ -361,10 +361,12 @@
   bool inline_vector_insert();
   bool inline_vector_compress_expand();
   bool inline_index_vector();
   bool inline_index_partially_in_upper_range();
 
+  bool inline_timestamp(bool serial);
+
   Node* gen_call_to_svml(int vector_api_op_id, BasicType bt, int num_elem, Node* opd1, Node* opd2);
 
   enum VectorMaskUseType {
     VecMaskUseLoad  = 1 << 0,
     VecMaskUseStore = 1 << 1,
@@ -385,7 +387,13 @@
   }
 
   bool inline_getObjectSize();
 
   bool inline_blackhole();
+
+  bool inline_sizeOf();
+  bool inline_sizeOf_impl(Node* obj);
+
+  bool inline_addressOf();
+
 };
 
diff a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp
--- a/src/hotspot/share/prims/nativeLookup.cpp
+++ b/src/hotspot/share/prims/nativeLookup.cpp
@@ -41,10 +41,11 @@
 #include "prims/jvm_misc.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/nativeLookup.hpp"
 #include "prims/unsafe.hpp"
 #include "prims/scopedMemoryAccess.hpp"
+#include "prims/shipilevMagic.hpp"
 #include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/os.hpp"
@@ -235,10 +236,11 @@
 #endif
 #if INCLUDE_JFR
   { CC"Java_jdk_jfr_internal_JVM_registerNatives",                 nullptr, FN_PTR(jfr_register_natives)            },
 #endif
   { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) },
+  { CC"Java_net_shipilev_Magic_registerNatives",                   nullptr, FN_PTR(JVM_RegisterNetShipilevMagicMethods) },
 };
 
 static address lookup_special_native(const char* jni_name) {
   int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod);
   for (int i = 0; i < count; i++) {
diff a/src/hotspot/share/prims/shipilevMagic.cpp b/src/hotspot/share/prims/shipilevMagic.cpp
--- /dev/null
+++ b/src/hotspot/share/prims/shipilevMagic.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2022, Red Hat, Inc. 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 "jni.h"
+#include "jvm.h"
+#include "classfile/javaClasses.inline.hpp"
+#include "gc/shared/collectedHeap.hpp"
+#include "oops/arrayOop.hpp"
+#include "oops/instanceKlass.inline.hpp"
+#include "oops/oop.inline.hpp"
+#include "oops/oopsHierarchy.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/jniHandles.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/orderAccess.hpp"
+#include "utilities/macros.hpp"
+
+#include OS_CPU_HEADER_INLINE(os)
+
+/**
+ * Implementation of the net.shipilev.Magic
+ */
+
+JVM_ENTRY(static jlong, NetShipilevMagic_timestamp(JNIEnv *env, jclass cls)) {
+#if defined(X86) && !defined(ZERO)
+  return os::rdtsc();
+#else
+  return -1;
+#endif
+} JVM_END
+
+JVM_ENTRY(static jlong, NetShipilevMagic_timestamp_serial(JNIEnv *env, jclass cls)) {
+#if defined(X86) && !defined(ZERO)
+  // Rely on rdtscp intrinsic to make the right thing
+  // serialization-wise. In these fallback/interpreter paths,
+  // just bite the bullet and do the fence.
+  OrderAccess::fence();
+  return os::rdtsc();
+#else
+  return -1;
+#endif
+} JVM_END
+
+JVM_ENTRY(jlong, NetShipilevMagic_sizeOf(JNIEnv *env, jclass cls, jobject obj))
+  assert(obj != NULL, "object must not be NULL");
+
+  oop o = JNIHandles::resolve_non_null(obj);
+  return o->size()*HeapWordSize;
+JVM_END
+
+JVM_ENTRY(jlong, NetShipilevMagic_addressOf(JNIEnv *env, jclass cls, jobject obj))
+  assert(obj != NULL, "object must not be NULL");
+
+  oop o = JNIHandles::resolve_non_null(obj);
+  return cast_from_oop<jlong>(o);
+JVM_END
+
+JVM_ENTRY(jlong, NetShipilevMagic_fieldOffsetOf(JNIEnv *env, jclass cls, jobject field))
+  assert(field != NULL, "field must not be NULL");
+
+  oop f    = JNIHandles::resolve_non_null(field);
+  oop m    = java_lang_reflect_Field::clazz(f);
+  Klass* k = java_lang_Class::as_Klass(m);
+  int slot = java_lang_reflect_Field::slot(f);
+
+  return InstanceKlass::cast(k)->field_offset(slot);
+JVM_END
+
+JVM_ENTRY(jlong, NetShipilevMagic_fieldSizeOf(JNIEnv *env, jclass cls, jobject field))
+  assert(field != NULL, "field must not be NULL");
+
+  oop f    = JNIHandles::resolve_non_null(field);
+  oop m    = java_lang_reflect_Field::clazz(f);
+  Klass* k = java_lang_Class::as_Klass(m);
+  int slot = java_lang_reflect_Field::slot(f);
+
+  Symbol* sig = InstanceKlass::cast(k)->field_signature(slot);
+  switch (sig->char_at(0)) {
+    case JVM_SIGNATURE_CLASS    :
+    case JVM_SIGNATURE_ARRAY    : return type2aelembytes(T_OBJECT);
+    case JVM_SIGNATURE_BYTE     : return type2aelembytes(T_BYTE);
+    case JVM_SIGNATURE_CHAR     : return type2aelembytes(T_CHAR);
+    case JVM_SIGNATURE_FLOAT    : return type2aelembytes(T_FLOAT);
+    case JVM_SIGNATURE_DOUBLE   : return type2aelembytes(T_DOUBLE);
+    case JVM_SIGNATURE_INT      : return type2aelembytes(T_INT);
+    case JVM_SIGNATURE_LONG     : return type2aelembytes(T_LONG);
+    case JVM_SIGNATURE_SHORT    : return type2aelembytes(T_SHORT);
+    case JVM_SIGNATURE_BOOLEAN  : return type2aelembytes(T_BOOLEAN);
+  }
+
+  ShouldNotReachHere();
+  return 0;
+JVM_END
+
+class GetReferencedObjectsClosure : public BasicOopIterateClosure {
+private:
+  objArrayOopDesc* const _result;
+  int _count;
+public:
+  GetReferencedObjectsClosure(objArrayOopDesc* result) : _result(result), _count(0) {}
+
+  template <typename T> void do_oop_nv(T* p) {
+    oop o = HeapAccess<>::oop_load(p);
+    if (!CompressedOops::is_null(o)) {
+      _result->obj_at_put(_count++, o);
+    }
+  }
+
+  int count() { return _count; }
+
+  virtual void do_oop(oop* p)       { do_oop_nv(p); }
+  virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
+
+  // Don't use the oop verification code in the oop_oop_iterate framework.
+  debug_only(virtual bool should_verify_oops() { return false; })
+};
+
+JVM_ENTRY(jint, NetShipilevMagic_getReferencedObjects(JNIEnv *env, jclass cls, jobject obj_ref, jobjectArray ref_buf_ref))
+  oop obj = JNIHandles::resolve_non_null(obj_ref);
+  objArrayOop ref_buf = objArrayOop(JNIHandles::resolve_non_null(ref_buf_ref));
+
+  assert(Universe::heap()->is_in(obj), "object should be in heap: " PTR_FORMAT, p2i(obj));
+  assert(Universe::heap()->is_in(ref_buf), "ref buf should be in heap: " PTR_FORMAT, p2i(ref_buf));
+
+  InstanceKlass* k = InstanceKlass::cast(obj->klass());
+
+  int count = 0;
+  {
+    InstanceKlass* ik = k;
+    while (ik != NULL) {
+      count += ik->nonstatic_oop_field_count();
+      ik = ik->superklass();
+    }
+  }
+
+  if (count == 0) {
+    return 0;
+  }
+
+  if (count > ref_buf->length()) {
+    return -1;
+  }
+
+  GetReferencedObjectsClosure cl(ref_buf);
+
+#ifdef _LP64
+  if (UseCompressedOops) {
+    k->oop_oop_iterate<narrowOop>(obj, &cl);
+  } else
+#endif
+  {
+    k->oop_oop_iterate<oop>(obj, &cl);
+  }
+
+  return cl.count();
+JVM_END
+
+/// JVM_RegisterUnsafeMethods
+
+#define CC (char*)  /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
+
+#define LANG "Ljava/lang/"
+
+#define OBJ LANG "Object;"
+#define CLS LANG "Class;"
+#define FLD LANG "reflect/Field;"
+
+static JNINativeMethod net_shipilev_Magic_methods[] = {
+  {CC "timestamp",            CC "()J",                 FN_PTR(NetShipilevMagic_timestamp)},
+  {CC "timestampSerial",      CC "()J",                 FN_PTR(NetShipilevMagic_timestamp_serial)},
+  {CC "sizeOf0",              CC "(" OBJ ")J",          FN_PTR(NetShipilevMagic_sizeOf)},
+  {CC "addressOf0",           CC "(" OBJ ")J",          FN_PTR(NetShipilevMagic_addressOf)},
+  {CC "getReferencedObjects", CC "(" OBJ "[" OBJ ")I",  FN_PTR(NetShipilevMagic_getReferencedObjects)},
+  {CC "fieldOffsetOf0",       CC "(" FLD ")J",          FN_PTR(NetShipilevMagic_fieldOffsetOf)},
+  {CC "fieldSizeOf0",         CC "(" FLD ")J",          FN_PTR(NetShipilevMagic_fieldSizeOf)},
+};
+
+#undef LANG
+#undef OBJ
+#undef CLS
+#undef FLD
+
+#undef CC
+#undef FN_PTR
+
+JVM_ENTRY(void, JVM_RegisterNetShipilevMagicMethods(JNIEnv *env, jclass cls)) {
+  ThreadToNativeFromVM ttnfv(thread);
+
+  int ok = env->RegisterNatives(cls, net_shipilev_Magic_methods, sizeof(net_shipilev_Magic_methods)/sizeof(JNINativeMethod));
+  guarantee(ok == 0, "register net.shipilev.Magic natives");
+} JVM_END
diff a/src/hotspot/share/prims/shipilevMagic.hpp b/src/hotspot/share/prims/shipilevMagic.hpp
--- /dev/null
+++ b/src/hotspot/share/prims/shipilevMagic.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, 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.
+ *
+ * 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.
+ *
+ */
+
+
+#ifndef SHARE_PRIMS_SHIPILEV_MAGIC_HPP
+#define SHARE_PRIMS_SHIPILEV_MAGIC_HPP
+
+#include "jni.h"
+
+extern "C" {
+  void JNICALL JVM_RegisterNetShipilevMagicMethods(JNIEnv *env, jclass cls);
+}
+
+#endif // SHARE_PRIMS_SHIPILEV_MAGIC_HPP
diff a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp
--- a/src/hotspot/share/runtime/vmOperation.hpp
+++ b/src/hotspot/share/runtime/vmOperation.hpp
@@ -96,10 +96,11 @@
   template(ShenandoahFinalMarkStartEvac)          \
   template(ShenandoahInitUpdateRefs)              \
   template(ShenandoahFinalUpdateRefs)             \
   template(ShenandoahFinalRoots)                  \
   template(ShenandoahDegeneratedGC)               \
+  template(EpsilonCollect)                        \
   template(Exit)                                  \
   template(LinuxDllLoad)                          \
   template(WhiteBoxOperation)                     \
   template(JVMCIResizeCounters)                   \
   template(ClassLoaderStatsOperation)             \
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
@@ -133,10 +133,11 @@
     exports javax.security.auth.callback;
     exports javax.security.auth.login;
     exports javax.security.auth.spi;
     exports javax.security.auth.x500;
     exports javax.security.cert;
+    exports net.shipilev;
 
 
     // additional qualified exports may be inserted at build time
     // see make/gensrc/GenModuleInfo.gmk
 
diff a/src/java.base/share/classes/net/shipilev/Magic.java b/src/java.base/share/classes/net/shipilev/Magic.java
--- /dev/null
+++ b/src/java.base/share/classes/net/shipilev/Magic.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2022, Red Hat, Inc. 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package net.shipilev;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.util.function.ToLongFunction;
+import java.util.Arrays;
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+import jdk.internal.vm.annotation.DontInline;
+import jdk.internal.vm.annotation.IntrinsicCandidate;
+
+public class Magic {
+
+    /*
+     * ---------------------- INTERFACE --------------------------
+     *         (If you are lazy to look into Javadoc)
+     * -----------------------------------------------------------
+     */
+
+    /**
+     * Returns the current CPU timestamp counter.
+     * <p>
+     * Maps to RDTSC on X86. No other platform is supported (yet).
+     *
+     * @return TSC value, or -1 if not supported
+     */
+    @IntrinsicCandidate
+    public static native long timestamp();
+
+    /**
+     * Same as {@link #timestamp}, but also provides instruction
+     * stream serialization. May be more expensive.
+     * <p>
+     * Maps to RDTSCP on X86. No other platform is supported (yet).
+     *
+     * @return TSC value, or -1 if not supported
+     */
+    @IntrinsicCandidate
+    public static native long timestampSerial();
+
+    /**
+     * Returns the implementation-specific estimate of the amount of storage
+     * consumed by the specified object.
+     * <p>
+     * The estimate may change during a single invocation of the JVM.
+     *
+     * @param obj object to estimate the size of
+     * @return storage size in bytes
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 16
+     */
+    @DontInline // Semantics: make sure the object is not scalar replaced.
+    public static long sizeOf(Object obj) {
+        Objects.requireNonNull(obj);
+        return sizeOf0(obj);
+    }
+
+    /**
+     * Returns the implementation-specific estimate of the offset of the field
+     * within the holding container.
+     * <p>
+     * For the instance fields, the offset is from the beginning of the holder
+     * object. For the static fields, the offset is from the beginning of the
+     * unspecified holder area. As such, these offsets are useful for comparing
+     * the offsets of two fields, not for any kind of absolute addressing.
+     * <p>
+     * The estimate may change during a single invocation of the JVM, for example
+     * during class redefinition.
+     *
+     * @param field field to poll
+     * @return the field offset in bytes
+     * @throws NullPointerException if {@code field} is {@code null}
+     * @since 16
+     */
+    public static long fieldOffsetOf(Field field) {
+        Objects.requireNonNull(field);
+        return fieldOffsetOf0(field);
+    }
+
+    /**
+     * Returns the implementation-specific estimate of the field slot size for
+     * the specified object field.
+     * <p>
+     * The estimate may change during a single invocation of the JVM.
+     *
+     * TODO: Split by staticness?
+     *
+     * @param field field to poll
+     * @return the field size in bytes
+     * @throws NullPointerException if {@code field} is {@code null}
+     * @since 16
+     */
+    public static long fieldSizeOf(Field field) {
+        Objects.requireNonNull(field);
+        return fieldSizeOf0(field);
+    }
+
+    /**
+     * Returns the implementation-specific estimate of the amount of storage
+     * consumed by the specified object and all objects referenced by it.
+     * <p>
+     * The estimate may change during a single invocation of the JVM. Notably,
+     * the estimate is not guaranteed to remain stable if the object references in
+     * the walked subgraph change when {@code deepSizeOf} is running.
+     *
+     * @param obj root object to start the estimate from
+     * @return storage size in bytes
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 16
+     */
+    public static long deepSizeOf(Object obj) {
+        return deepSizeOf0(obj, (o) -> DEEP_SIZE_OF_TRAVERSE | DEEP_SIZE_OF_SHALLOW);
+    }
+
+
+    /**
+     * Returns the implementation-specific estimate of the amount of storage
+     * consumed by the specified object and all objects referenced by it.
+     * <p>
+     * The estimate may change during a single invocation of the JVM. Notably,
+     * the estimate is not guaranteed to remain stable if the object references in
+     * the walked subgraph change when {@code deepSizeOf} is running.
+     *
+     * @param obj root object to start the estimate from
+     * @param includeCheck callback to evaluate an object's size. The callback can
+     * return a positive value as a bitmask - valid values are
+     * {@link #DEEP_SIZE_OF_SHALLOW} to consider the object's shallow sise and
+     * {@link #DEEP_SIZE_OF_TRAVERSE} to traverse ("go deeper") the object's
+     * references. A negative value means that the absolute return value is
+     * considered and the object's references are not considered.
+     * @return storage size in bytes
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @since 16
+     */
+    public static long deepSizeOf(Object obj, ToLongFunction<Object> includeCheck) {
+        return deepSizeOf0(obj, includeCheck);
+    }
+
+    /**
+     * Returns the implementation-specific representation of the memory address
+     * where the specified object resides.
+     * <p>
+     * The estimate may change during a single invocation of the JVM. Notably,
+     * in the presence of moving garbage collector, the address can change at any
+     * time, including during the call. As such, this method is only useful for
+     * low-level debugging and heap introspection in a quiescent application.
+     * <p>
+     * The JVM is also free to provide non-verbatim answers, for example, adding
+     * the random offset in order to hide the real object addresses. Because of this,
+     * this method is useful to compare the relative Object positions, or inspecting
+     * the object alignments up to some high threshold, but not for accessing the objects
+     * via the naked native address.
+     *
+     * @param obj object to get the address of
+     * @return current object address
+     * @since 16
+     */
+    @DontInline // Semantics: make sure the object is not scalar replaced.
+    public static long addressOf(Object obj) {
+        Objects.requireNonNull(obj);
+        return addressOf0(obj);
+    }
+
+    /*
+     * ---------------------- IMPLEMENTATION --------------------------
+     */
+
+    private static native void registerNatives();
+    static {
+        registerNatives();
+    }
+
+    public Magic() {
+        throw new IllegalArgumentException("NO INSTANCE MAGIC FOR YOU.");
+    }
+
+    /**
+     * Bit value for {@link #deepSizeOf(Object, ToLongFunction)}'s callback
+     * return value to continue traversal ("go deep") of the references of
+     * the object passed to the callback.
+     */
+    public static final long DEEP_SIZE_OF_TRAVERSE = 1;
+    /**
+     * Bit value for {@link #deepSizeOf(Object, ToLongFunction)}'s callback
+     * return value to consider the shallow size of the object passed to the
+     * callback.
+     */
+    public static final long DEEP_SIZE_OF_SHALLOW = 2;
+
+    private static long handleIncludeCheck(ArrayDeque<Object> q, Object o, ToLongFunction<Object> ic, long ts, long os) {
+        long t = ic.applyAsLong(o);
+        if (t > 0) {
+            if ((t & DEEP_SIZE_OF_TRAVERSE) != 0) {
+                q.push(o);
+            }
+            if ((t & DEEP_SIZE_OF_SHALLOW) != 0) {
+                ts += os;
+            }
+        } else {
+            ts -= t;
+        }
+        return ts;
+    }
+
+    @DontInline // Semantics: make sure the object is not scalar replaced.
+    private static long deepSizeOf0(Object obj, ToLongFunction<Object> includeCheck) {
+        Objects.requireNonNull(obj);
+
+        IdentityHashSet visited = new IdentityHashSet(IdentityHashSet.MINIMUM_CAPACITY);
+        ArrayDeque<Object> q = new ArrayDeque<>();
+
+        visited.add(obj);
+
+        long rootSize = sizeOf0(obj);
+        long totalSize = handleIncludeCheck(q, obj, includeCheck, 0, rootSize);
+
+        Object[] refBuf = new Object[1];
+
+        while (!q.isEmpty()) {
+            Object o = q.pop();
+            Class<?> cl = o.getClass();
+            if (cl.isArray()) {
+                // Separate array path avoids adding a lot of (potentially large) array
+                // contents on the queue. No need to handle primitive arrays too.
+
+                if (cl.getComponentType().isPrimitive()) {
+                    continue;
+                }
+
+                for (Object e : (Object[])o) {
+                    if (e != null && visited.add(e)) {
+                        long size = sizeOf0(e);
+                        totalSize = handleIncludeCheck(q, e, includeCheck, totalSize, size);
+                    }
+                }
+            } else {
+                int objs;
+                while ((objs = getReferencedObjects(o, refBuf)) < 0) {
+                    refBuf = new Object[refBuf.length * 2];
+                }
+
+                for (int c = 0; c < objs; c++) {
+                    Object e = refBuf[c];
+                    if (visited.add(e)) {
+                        long size = sizeOf0(e);
+                        totalSize = handleIncludeCheck(q, e, includeCheck, totalSize, size);
+                    }
+                }
+
+                // Null out the buffer: do not keep these objects referenced until next
+                // buffer fill, and help the VM code to avoid full SATB barriers on existing
+                // buffer elements in getReferencedObjects.
+                Arrays.fill(refBuf, 0, objs, null);
+            }
+        }
+
+        return totalSize;
+    }
+
+    /**
+     * Peels the referenced objects from the given object and puts them
+     * into the reference buffer. Never returns nulls in reference buffer.
+     * Returns the number of valid elements in the buffer. If reference bufffer
+     * is too small, returns -1.
+     *
+     * @param obj object to peel
+     * @param refBuf reference buffer
+     * @return number of valid elements in buffer, -1 if buffer is too small
+     */
+    @IntrinsicCandidate
+    private static native int getReferencedObjects(Object obj, Object[] refBuf);
+
+    private static final class IdentityHashSet {
+        private static final int MINIMUM_CAPACITY = 4;
+        private static final int MAXIMUM_CAPACITY = 1 << 29;
+
+        private Object[] table;
+        private int size;
+
+        public IdentityHashSet(int expectedMaxSize) {
+            table = new Object[capacity(expectedMaxSize)];
+        }
+
+        private static int capacity(int expectedMaxSize) {
+            return
+                (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
+                (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
+                Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
+        }
+
+        private static int nextIndex(int i, int len) {
+            return (i + 1 < len ? i + 1 : 0);
+        }
+
+        public boolean add(Object o) {
+            while (true) {
+                final Object[] tab = table;
+                final int len = tab.length;
+                int i = System.identityHashCode(o) & (len - 1);
+
+                for (Object item; (item = tab[i]) != null; i = nextIndex(i, len)) {
+                    if (item == o) {
+                        return false;
+                    }
+                }
+
+                final int s = size + 1;
+                if (s*3 > len && resize()) continue;
+
+                tab[i] = o;
+                size = s;
+                return true;
+            }
+        }
+
+        private boolean resize() {
+            Object[] oldTable = table;
+            int oldLength = oldTable.length;
+            if (oldLength == MAXIMUM_CAPACITY) {
+                throw new IllegalStateException("Capacity exhausted.");
+            }
+
+            int newLength = oldLength * 2;
+            if (newLength <= oldLength) {
+                return false;
+            }
+
+            Object[] newTable = new Object[newLength];
+            for (Object o : oldTable) {
+                if (o != null) {
+                    int i = System.identityHashCode(o) & (newLength - 1);
+                    while (newTable[i] != null) {
+                        i = nextIndex(i, newLength);
+                    }
+                    newTable[i] = o;
+                }
+            }
+            table = newTable;
+            return true;
+        }
+    }
+
+    @IntrinsicCandidate
+    private static native long sizeOf0(Object obj);
+
+    @IntrinsicCandidate
+    private static native long addressOf0(Object obj);
+
+    // Reflection-like call, is not supposed to be fast?
+    private static native long fieldOffsetOf0(Field field);
+
+    // Reflection-like call, is not supposed to be fast?
+    private static native long fieldSizeOf0(Field field);
+
+}
diff a/test/hotspot/jtreg/gc/epsilon/TestSlidingGC.java b/test/hotspot/jtreg/gc/epsilon/TestSlidingGC.java
--- /dev/null
+++ b/test/hotspot/jtreg/gc/epsilon/TestSlidingGC.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, 2018, Red Hat, Inc. 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.
+ */
+
+package gc.epsilon;
+
+/**
+ * @test TestSlidingGC
+ * @key randomness
+ * @requires vm.gc.Epsilon & !vm.graal.enabled
+ * @summary Epsilon sliding GC works
+ * @library /test/lib
+ * @run main/othervm -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonSlidingGC -XX:+EpsilonVerify                      gc.epsilon.TestSlidingGC
+ * @run main/othervm -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonSlidingGC                                         gc.epsilon.TestSlidingGC
+ * @run main/othervm -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonSlidingGC -XX:+EpsilonVerify -XX:+EpsilonUncommit gc.epsilon.TestSlidingGC
+ * @run main/othervm -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+EpsilonSlidingGC                    -XX:+EpsilonUncommit gc.epsilon.TestSlidingGC
+ */
+
+import java.util.concurrent.*;
+import java.util.Random;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+
+public class TestSlidingGC {
+
+  static int SIZE  = Integer.getInteger("size", 10_000_000);
+  static int COUNT = Integer.getInteger("count", 100_000_000); // ~2.4 GB allocation
+
+  static Object[] sink;
+
+  public static void main(String... args) {
+    Random r = Utils.getRandomInstance();
+    sink = new Object[SIZE];
+    for (int c = 0; c < COUNT; c++) {
+      sink[r.nextInt(SIZE)] = new Object();
+    }
+  }
+
+}
diff a/test/jdk/net/shipilev/magic/AddressOf.java b/test/jdk/net/shipilev/magic/AddressOf.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/AddressOf.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   AddressOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   AddressOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   AddressOf
+ */
+
+import java.lang.reflect.Field;
+
+import net.shipilev.Magic;
+
+public class AddressOf {
+
+    public static void main(String ... args) throws Exception {
+        testAddress_newInteger();
+        testAddress_IntegerValueOf();
+        testAddress_newObject();
+        testAddress_localObject();
+        testAddress_fieldObject();
+        testNulls();
+    }
+
+    private static void testAddress_newInteger() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.addressOf(new Integer(c)));
+        }
+    }
+
+    private static void testAddress_IntegerValueOf() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.addressOf(Integer.valueOf(c)));
+        }
+    }
+
+    private static void testAddress_newObject() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.addressOf(new Object()));
+        }
+    }
+
+    private static void testAddress_localObject() throws Exception {
+        Object o = new Object();
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.addressOf(o));
+        }
+    }
+
+    static Object staticO = new Object();
+
+    private static void testAddress_fieldObject() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.addressOf(staticO));
+        }
+    }
+
+    private static void testNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            try {
+                Magic.addressOf(null);
+                MagicUtil.assertFail();
+            } catch (NullPointerException e) {
+                // expected
+            }
+        }
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/AddressOfStability.java b/test/jdk/net/shipilev/magic/AddressOfStability.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/AddressOfStability.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -Xint
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:-TieredCompilation
+ *                   AddressOfStability
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -Xint
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:-TieredCompilation
+ *                   AddressOfStability
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.addressOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -Xint
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:TieredStopAtLevel=1
+ *                   AddressOfStability
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:CompileCommand=exclude,AddressOfStability::testInterpreted
+ *                   -XX:-TieredCompilation
+ *                   AddressOfStability
+ */
+
+import java.lang.reflect.Field;
+
+import net.shipilev.Magic;
+
+public class AddressOfStability {
+
+    public static void main(String ... args) throws Exception {
+        Object o = new Object();
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            long addrInt1 = testInterpreted(o);
+            long addrComp = testCompiled(o);
+            long addrInt2 = testInterpreted(o);
+
+            if (addrInt1 == addrInt2) {
+                // No moves were detected, compare with compiled.
+                MagicUtil.assertEquals(addrInt1, addrComp);
+            }
+        }
+    }
+
+    private static long testCompiled(Object o) {
+        return Magic.addressOf(o);
+    }
+
+    private static long testInterpreted(Object o) {
+        return Magic.addressOf(o);
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/CheckIntrinsics.java b/test/jdk/net/shipilev/magic/CheckIntrinsics.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/CheckIntrinsics.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test that intrinsics are defined correctly
+ *
+ * @run main/othervm -Xmx128m -XX:+UnlockDiagnosticVMOptions -XX:+CheckIntrinsics CheckIntrinsics
+ */
+
+import java.lang.reflect.Field;
+
+public class CheckIntrinsics {
+    public static void main(String ... args) throws Exception {
+        // Deliberately empty, the checks happen at startup.
+    }
+}
diff a/test/jdk/net/shipilev/magic/DeepSizeOf.java b/test/jdk/net/shipilev/magic/DeepSizeOf.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/DeepSizeOf.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+ 
+/*
+ * @test
+ * @summary Test for Magic.deepSizeOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=2
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=3
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=4
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   DeepSizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.deepSizeOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=2
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=3
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=4
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   DeepSizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.deepSizeOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   DeepSizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   DeepSizeOf
+ */
+
+import net.shipilev.Magic;
+
+public class DeepSizeOf {
+
+    public static void main(String ... args) {
+        testSame_newObject();
+        testSimpleHierarchy();
+        testPartialNulls();
+
+        testNodeChain(0);
+        testNodeChain(1);
+        testNodeChain(10);
+        testNodeChain(100);
+
+        testNodeTree();
+
+        testObjArray(0);
+        testObjArray(1);
+        testObjArray(10);
+        testObjArray(100);
+
+        testNulls();
+
+        testIncludeCheck();
+        testIncludeCheckDeep();
+    }
+
+    private static void testSame_newObject() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            Object o = new Object();
+            MagicUtil.assertEquals(Magic.sizeOf(o), Magic.deepSizeOf(o));
+        }
+    }
+
+    private static void testNodeChain(int depth) {
+        Node n = new Node(null);
+        for (int d = 0; d < depth; d++) {
+            n = new Node(n);
+        }
+
+        for (int c = 0; c < MagicUtil.SHORT_ITERS; c++) {
+            MagicUtil.assertEquals(Magic.sizeOf(n)*(depth + 1), Magic.deepSizeOf(n));
+        }
+    }
+
+    private static class Node {
+       Node next;
+       public Node(Node n) { next = n; }
+    }
+
+    private static void testNodeTree() {
+        TreeNode r = new TreeNode(new TreeNode(new TreeNode(null, null), null), new TreeNode(null, null));
+        for (int c = 0; c < MagicUtil.SHORT_ITERS; c++) {
+            MagicUtil.assertEquals(Magic.sizeOf(r)*4, Magic.deepSizeOf(r));
+        }
+    }
+
+    private static class TreeNode {
+       TreeNode l, r;
+       public TreeNode(TreeNode l, TreeNode r) { this.l = l; this.r = r; }
+    }
+
+    private static void testObjArray(int size) {
+        Object o = new Object();
+        Object[] arr = new Object[size];
+        for (int d = 0; d < size; d++) {
+            arr[d] = new Object();
+        }
+
+        for (int c = 0; c < MagicUtil.SHORT_ITERS; c++) {
+            MagicUtil.assertEquals(Magic.sizeOf(arr) + Magic.sizeOf(o)*size, Magic.deepSizeOf(arr));
+        }
+    }
+
+    private static class A {
+        Object o1;
+    }
+
+    private static class B extends A {
+        Object o2;
+    }
+
+    private static void testSimpleHierarchy() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            B b = new B();
+            b.o1 = new Object();
+            b.o2 = new Object();
+            MagicUtil.assertEquals(Magic.sizeOf(b) + Magic.sizeOf(b.o1) + Magic.sizeOf(b.o2), Magic.deepSizeOf(b));
+        }
+    }
+
+    private static class D {
+        Object o1;
+        Object o2;
+    }
+
+    private static void testPartialNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            D d = new D();
+            d.o1 = null;
+            d.o2 = new Object();
+            MagicUtil.assertEquals(Magic.sizeOf(d) + Magic.sizeOf(d.o2), Magic.deepSizeOf(d));
+        }
+    }
+
+    private static void testNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            try {
+                Magic.deepSizeOf(null);
+                MagicUtil.assertFail();
+            } catch (NullPointerException e) {
+                // expected
+            }
+        }
+    }
+
+    private static void testIncludeCheck() {
+        for (int i = 0; i < MagicUtil.ITERS; i++) {
+            Object o = new Object();
+            MagicUtil.assertEquals(42L, Magic.deepSizeOf(o, (obj) -> -42L));
+        }
+    }
+
+    private static void testIncludeCheckDeep() {
+        for (int i = 0; i < MagicUtil.ITERS; i++) {
+            DeepA a = new DeepA();
+            DeepB b = new DeepB();
+            DeepC c = new DeepC();
+            a.b = b;
+            b.c = c;
+            c.x = new Object();
+
+            long sA = Magic.sizeOf(a);
+            long sB = Magic.sizeOf(b);
+            long sC = Magic.sizeOf(c);
+            long sCX = Magic.sizeOf(c.x);
+
+            MagicUtil.assertEquals(sA,
+                                       Magic.deepSizeOf(a, (obj) -> {
+                                           if (obj instanceof DeepB)
+                                               return 0L; // don't consider DeepB (don't go deeper)
+                                           return Magic.DEEP_SIZE_OF_SHALLOW | Magic.DEEP_SIZE_OF_TRAVERSE;
+                                       }));
+
+            MagicUtil.assertEquals(sA + sC + sCX,
+                                       Magic.deepSizeOf(a, (obj) -> {
+                                           if (obj instanceof DeepB)
+                                               return Magic.DEEP_SIZE_OF_TRAVERSE; // don't consider DeepB (but its references!)
+                                           return Magic.DEEP_SIZE_OF_SHALLOW | Magic.DEEP_SIZE_OF_TRAVERSE;
+                                       }));
+
+            MagicUtil.assertEquals(sA,
+                                       Magic.deepSizeOf(a, (obj) -> {
+                                           if (obj instanceof DeepA)
+                                               return Magic.DEEP_SIZE_OF_SHALLOW; // consider DeepA, but don't go deeper
+                                           return Magic.DEEP_SIZE_OF_SHALLOW | Magic.DEEP_SIZE_OF_TRAVERSE;
+                                       }));
+
+            MagicUtil.assertEquals(sA + sB,
+                                       Magic.deepSizeOf(a, (obj) -> {
+                                           if (obj instanceof DeepB)
+                                               return Magic.DEEP_SIZE_OF_SHALLOW; // consider DeepB, but don't go deeper
+                                           return Magic.DEEP_SIZE_OF_SHALLOW | Magic.DEEP_SIZE_OF_TRAVERSE;
+                                       }));
+        }
+    }
+
+    private static class DeepA {
+        DeepB b;
+    }
+
+    private static class DeepB {
+        DeepC c;
+    }
+
+    private static class DeepC {
+        Object x;
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/FieldOffsetOf.java b/test/jdk/net/shipilev/magic/FieldOffsetOf.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/FieldOffsetOf.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+ 
+/*
+ * @test
+ * @summary Test for Magic.fieldOffsetOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   FieldOffsetOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.fieldOffsetOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   FieldOffsetOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.fieldOffsetOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldOffsetOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   FieldOffsetOf
+ */
+
+import java.lang.reflect.Field;
+import jdk.test.lib.Platform;
+
+import net.shipilev.Magic;
+
+public class FieldOffsetOf {
+
+    public static void main(String ... args) throws Exception {
+        testInstanceOffsets();
+        testStaticOffsets();
+        testNulls();
+    }
+
+    private static void testInstanceOffsets() throws Exception {
+        int expected = Platform.is64bit() ? 12 : 8;
+
+        Field f = Holder.class.getDeclaredField("x");
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.fieldOffsetOf(f));
+        }
+    }
+
+    private static void testStaticOffsets() throws Exception {
+        Field f = Holder.class.getDeclaredField("staticX");
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0,  Magic.fieldOffsetOf(f));
+            MagicUtil.assertNotEquals(-1, Magic.fieldOffsetOf(f));
+        }
+    }
+
+    private static void testNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            try {
+                Magic.fieldOffsetOf(null);
+                MagicUtil.assertFail();
+            } catch (NullPointerException e) {
+                // expected
+            }
+        }
+    }
+
+    static class Holder {
+        static int staticX;
+        int x;
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/FieldSizeOf.java b/test/jdk/net/shipilev/magic/FieldSizeOf.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/FieldSizeOf.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.fieldSizeOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:-TieredCompilation
+ *                   FieldSizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.fieldSizeOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:-TieredCompilation
+ *                   FieldSizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.fieldSizeOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   FieldSizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:. 
+ *                   -XX:-TieredCompilation
+ *                   FieldSizeOf
+ */
+
+import java.lang.reflect.Field;
+import jdk.test.whitebox.WhiteBox;
+
+import net.shipilev.Magic;
+
+public class FieldSizeOf {
+
+    static final Boolean compressedOops = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedOops");
+    static final int R = ((compressedOops == null) || (compressedOops == true)) ?  4 : 8;
+
+    public static void main(String ... args) throws Exception {
+        testInstanceOffsets();
+        testStaticOffsets();
+        testNulls();
+    }
+
+    private static void testInstanceOffsets() throws Exception {
+        testWith(1, Holder.class.getDeclaredField("f_boolean"));
+        testWith(1, Holder.class.getDeclaredField("f_byte"));
+        testWith(2, Holder.class.getDeclaredField("f_char"));
+        testWith(2, Holder.class.getDeclaredField("f_short"));
+        testWith(4, Holder.class.getDeclaredField("f_int"));
+        testWith(4, Holder.class.getDeclaredField("f_float"));
+        testWith(8, Holder.class.getDeclaredField("f_long"));
+        testWith(8, Holder.class.getDeclaredField("f_double"));
+        testWith(R, Holder.class.getDeclaredField("f_object"));
+        testWith(R, Holder.class.getDeclaredField("f_array"));
+    }
+
+    private static void testStaticOffsets() throws Exception {
+        testWith(1, Holder.class.getDeclaredField("s_boolean"));
+        testWith(1, Holder.class.getDeclaredField("s_byte"));
+        testWith(2, Holder.class.getDeclaredField("s_char"));
+        testWith(2, Holder.class.getDeclaredField("s_short"));
+        testWith(4, Holder.class.getDeclaredField("s_int"));
+        testWith(4, Holder.class.getDeclaredField("s_float"));
+        testWith(8, Holder.class.getDeclaredField("s_long"));
+        testWith(8, Holder.class.getDeclaredField("s_double"));
+        testWith(R, Holder.class.getDeclaredField("s_object"));
+        testWith(R, Holder.class.getDeclaredField("s_array"));
+    }
+
+    private static void testWith(int expected, Field f) {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.fieldSizeOf(f));
+        }
+    }
+
+    private static void testNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            try {
+                Magic.fieldSizeOf(null);
+                MagicUtil.assertFail();
+            } catch (NullPointerException e) {
+                // expected
+            }
+        }
+    }
+
+    public static class Holder {
+        static boolean  s_boolean;
+        static byte     s_byte;
+        static char     s_char;
+        static short    s_short;
+        static int      s_int;
+        static float    s_float;
+        static double   s_double;
+        static long     s_long;
+        static Object   s_object;
+        static Object[] s_array;
+        boolean  f_boolean;
+        byte     f_byte;
+        char     f_char;
+        short    f_short;
+        int      f_int;
+        float    f_float;
+        double   f_double;
+        long     f_long;
+        Object   f_object;
+        Object[] f_array;
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/MagicUtil.java b/test/jdk/net/shipilev/magic/MagicUtil.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/MagicUtil.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+import java.lang.reflect.Field;
+
+public class MagicUtil {
+
+    public static final int SHORT_ITERS = 10_000;
+    public static final int ITERS = 1_000_000;
+
+    public static void assertEquals(long expected, long actual) {
+        if (expected != actual) {
+            throw new IllegalStateException(
+               "Error: expected: " + expected + " (" + Long.toHexString(expected) +
+                "), actual: " + actual + " (" + Long.toHexString(actual) + ")");
+        }
+    }
+
+    public static void assertNotEquals(long notExpected, long actual) {
+        if (notExpected == actual) {
+            throw new IllegalStateException(
+               "Error: not expected: " + notExpected + " (" + Long.toHexString(notExpected) +
+                "), actual: " + actual + " (" + Long.toHexString(actual) + ")");
+        }
+    }
+
+    public static void assertFail() {
+        throw new IllegalStateException("Should not be here");
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/SizeOf.java b/test/jdk/net/shipilev/magic/SizeOf.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/SizeOf.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with 32-bit compressed oops
+ * @library /test/lib
+ * @requires vm.debug
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ * @requires vm.debug
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ * @requires vm.debug
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:FastAllocateSizeLimit=0
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with 32-bit compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ * @requires vm.debug
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.sizeOf with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ * @requires vm.debug
+ *
+ * @build jdk.test.whitebox.WhiteBox
+ * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -Xint
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -XX:TieredStopAtLevel=1
+ *                   SizeOf
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni -XX:+WhiteBoxAPI -Xbootclasspath/a:.
+ *                   -XX:ObjectAlignmentInBytes=32
+ *                   -XX:-TieredCompilation
+ *                   SizeOf
+ */
+
+import jdk.test.lib.Platform;
+import jdk.test.whitebox.WhiteBox;
+
+import net.shipilev.Magic;
+
+public class SizeOf {
+
+    static final Boolean compressedOops = WhiteBox.getWhiteBox().getBooleanVMFlag("UseCompressedOops");
+    static final int R = ((compressedOops == null) || (compressedOops == true)) ?  4 : 8;
+
+    static final Long align = WhiteBox.getWhiteBox().getIntVMFlag("ObjectAlignmentInBytes");
+    static final int A = (align == null ? 8 : align.intValue());
+
+    public static void main(String ... args) {
+        testSize_newObject();
+        testSize_localObject();
+        testSize_fieldObject();
+
+        testSize_newSmallByteArray();
+        testSize_localSmallByteArray();
+        testSize_fieldSmallByteArray();
+
+        testSize_newSmallObjArray();
+        testSize_localSmallObjArray();
+        testSize_fieldSmallObjArray();
+
+        testNulls();
+    }
+
+    private static int roundUp(int v, int a) {
+        return (v + a - 1) / a * a;
+    }
+
+    private static void testSize_newObject() {
+        int expected = roundUp(Platform.is64bit() ? 16 : 8, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(new Object()));
+        }
+    }
+
+    private static void testSize_localObject() {
+        int expected = roundUp(Platform.is64bit() ? 16 : 8, A);
+        Object o = new Object();
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(o));
+        }
+    }
+
+    static Object staticO = new Object();
+
+    private static void testSize_fieldObject() {
+        int expected = roundUp(Platform.is64bit() ? 16 : 8, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(staticO));
+        }
+    }
+
+    private static void testSize_newSmallByteArray() {
+        int expected = roundUp(1024 + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(new byte[1024]));
+        }
+    }
+
+    private static void testSize_localSmallByteArray() {
+        byte[] arr = new byte[1024];
+        int expected = roundUp(arr.length + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(arr));
+        }
+    }
+
+    static byte[] smallArr = new byte[1024];
+
+    private static void testSize_fieldSmallByteArray() {
+        int expected = roundUp(smallArr.length + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(smallArr));
+        }
+    }
+
+    private static void testSize_newSmallObjArray() {
+        int expected = roundUp(1024*R + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(new Object[1024]));
+        }
+    }
+
+    private static void testSize_localSmallObjArray() {
+        Object[] arr = new Object[1024];
+        int expected = roundUp(arr.length*R + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(arr));
+        }
+    }
+
+    static Object[] smallObjArr = new Object[1024];
+
+    private static void testSize_fieldSmallObjArray() {
+        int expected = roundUp(smallArr.length*R + 16, A);
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertEquals(expected, Magic.sizeOf(smallObjArr));
+        }
+    }
+
+    private static void testNulls() {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            try {
+                Magic.sizeOf(null);
+                MagicUtil.assertFail();
+            } catch (NullPointerException e) {
+                // expected
+            }
+        }
+    }
+
+}
diff a/test/jdk/net/shipilev/magic/Timestamp.java b/test/jdk/net/shipilev/magic/Timestamp.java
--- /dev/null
+++ b/test/jdk/net/shipilev/magic/Timestamp.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020, Red Hat, Inc. 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.
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.timestamp* with 32-bit compressed oops
+ * @library /test/lib
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx128m
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   Timestamp
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.timestamp* with zero-based compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx4g
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   Timestamp
+ */
+
+/*
+ * @test
+ * @summary Test for Magic.timestamp* without compressed oops
+ * @library /test/lib
+ * @requires vm.bits == 64
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -Xint
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:TieredStopAtLevel=1
+ *                   Timestamp
+ *
+ * @run main/othervm -Xmx128m -XX:-UseCompressedOops
+ *                   -XX:+UnlockDiagnosticVMOptions -XX:+AbortVMOnCompilationFailure -Xcheck:jni
+ *                   -XX:-TieredCompilation
+ *                   Timestamp
+ */
+
+import java.lang.reflect.Field;
+
+import net.shipilev.Magic;
+
+public class Timestamp {
+
+    public static void main(String ... args) throws Exception {
+        test_timestamp();
+        test_timestampSerial();
+    }
+
+    private static void test_timestamp() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.timestamp());
+        }
+    }
+
+    private static void test_timestampSerial() throws Exception {
+        for (int c = 0; c < MagicUtil.ITERS; c++) {
+            MagicUtil.assertNotEquals(0, Magic.timestampSerial());
+        }
+    }
+}
