[vm] Remove code collection.

Code collection interacts badly with
 - warming up compiled code
 - retaining pre-compiled code
 - code coverage
 - hot reload (deopting to an old version of a function)

Change-Id: Id269a6c3281e577d4f600f0c158af9e62f6b49ea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/99722
Reviewed-by: Siva Annamalai <asiva@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
diff --git a/pkg/status_file/test/data/standalone_2_vm.status b/pkg/status_file/test/data/standalone_2_vm.status
index fd09ed8..01c5b89 100644
--- a/pkg/status_file/test/data/standalone_2_vm.status
+++ b/pkg/status_file/test/data/standalone_2_vm.status
@@ -48,7 +48,6 @@
 io/test_extension_test: Skip # Platform.executable
 io/test_extension_fail_test: Skip # Platform.executable
 io/platform_test: Skip # Platform.executable
-io/code_collection_test: Skip # Platform.executable
 full_coverage_test: Skip # Platform.executable
 regress_26031_test: Skip # Platform.resolvedExecutable
 
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index 6632130..e191728 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -843,9 +843,6 @@
 #if !defined(TARGET_ARCH_IA32)
     vm_options.AddArgument("--link_natives_lazily");
 #endif
-#if !defined(PRODUCT)
-    vm_options.AddArgument("--collect_code=false");
-#endif
   }
 
   char* error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index d0916b9..39d5959 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1076,9 +1076,6 @@
 
   if (Options::gen_snapshot_kind() == kAppJIT) {
     vm_options.AddArgument("--fields_may_be_reset");
-#if !defined(PRODUCT)
-    vm_options.AddArgument("--collect_code=false");
-#endif
   }
 #if defined(DART_PRECOMPILED_RUNTIME)
   vm_options.AddArgument("--precompilation");
diff --git a/runtime/vm/compilation_trace.cc b/runtime/vm/compilation_trace.cc
index 48db21c..af8d622 100644
--- a/runtime/vm/compilation_trace.cc
+++ b/runtime/vm/compilation_trace.cc
@@ -365,11 +365,6 @@
     return Object::null();
   }
 
-  // Prevent premature code collection due to major GC during startup.
-  if (function.usage_counter() < Function::kGraceUsageCounter) {
-    function.set_usage_counter(Function::kGraceUsageCounter);
-  }
-
   error_ = Compiler::CompileFunction(thread_, function);
   if (error_.IsError()) {
     return error_.raw();
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 92b725f..307c7ad 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1173,9 +1173,6 @@
   // immediate objects (Smis) or permanent objects (vm-isolate heap or
   // image pages). Here we choose to skip the barrier for any constant on
   // the assumption it will remain reachable through the object pool.
-  // TODO(concurrent-marking): Consider ensuring marking is not in progress
-  // when code is disabled or only omitting the barrier if code collection
-  // is disabled.
 
   return !BindsToConstant();
 }
diff --git a/runtime/vm/compiler/jit/compiler.cc b/runtime/vm/compiler/jit/compiler.cc
index 412e6b0..1a7fd29 100644
--- a/runtime/vm/compiler/jit/compiler.cc
+++ b/runtime/vm/compiler/jit/compiler.cc
@@ -101,7 +101,6 @@
 #endif
 
     FLAG_background_compilation = false;
-    FLAG_collect_code = false;
     FLAG_enable_mirrors = false;
     // TODO(dacoharkes): Ffi support in AOT
     // https://github.com/dart-lang/sdk/issues/35765
@@ -427,12 +426,6 @@
   }
 #endif  // !defined(PRODUCT)
 
-  if (function.is_intrinsic() &&
-      (function.usage_counter() < Function::kGraceUsageCounter)) {
-    // Intrinsic functions may execute without incrementing their usage counter.
-    // Give them a non-zero initial usage to prevent premature code collection.
-    function.set_usage_counter(Function::kGraceUsageCounter);
-  }
   if (!function.IsOptimizable()) {
     // A function with huge unoptimized code can become non-optimizable
     // after generating unoptimized code.
@@ -786,7 +779,6 @@
         }
         done = true;
       }
