diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index c637fafc8b5..c4a23d8882d 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -1240,19 +1240,12 @@ public:
 
   // Determine if an object is dead, given the object and also
   // the region to which the object belongs.
-  bool is_obj_dead(const oop obj, const HeapRegion* hr) const {
-    return hr->is_obj_dead(obj, _cm->prev_mark_bitmap());
-  }
+  inline bool is_obj_dead(const oop obj, const HeapRegion* hr) const;
 
   // This function returns true when an object has been
   // around since the previous marking and hasn't yet
   // been marked during this marking, and is not in a closed archive region.
-  bool is_obj_ill(const oop obj, const HeapRegion* hr) const {
-    return
-      !hr->obj_allocated_since_next_marking(obj) &&
-      !is_marked_next(obj) &&
-      !hr->is_closed_archive();
-  }
+  inline bool is_obj_ill(const oop obj, const HeapRegion* hr) const;
 
   // Determine if an object is dead, given only the object itself.
   // This will find the region to which the object belongs and
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
index cb7b3d9034e..20f66698ec7 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp
@@ -32,6 +32,7 @@
 #include "gc/g1/g1EvacFailureRegions.hpp"
 #include "gc/g1/g1Policy.hpp"
 #include "gc/g1/g1RemSet.hpp"
+#include "gc/g1/heapRegion.inline.hpp"
 #include "gc/g1/heapRegionManager.inline.hpp"
 #include "gc/g1/heapRegionRemSet.hpp"
 #include "gc/g1/heapRegionSet.inline.hpp"
@@ -207,6 +208,10 @@ inline bool G1CollectedHeap::is_in_young(const oop obj) {
   return heap_region_containing(obj)->is_young();
 }
 
