[vm, gc] Don't enqueue pre-marked Instructions.

Change-Id: Ic9a3b5f83fc45e363162c0531d474a663d243c6c
Reviewed-on: https://dart-review.googlesource.com/c/92666
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 5dc41bb..c246f43 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -368,12 +368,6 @@
   }
 
   static bool TryAcquireMarkBit(RawObject* raw_obj) {
-    // While it might seem this is redundant with TryAcquireMarkBit, we must
-    // do this check first to avoid attempting an atomic::fetch_and on the
-    // read-only vm-isolate or image pages, which can fault even if there is no
-    // change in the value.
-    if (raw_obj->IsMarked()) return false;
-
     if (!sync) {
       raw_obj->SetMarkBitUnsynchronized();
       return true;
@@ -383,17 +377,28 @@
   }
 
   void MarkObject(RawObject* raw_obj) {
-    // Fast exit if the raw object is a Smi.
+    // Fast exit if the raw object is immediate or in new space. No memory
+    // access.
     if (raw_obj->IsSmiOrNewObject()) {
       return;
     }
 
+    // While it might seem this is redundant with TryAcquireMarkBit, we must
+    // do this check first to avoid attempting an atomic::fetch_and on the
+    // read-only vm-isolate or image pages, which can fault even if there is no
+    // change in the value.
+    // Doing this before checking for an Instructions object avoids
+    // unnecessary queueing of pre-marked objects.
+    if (raw_obj->IsMarked()) {
+      return;
+    }
+
     intptr_t class_id = raw_obj->GetClassId();
     ASSERT(class_id != kFreeListElement);
 
     if (sync && UNLIKELY(class_id == kInstructionsCid)) {
-      // If this is the concurrent marker, instruction pages may be
-      // non-writable.
+      // If this is the concurrent marker, this object may be non-writable due
+      // to W^X (--write-protect-code).
       deferred_work_list_.Push(raw_obj);
       return;
     }