-
     }
   }
   return result->raw();
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index d7b662d..a406f01 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -58,7 +58,7 @@
   P(background_compilation, bool, USING_MULTICORE,                             \
     "Run optimizing compilation in background")                                \
   P(causal_async_stacks, bool, !USING_PRODUCT, "Improved async stacks")        \
-  P(collect_code, bool, true, "Attempt to GC infrequently used code.")         \
+  P(collect_code, bool, false, "Attempt to GC infrequently used code.")        \
   P(collect_dynamic_function_names, bool, true,                                \
     "Collects all dynamic function names to identify unique targets")          \
   P(compactor_tasks, int, 2,                                                   \
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 7ff24be..ec644c0 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -21,92 +21,6 @@
 
 namespace dart {
 
-// Collects a list of RawFunction whose code_ or unoptimized_code_ slots were
-// treated as weak (not visited) during marking because they had low usage.
-// These slots (and the corresponding entry_point_ caches) must be cleared after
-// marking if the target RawCode were not otherwise marked. (--collect-code)
-class SkippedCodeFunctions {
- public:
-  SkippedCodeFunctions() {}
-
-  void Add(RawFunction* func) {
-    // With concurrent mark, we hold raw pointers across safepoints.
-    ASSERT(func->IsOldObject());
-
-    skipped_code_functions_.Add(func);
-  }
-
-  void DetachCode() {
-#if defined(DART_PRECOMPILED_RUNTIME)
-    UNREACHABLE();
-#else
-    Thread* thread = Thread::Current();
-    StackZone zone(thread);  // For log prints.
-    HANDLESCOPE(thread);
-
-    intptr_t unoptimized_code_count = 0;
-    intptr_t current_code_count = 0;
-    for (int i = 0; i < skipped_code_functions_.length(); i++) {
-      RawFunction* func = skipped_code_functions_[i];
-      RawCode* code = func->ptr()->code_;
-      if (!code->IsMarked()) {
-        // If the code wasn't strongly visited through other references
-        // after skipping the function's code pointer, then we disconnect the
-        // code from the function.
-        if (FLAG_enable_interpreter && Function::HasBytecode(func)) {
-          func->StorePointer(&(func->ptr()->code_),
-                             StubCode::InterpretCall().raw());
-          uword entry_point = StubCode::InterpretCall().EntryPoint();
-          func->ptr()->entry_point_ = entry_point;
-          func->ptr()->unchecked_entry_point_ = entry_point;
-        } else {
-          func->StorePointer(&(func->ptr()->code_),
-                             StubCode::LazyCompile().raw());
-          uword entry_point = StubCode::LazyCompile().EntryPoint();
-          func->ptr()->entry_point_ = entry_point;
-          func->ptr()->unchecked_entry_point_ = entry_point;
-        }
-        if (FLAG_log_code_drop) {
-          // NOTE: This code runs while GC is in progress and runs within
-          // a NoHandleScope block. Hence it is not okay to use a regular Zone
-          // or Scope handle. We use a direct stack handle so the raw pointer in
-          // this handle is not traversed. The use of a handle is mainly to
-          // be able to reuse the handle based code and avoid having to add
-          // helper functions to the raw object interface.
-          String name;
-          name = func->ptr()->name_;
-          THR_Print("Detaching code: %s\n", name.ToCString());
-          current_code_count++;
-        }
-      }
-
-      code = func->ptr()->unoptimized_code_;
-      if (!code->IsMarked()) {
-        // If the code wasn't strongly visited through other references
-        // after skipping the function's code pointer, then we disconnect the
-        // code from the function.
-        func->StorePointer(&(func->ptr()->unoptimized_code_), Code::null());
-        if (FLAG_log_code_drop) {
-          unoptimized_code_count++;
-        }
-      }
-    }
-    if (FLAG_log_code_drop) {
-      THR_Print("  total detached current: %" Pd "\n", current_code_count);
-      THR_Print("  total detached unoptimized: %" Pd "\n",
-                unoptimized_code_count);
-    }
-    // Clean up.
-    skipped_code_functions_.Clear();
-#endif  // !DART_PRECOMPILED_RUNTIME
-  }
-
- private:
-  MallocGrowableArray<RawFunction*> skipped_code_functions_;
-
-  DISALLOW_COPY_AND_ASSIGN(SkippedCodeFunctions);
-};
-
 class MarkerWorkList : public ValueObject {
  public:
   explicit MarkerWorkList(MarkingStack* marking_stack)
@@ -172,8 +86,7 @@
   MarkingVisitorBase(Isolate* isolate,
                      PageSpace* page_space,
                      MarkingStack* marking_stack,
-                     MarkingStack* deferred_marking_stack,
-                     SkippedCodeFunctions* skipped_code_functions)
+                     MarkingStack* deferred_marking_stack)
       : ObjectPointerVisitor(isolate),
         thread_(Thread::Current()),
 #ifndef PRODUCT
@@ -185,7 +98,6 @@
         work_list_(marking_stack),
         deferred_work_list_(deferred_marking_stack),
         delayed_weak_properties_(NULL),
-        skipped_code_functions_(skipped_code_functions),
         marked_bytes_(0),
         marked_micros_(0) {
     ASSERT(thread_->isolate() == isolate);
@@ -198,7 +110,6 @@
   }
 
   ~MarkingVisitorBase() {
-    delete skipped_code_functions_;
 #ifndef PRODUCT
     delete[] class_stats_count_;
     delete[] class_stats_size_;
@@ -286,13 +197,6 @@
     }
   }
 
-  bool visit_function_code() const { return skipped_code_functions_ == NULL; }
-
-  virtual void add_skipped_code_function(RawFunction* func) {
-    ASSERT(!visit_function_code());
-    skipped_code_functions_->Add(func);
-  }
-
   void EnqueueWeakProperty(RawWeakProperty* raw_weak) {
     ASSERT(raw_weak->IsHeapObject());
     ASSERT(raw_weak->IsOldObject());
@@ -346,10 +250,6 @@
   // Called when all marking is complete.
   void Finalize() {
     work_list_.Finalize();
-    // Detach code from functions.
-    if (skipped_code_functions_ != NULL) {
-      skipped_code_functions_->DetachCode();
-    }
     // Clear pending weak properties.
     RawWeakProperty* cur_weak = delayed_weak_properties_;
     delayed_weak_properties_ = NULL;
@@ -447,7 +347,6 @@
   MarkerWorkList work_list_;
   MarkerWorkList deferred_work_list_;
   RawWeakProperty* delayed_weak_properties_;
-  SkippedCodeFunctions* skipped_code_functions_;
   uintptr_t marked_bytes_;
   int64_t marked_micros_;
 
@@ -881,7 +780,7 @@
   delete[] visitors_;
 }
 
-void GCMarker::StartConcurrentMark(PageSpace* page_space, bool collect_code) {
+void GCMarker::StartConcurrentMark(PageSpace* page_space) {
   isolate_->EnableIncrementalBarrier(&marking_stack_, &deferred_marking_stack_);
 
   const intptr_t num_tasks = FLAG_marker_tasks;
@@ -901,11 +800,8 @@
   ResetRootSlices();
   for (intptr_t i = 0; i < num_tasks; i++) {
     ASSERT(visitors_[i] == NULL);
-    SkippedCodeFunctions* skipped_code_functions =
-        collect_code ? new SkippedCodeFunctions() : NULL;
     visitors_[i] = new SyncMarkingVisitor(isolate_, page_space, &marking_stack_,
-                                          &deferred_marking_stack_,
-                                          skipped_code_functions);
+                                          &deferred_marking_stack_);
 
     // Begin marking on a helper thread.
     bool result = Dart::thread_pool()->Run(
@@ -920,7 +816,7 @@
   }
 }
 
-void GCMarker::MarkObjects(PageSpace* page_space, bool collect_code) {
+void GCMarker::MarkObjects(PageSpace* page_space) {
   if (isolate_->marking_stack() != NULL) {
     isolate_->DisableIncrementalBarrier();
   }
@@ -933,11 +829,8 @@
       TIMELINE_FUNCTION_GC_DURATION(thread, "Mark");
       int64_t start = OS::GetCurrentMonotonicMicros();
       // Mark everything on main thread.
-      SkippedCodeFunctions* skipped_code_functions =
-          collect_code ? new SkippedCodeFunctions() : NULL;
       UnsyncMarkingVisitor mark(isolate_, page_space, &marking_stack_,
-                                &deferred_marking_stack_,
-                                skipped_code_functions);
+                                &deferred_marking_stack_);
       ResetRootSlices();
       IterateRoots(&mark);
       mark.ProcessDeferredMarking();
@@ -965,11 +858,8 @@
           visitor = visitors_[i];
           visitors_[i] = NULL;
         } else {
-          SkippedCodeFunctions* skipped_code_functions =
-              collect_code ? new SkippedCodeFunctions() : NULL;
           visitor = new SyncMarkingVisitor(
-              isolate_, page_space, &marking_stack_, &deferred_marking_stack_,
-              skipped_code_functions);
+              isolate_, page_space, &marking_stack_, &deferred_marking_stack_);
         }
 
         bool result = Dart::thread_pool()->Run(new ParallelMarkTask(
diff --git a/runtime/vm/heap/marker.h b/runtime/vm/heap/marker.h
index 6108e21..9216445 100644
--- a/runtime/vm/heap/marker.h
+++ b/runtime/vm/heap/marker.h
@@ -35,11 +35,11 @@
   // Mark roots synchronously, then spawn tasks to concurrently drain the
   // marking queue. Only called when no marking or sweeping is in progress.
   // Marking must later be finalized by calling MarkObjects.
-  void StartConcurrentMark(PageSpace* page_space, bool collect_code);
+  void StartConcurrentMark(PageSpace* page_space);
 
   // (Re)mark roots, drain the marking queue and finalize weak references.
   // Does not required StartConcurrentMark to have been previously called.
-  void MarkObjects(PageSpace* page_space, bool collect_code);
+  void MarkObjects(PageSpace* page_space);
 
   intptr_t marked_words() const { return marked_bytes_ >> kWordSizeLog2; }
   intptr_t MarkedWordsPerMicro() const;
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 5ef2454..4f0b6fc 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -40,18 +40,6 @@
             print_free_list_after_gc,
             false,
             "Print free list statistics after a GC");
-DEFINE_FLAG(int,
-            code_collection_interval_in_us,
-            30000000,
-            "Time between attempts to collect unused code.");
-DEFINE_FLAG(bool,
-            log_code_drop,
-            false,
-            "Emit a log message when pointers to unused code are dropped.");
-DEFINE_FLAG(bool,
-            always_drop_code,
-            false,
-            "Always try to drop code if the function's usage counter is >= 0");
 DEFINE_FLAG(bool, log_growth, false, "Log PageSpace growth policy decisions.");
 
 HeapPage* HeapPage::Allocate(intptr_t size_in_words,
@@ -919,23 +907,6 @@
 }
 #endif  // PRODUCT
 
-bool PageSpace::ShouldCollectCode() {
-  // Try to collect code if enough time has passed since the last attempt.
-  const int64_t start = OS::GetCurrentMonotonicMicros();
-  const int64_t last_code_collection_in_us =
-      page_space_controller_.last_code_collection_in_us();
-
-  if ((start - last_code_collection_in_us) >
-      FLAG_code_collection_interval_in_us) {
-    if (FLAG_log_code_drop) {
-      OS::PrintErr("Trying to detach code.\n");
-    }
-    page_space_controller_.set_last_code_collection_in_us(start);
-    return true;
-  }
-  return false;
-}
-
 void PageSpace::WriteProtectCode(bool read_only) {
   if (FLAG_write_protect_code) {
     MutexLocker ml(pages_lock_);
@@ -1107,13 +1078,6 @@
   SpaceUsage usage_before = GetCurrentUsage();
 
   // Mark all reachable old-gen objects.
-#if defined(PRODUCT)
-  bool collect_code = FLAG_collect_code && ShouldCollectCode();
-#else
-  bool collect_code = FLAG_collect_code && ShouldCollectCode() &&
-                      !isolate->HasAttemptedReload();
-#endif  // !defined(PRODUCT)
-
   if (marker_ == NULL) {
     ASSERT(phase() == kDone);
     marker_ = new GCMarker(isolate, heap_);
@@ -1123,12 +1087,12 @@
 
   if (!finalize) {
     ASSERT(phase() == kDone);
-    marker_->StartConcurrentMark(this, collect_code);
+    marker_->StartConcurrentMark(this);
     return;
   }
 
   NOT_IN_PRODUCT(isolate->class_table()->ResetCountersOld());
-  marker_->MarkObjects(this, collect_code);
+  marker_->MarkObjects(this);
   usage_.used_in_words = marker_->marked_words() + allocated_black_in_words_;
   allocated_black_in_words_ = 0;
   mark_words_per_micro_ = marker_->MarkedWordsPerMicro();
@@ -1393,7 +1357,6 @@
       desired_utilization_((100.0 - heap_growth_ratio) / 100.0),
       heap_growth_max_(heap_growth_max),
       garbage_collection_time_ratio_(garbage_collection_time_ratio),
-      last_code_collection_in_us_(OS::GetCurrentMonotonicMicros()),
       idle_gc_threshold_in_words_(0) {
   intptr_t grow_heap = heap_growth_max / 2;
   gc_threshold_in_words_ =
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 8844ee7..c1608af 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -15,8 +15,6 @@
 
 namespace dart {
 
-DECLARE_FLAG(bool, log_code_drop);
-DECLARE_FLAG(bool, always_drop_code);
 DECLARE_FLAG(bool, write_protect_code);
 
 // Forward declarations.
@@ -227,11 +225,6 @@
                                  int64_t end);
   void EvaluateAfterLoading(SpaceUsage after);
 
-  int64_t last_code_collection_in_us() { return last_code_collection_in_us_; }
-  void set_last_code_collection_in_us(int64_t t) {
-    last_code_collection_in_us_ = t;
-  }
-
   void set_last_usage(SpaceUsage current) { last_usage_ = current; }
 
   void Enable() { is_enabled_ = true; }
@@ -261,10 +254,6 @@
   // we grow the heap more aggressively.
   const int garbage_collection_time_ratio_;
 
-  // The time in microseconds of the last time we tried to collect unused
-  // code.
-  int64_t last_code_collection_in_us_;
-
   // Perform a synchronous GC when capacity exceeds this amount.
   intptr_t gc_threshold_in_words_;
 
@@ -346,10 +335,6 @@
   RawObject* FindObject(FindObjectVisitor* visitor,
                         HeapPage::PageType type) const;
 
-  // Checks if enough time has elapsed since the last attempt to collect
-  // code.
-  bool ShouldCollectCode();
-
   // Collect the garbage in the page space using mark-sweep or mark-compact.
   void CollectGarbage(bool compact, bool finalize);
 
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index ae55ce6..92e2c88 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -69,7 +69,6 @@
 static void DeterministicModeHandler(bool value) {
   if (value) {
     FLAG_background_compilation = false;  // Timing dependent.
-    FLAG_collect_code = false;            // Timing dependent.
     FLAG_concurrent_mark = false;         // Timing dependent.
     FLAG_concurrent_sweep = false;        // Timing dependent.
     FLAG_random_seed = 0x44617274;  // "Dart"
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 8a191b4..b912fcb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1971,9 +1971,6 @@
 
 class Function : public Object {
  public:
-  // A value to prevent premature code collection. lg(32) = 5 major GCs.
-  static constexpr intptr_t kGraceUsageCounter = 32;
-
   RawString* name() const { return raw_ptr()->name_; }
   RawString* UserVisibleName() const;  // Same as scrubbed name.
   RawString* QualifiedScrubbedName() const {
@@ -7449,8 +7446,6 @@
   friend class TwoByteString;
   friend class ExternalOneByteString;
   friend class ExternalTwoByteString;
-  // So that SkippedCodeFunctions can print a debug string from a NoHandleScope.
-  friend class SkippedCodeFunctions;
   friend class RawOneByteString;
   friend class RODataSerializationCluster;  // SetHash
 };
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 78a9445..27d808f 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -427,6 +427,7 @@
 REGULAR_VISITOR(TypeRef)
 REGULAR_VISITOR(TypeParameter)
 REGULAR_VISITOR(PatchClass)
+REGULAR_VISITOR(Function)
 COMPRESSED_VISITOR(Closure)
 REGULAR_VISITOR(ClosureData)
 REGULAR_VISITOR(SignatureData)
@@ -495,73 +496,6 @@
 // Smi has no heap representation.
 UNREACHABLE_VISITOR(Smi)
 
-bool RawFunction::CheckUsageCounter(RawFunction* raw_fun) {
-  // NOTE: This code runs while GC is in progress and runs within
-  // a NoHandleScope block. Hence it is not okay to use regular Zone or
-  // Scope handles. We use direct stack handles, and so the raw pointers in
-  // these handles are not traversed. The use of handles is mainly to
-  // be able to reuse the handle based code and avoid having to add
-  // helper functions to the raw object interface.
-  Function fn;
-  fn = raw_fun;
-
-  // The function may not have code.
-  if (!fn.HasCode()) return false;
-  // These may not increment the usage counter.
-  if (fn.is_intrinsic()) return false;
-
-  if (fn.usage_counter() >= 0) {
-    fn.SetUsageCounter(fn.usage_counter() / 2);
-  }
-  return FLAG_always_drop_code || (fn.usage_counter() == 0);
-}
-
-bool RawFunction::ShouldVisitCode(RawCode* raw_code) {
-  // NOTE: This code runs while GC is in progress and runs within
-  // a NoHandleScope block. Hence it is not okay to use regular Zone or
-  // Scope handles. We use direct stack handles, and so the raw pointers in
-  // these handles are not traversed. The use of handles is mainly to
-  // be able to reuse the handle based code and avoid having to add
-  // helper functions to the raw object interface.
-  Code code;
-  code = raw_code;
-  if (code.IsNull()) return true;
-  if (code.is_optimized()) return true;
-  if (code.HasBreakpoint()) return true;
-  return false;
-}
-
-intptr_t RawFunction::VisitFunctionPointers(RawFunction* raw_obj,
-                                            ObjectPointerVisitor* visitor) {
-  if (visitor->visit_function_code() || !CheckUsageCounter(raw_obj)) {
-    visitor->VisitPointers(raw_obj->from(), raw_obj->to());
-    return Function::InstanceSize();
-  }
-#if defined(DART_PRECOMPILED_RUNTIME)
-  UNREACHABLE();
-#else
-  visitor->VisitPointers(raw_obj->from(), raw_obj->to_no_code());
-
-  visitor->VisitPointer(
-      reinterpret_cast<RawObject**>(&raw_obj->ptr()->bytecode_));
-
-  if (ShouldVisitCode(raw_obj->ptr()->code_)) {
-    visitor->VisitPointer(
-        reinterpret_cast<RawObject**>(&raw_obj->ptr()->code_));
-  } else {
-    visitor->add_skipped_code_function(raw_obj);
-  }
-
-  if (ShouldVisitCode(raw_obj->ptr()->unoptimized_code_)) {
-    visitor->VisitPointer(
-        reinterpret_cast<RawObject**>(&raw_obj->ptr()->unoptimized_code_));
-  } else {
-    visitor->add_skipped_code_function(raw_obj);
-  }
-#endif
-  return Function::InstanceSize();
-}
-
 bool RawCode::ContainsPC(RawObject* raw_obj, uword pc) {
   if (raw_obj->IsCode()) {
     RawCode* raw_code = static_cast<RawCode*>(raw_obj);
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3967064..05d60dd 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -693,7 +693,6 @@
   friend class SizeExcludingClassVisitor;  // GetClassId
   friend class InstanceAccumulator;        // GetClassId
   friend class RetainingPathVisitor;       // GetClassId
-  friend class SkippedCodeFunctions;       // StorePointer
   friend class ImageReader;                // tags_ check
   friend class ImageWriter;
   friend class AssemblyImageWriter;
@@ -875,15 +874,10 @@
   static constexpr intptr_t kMaxOptionalParametersBits = 14;
 
  private:
-  // So that the SkippedCodeFunctions::DetachCode can null out the code fields.
-  friend class SkippedCodeFunctions;
   friend class Class;
 
   RAW_HEAP_OBJECT_IMPLEMENTATION(Function);
 
-  static bool ShouldVisitCode(RawCode* raw_code);
-  static bool CheckUsageCounter(RawFunction* raw_fun);
-
   uword entry_point_;  // Accessed from generated code.
   uword unchecked_entry_point_;  // Accessed from generated code.
 
@@ -1329,7 +1323,6 @@
   friend class Function;
   template <bool>
   friend class MarkingVisitorBase;
-  friend class SkippedCodeFunctions;
   friend class StackFrame;
   friend class Profiler;
   friend class FunctionDeserializationCluster;
@@ -1415,7 +1408,6 @@
   friend class StackFrame;
   template <bool>
   friend class MarkingVisitorBase;
-  friend class SkippedCodeFunctions;
   friend class Function;
   friend class ImageReader;
   friend class ImageWriter;
diff --git a/runtime/vm/visitor.h b/runtime/vm/visitor.h
index 4eac814..165aa3e 100644
--- a/runtime/vm/visitor.h
+++ b/runtime/vm/visitor.h
@@ -37,8 +37,6 @@
   // Range of pointers to visit 'first' <= pointer <= 'last'.
   virtual void VisitPointers(RawObject** first, RawObject** last) = 0;
 
-  virtual bool visit_function_code() const { return true; }
-  virtual void add_skipped_code_function(RawFunction* funct) { UNREACHABLE(); }
   // len argument is the number of pointers to visit starting from 'p'.
   void VisitPointers(RawObject** p, intptr_t len) {
     VisitPointers(p, (p + len - 1));
diff --git a/tests/standalone_2/io/code_collection_test.dart b/tests/standalone_2/io/code_collection_test.dart
deleted file mode 100644
index 71f36b6..0000000
--- a/tests/standalone_2/io/code_collection_test.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Dart test program testing code GC.
-
-import "package:expect/expect.dart";
-import "dart:async";
-import "dart:io";
-
-int foo(int x) {
-  x = x + 1;
-  // Print marker message while foo is on the stack so the code cannot be
-  // collected.
-  stderr.write("foo=$x\n");
-  return x;
-}
-
-List<int> bar() {
-  // A couple of big allocations trigger GC.
-  var l = new List.filled(700000, 7);
-  return l;
-}
-
-doTest() {
-  var i = 0;
-  var ret = foo(1); // Initial call to compile.
-  // Time passes, GC runs, foo's code is dropped.
-  var ms = const Duration(milliseconds: 100);
-  var t = new Timer.periodic(ms, (timer) {
-    i++;
-    // Calling bar will trigger GC without foo being on the stack. This way
-    // the method can be collected.
-    bar();
-    if (i > 1) {
-      timer.cancel();
-      // foo is called again to make sure we can still run it even after
-      // its code has been detached.
-      var ret = foo(2);
-      // GC after here may collect the second compilation of foo.
-    }
-  });
-}
-
-List<String> packageOptions() {
-  if (Platform.packageRoot != null) {
-    return <String>['--package-root=${Platform.packageRoot}'];
-  } else if (Platform.packageConfig != null) {
-    return <String>['--packages=${Platform.packageConfig}'];
-  } else {
-    return <String>[];
-  }
-}
-
-main(List<String> arguments) {
-  if (arguments.contains("--run")) {
-    doTest();
-  } else {
-    // Run the test and capture stderr.
-    var args = packageOptions();
-    args.addAll([
-      "--verbose-gc",
-      "--collect-code",
-      "--code-collection-interval-in-us=0",
-      "--old_gen_growth_rate=10",
-      "--log-code-drop",
-      "--optimization-counter-threshold=-1",
-      Platform.script.toFilePath(),
-      "--run"
-    ]);
-    print("+ ${Platform.executable} ${args.join(' ')}");
-    var pr = Process.runSync(Platform.executable, args);
-
-    print(pr.stderr);
-    Expect.equals(0, pr.exitCode);
-
-    // Code drops are logged with --log-code-drop. Look through stderr for the
-    // message that foo's code was dropped.
-    bool saw_foo2 = false;
-    bool saw_detaching_foo = false;
-    bool saw_foo3 = false;
-    pr.stderr.split("\n").forEach((line) {
-      if (line.contains("foo=2")) {
-        Expect.isFalse(saw_foo2, "foo=2 ran twice");
-        saw_foo2 = true;
-      }
-      if (line.contains("Detaching code") && line.contains("foo")) {
-        Expect.isTrue(saw_foo2, "foo detached before running");
-        // May detach twice.
-        saw_detaching_foo = true;
-      }
-      if (line.contains("foo=3")) {
-        Expect.isFalse(saw_foo3, "foo=3 ran twice");
-        Expect.isTrue(saw_detaching_foo, "foo should have been collected");
-        saw_foo3 = true;
-      }
-    });
-
-    Expect.isTrue(saw_foo2, "Missing foo=2");
-    Expect.isTrue(saw_detaching_foo, "Missing code collection for foo");
-    Expect.isTrue(saw_foo3, "Missing foo=3");
-  }
-}
diff --git a/tests/standalone_2/standalone_2_kernel.status b/tests/standalone_2/standalone_2_kernel.status
index ceb859a..5bece55 100644
--- a/tests/standalone_2/standalone_2_kernel.status
+++ b/tests/standalone_2/standalone_2_kernel.status
@@ -73,7 +73,6 @@
 
 # The failures below still need to be investigated and possibly fixed, or marked as skipped.
 [ $compiler == dartkb && $strong ]
-io/code_collection_test: RuntimeError # Reruns the same script (dill file without AST) without passing --enable-interpreter or --use-bytecode-compiler.
 io/dart_std_io_pipe_test: Pass, Timeout # Please triage
 io/platform_resolved_executable_test/00: RuntimeError # Reruns the same script (dill file without AST) without passing --enable-interpreter or --use-bytecode-compiler.
 io/platform_resolved_executable_test/01: RuntimeError # Reruns the same script (dill file without AST) without passing --enable-interpreter or --use-bytecode-compiler.
diff --git a/tests/standalone_2/standalone_2_precompiled.status b/tests/standalone_2/standalone_2_precompiled.status
index 64e4609..3209e7b 100644
--- a/tests/standalone_2/standalone_2_precompiled.status
+++ b/tests/standalone_2/standalone_2_precompiled.status
@@ -79,5 +79,4 @@
 package/scenarios/packages_option_only/packages_option_only_test: Skip
 
 [ $mode == product || $runtime == dart_precompiled ]
-io/code_collection_test: Skip # Incompatible flags
 no_assert_test: SkipByDesign # Requires checked mode.
diff --git a/tests/standalone_2/standalone_2_vm.status b/tests/standalone_2/standalone_2_vm.status
index bc23a30..f6f03df 100644
--- a/tests/standalone_2/standalone_2_vm.status
+++ b/tests/standalone_2/standalone_2_vm.status
@@ -8,7 +8,6 @@
 
 [ $compiler == app_jit ]
 full_coverage_test: Skip # Platform.executable
-io/code_collection_test: Skip # Platform.executable
 io/namespace_test: RuntimeError # Issue 33168
 io/platform_resolved_executable_test/00: RuntimeError # Issue 33168
 io/platform_resolved_executable_test/01: RuntimeError # Issue 33168
@@ -93,7 +92,6 @@
 io/file_constructor_test: RuntimeError
 
 [ $runtime == vm && ($arch == arm || $arch == arm64) ]
-io/code_collection_test: Timeout, Pass
 io/dart_std_io_pipe_test: Timeout, Pass
 io/file_input_stream_test: Skip # Issue 26109
 io/file_stream_test: Skip # Issue 26109
@@ -101,7 +99,6 @@
 io/process_sync_test: Timeout, Pass
 
 [ $runtime == vm && ($arch == simarm || $arch == simarm64) ]
-io/code_collection_test: Timeout, Pass
 io/dart_std_io_pipe_test: Timeout, Pass
 io/http_client_stays_alive_test: Skip # Spawns process in Dart2 mode.
 io/process_sync_test: Timeout, Pass