   # This function receives the manifest entries and some source
   # files that have changed. It then, recursively, figures out
   # all the files that changed (via the module dependencies) and
-  # return their sources as the remaining entries.
+  # return the non-changed entries and the removed sources.
   defp remove_stale_entries(all, []) do
     {all, []}
   end
 
   defp remove_stale_entries(all, changed) do
-    remove_stale_entries(all, :lists.usort(changed), [], [])
-  end
-
-  defp remove_stale_entries([{beam, module, source, _d, _f, _bin} = entry|t], changed, removed, acc) do
-    if source in changed do
-      _ = File.rm(beam)
-      _ = :code.purge(module)
-      _ = :code.delete(module)
-      remove_stale_entries(t, changed, [module|removed], acc)
+    remove_stale_entries(all, HashSet.new, Enum.into(changed, HashSet.new))
+  end
+
+  defp remove_stale_entries(entries, old_stale, old_removed) do
+    {rest, new_stale, new_removed} =
+      Enum.reduce entries, {[], old_stale, old_removed}, &remove_stale_entry/2
+
+    if HashSet.size(new_stale) > HashSet.size(old_stale) or
+       HashSet.size(new_removed) > HashSet.size(old_removed) do
+      remove_stale_entries(rest, new_stale, new_removed)
     else
-      remove_stale_entries(t, changed, removed, [entry|acc])
-    end
-  end
-
-  defp remove_stale_entries([], changed, removed, acc) do
-    # If any of the dependencies for the remaining entries
-    # were removed, get its source so we can remove them.
-    next_changed = for {_b, _m, source, deps, _f, _bin} <- acc,
-                    Enum.any?(deps, &(&1 in removed)),
-                    do: source
-
-    {acc, next} = remove_stale_entries(Enum.reverse(acc), next_changed)
-    {acc, next ++ changed}
+      {rest, Enum.to_list(new_removed)}
+    end
+  end
+
+  defp remove_stale_entry({beam, module, source, compile, runtime, _f, _bin} = entry,
+                          {rest, stale, removed}) do
+    cond do
+      # If I changed in disk or have a compile time dependency
+      # on something stale, I need to be recompiled.
+      source in removed or Enum.any?(compile, &(&1 in stale)) ->
+        _ = File.rm(beam)
+        _ = :code.purge(module)
+        _ = :code.delete(module)
+        {rest, HashSet.put(stale, module), HashSet.put(removed, source)}
+
+      # If I have a runtime time dependency on something stale,
+      # I am stale too.
+      Enum.any?(runtime, &(&1 in stale)) ->
+        {[entry|rest], HashSet.put(stale, module), removed}
+
+      # Otherwise, we don't store it anywhere
+      true ->
+        {[entry|rest], stale, removed}
+    end
   end
 
   ## Manifest handling

        # Otherwise let's start with the new ones
        # plus the ones that have changed
        for(source <- all,
            not Enum.any?(all_entries, fn {_b, _m, s, _d, _f, _bin} -> s == source end),
            do: source)
          ++
        for({_b, _m, source, _d, files, _bin} <- all_entries,
            times = Enum.map([source|files], &HashDict.fetch!(all_mtimes, &1)),
            Mix.Utils.stale?(times, [modified]),
            do: source)

                do: relative

    source = Path.relative_to(source, cwd)
    tuple  = {beam, module, source, compile, runtime, files, binary}
    Agent.cast pid, &:lists.keystore(beam, 1, &1, tuple)
  end

  defp get_external_resources(module) do