+inline bool G1CollectedHeap::is_obj_dead(const oop obj, const HeapRegion* hr) const {
+  return hr->is_obj_dead(obj, _cm->prev_mark_bitmap());
+}
+
 inline bool G1CollectedHeap::is_obj_dead(const oop obj) const {
   if (obj == NULL) {
     return false;
@@ -214,6 +219,13 @@ inline bool G1CollectedHeap::is_obj_dead(const oop obj) const {
   return is_obj_dead(obj, heap_region_containing(obj));
 }
 
+inline bool G1CollectedHeap::is_obj_ill(const oop obj, const HeapRegion* hr) const {
+  return
+    !hr->obj_allocated_since_next_marking(obj) &&
+    !is_marked_next(obj) &&
+    !hr->is_closed_archive();
+}
+
 inline bool G1CollectedHeap::is_obj_ill(const oop obj) const {
   if (obj == NULL) {
     return false;
diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
index 58326d39aa5..ab08bfc8567 100644
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp
@@ -210,14 +210,7 @@ void G1ParScanThreadState::do_oop_evac(T* p) {
   }
   RawAccess<IS_NOT_NULL>::oop_store(p, obj);
 
-  assert(obj != NULL, "Must be");
-  if (HeapRegion::is_in_same_region(p, obj)) {
-    return;
-  }
-  HeapRegion* from = _g1h->heap_region_containing(p);
-  if (!from->is_young()) {
-    enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj);
-  }
+  write_ref_field_post(p, obj);
 }
 
 MAYBE_INLINE_EVACUATION
diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
index 0997d21ea52..fda24532aa4 100644
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp
@@ -25,12 +25,9 @@
 #ifndef SHARE_GC_G1_G1PARSCANTHREADSTATE_HPP
 #define SHARE_GC_G1_G1PARSCANTHREADSTATE_HPP
 
-#include "gc/g1/g1CardTable.hpp"
 #include "gc/g1/g1CollectedHeap.hpp"
 #include "gc/g1/g1RedirtyCardsQueue.hpp"
 #include "gc/g1/g1OopClosures.hpp"
-#include "gc/g1/g1RemSet.hpp"
-#include "gc/g1/heapRegionRemSet.inline.hpp"
 #include "gc/shared/ageTable.hpp"
 #include "gc/shared/copyFailedInfo.hpp"
 #include "gc/shared/partialArrayTaskStepper.hpp"
@@ -40,9 +37,10 @@
 #include "oops/oop.hpp"
 #include "utilities/ticks.hpp"
 
+class G1CardTable;
+class G1EvacuationRootClosures;
 class G1OopStarChunkedList;
 class G1PLABAllocator;
-class G1EvacuationRootClosures;
 class HeapRegion;
 class PreservedMarks;
 class PreservedMarksSet;
@@ -60,7 +58,7 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
   AgeTable _age_table;
   // Local tenuring threshold.
   uint _tenuring_threshold;
-  G1ScanEvacuatedObjClosure  _scanner;
+  G1ScanEvacuatedObjClosure _scanner;
 
   uint _worker_id;
 
@@ -104,8 +102,6 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
   EvacuationFailedInfo _evacuation_failed_info;
   G1EvacFailureRegions* _evac_failure_regions;
 
-  void handle_evacuation_failure_notifications(oop obj, markWord m, size_t word_sz);
-
 public:
   G1ParScanThreadState(G1CollectedHeap* g1h,
                        G1RedirtyCardsQueueSet* rdcqs,
@@ -130,28 +126,16 @@ public:
 
   void push_on_queue(ScannerTask task);
 
-  template <class T> void enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) {
-    assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already.");
-    assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already.");
+  // Apply the post barrier to the given reference field. Enqueues the card of p
+  // if the barrier does not filter out the reference for some reason (e.g.
+  // p and q are in the same region, p is in survivor)
+  // To be called during GC if nothing particular about p and obj are known.
+  template <class T> void write_ref_field_post(T* p, oop obj);
 
-#ifdef ASSERT
-    HeapRegion* const hr_obj = _g1h->heap_region_containing(o);
-    assert(region_attr.needs_remset_update() == hr_obj->rem_set()->is_tracked(),
-           "State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u",
-           BOOL_TO_STR(region_attr.needs_remset_update()),
-           BOOL_TO_STR(hr_obj->rem_set()->is_tracked()),
-           hr_obj->hrm_index());
-#endif
-    if (!region_attr.needs_remset_update()) {
-      return;
-    }
-    size_t card_index = ct()->index_for(p);
-    // If the card hasn't been added to the buffer, do it.
-    if (_last_enqueued_card != card_index) {
-      _rdc_local_qset.enqueue(ct()->byte_for_index(card_index));
-      _last_enqueued_card = card_index;
-    }
-  }
+  // Enqueue the card if the reference's target region's remembered set is tracked.
+  // Assumes that a significant amount of pre-filtering (like done by
+  // write_ref_field_post() above) has already been performed.
+  template <class T> void enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o);
 
   G1EvacuationRootClosures* closures() { return _closures; }
   uint worker_id() { return _worker_id; }
diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp
index db117c50611..1184919dbf2 100644
--- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp
+++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021, 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
@@ -27,6 +27,7 @@
 
 #include "gc/g1/g1ParScanThreadState.hpp"
 
+#include "gc/g1/g1CardTable.hpp"
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1OopStarChunkedList.inline.hpp"
 #include "gc/g1/g1RemSet.hpp"
@@ -95,4 +96,38 @@ G1OopStarChunkedList* G1ParScanThreadState::oops_into_optional_region(const Heap
   return &_oops_into_optional_regions[hr->index_in_opt_cset()];
 }
 
+template <class T> void G1ParScanThreadState::write_ref_field_post(T* p, oop obj) {
+  assert(obj != NULL, "Must be");
+  if (HeapRegion::is_in_same_region(p, obj)) {
+    return;
+  }
+  HeapRegion* from = _g1h->heap_region_containing(p);
+  if (!from->is_young()) {
+    enqueue_card_if_tracked(_g1h->region_attr(obj), p, obj);
+  }
+}
+
+template <class T> void G1ParScanThreadState::enqueue_card_if_tracked(G1HeapRegionAttr region_attr, T* p, oop o) {
+  assert(!HeapRegion::is_in_same_region(p, o), "Should have filtered out cross-region references already.");
+  assert(!_g1h->heap_region_containing(p)->is_young(), "Should have filtered out from-young references already.");
+
+#ifdef ASSERT
+  HeapRegion* const hr_obj = _g1h->heap_region_containing(o);
+  assert(region_attr.needs_remset_update() == hr_obj->rem_set()->is_tracked(),
+         "State flag indicating remset tracking disagrees (%s) with actual remembered set (%s) for region %u",
+         BOOL_TO_STR(region_attr.needs_remset_update()),
+         BOOL_TO_STR(hr_obj->rem_set()->is_tracked()),
+         hr_obj->hrm_index());
+#endif
+  if (!region_attr.needs_remset_update()) {
+    return;
+  }
+  size_t card_index = ct()->index_for(p);
+  // If the card hasn't been added to the buffer, do it.
+  if (_last_enqueued_card != card_index) {
+    _rdc_local_qset.enqueue(ct()->byte_for_index(card_index));
+    _last_enqueued_card = card_index;
+  }
+}
+
 #endif // SHARE_GC_G1_G1PARSCANTHREADSTATE_INLINE_HPP