diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 54b038b..b5f4326 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -130,47 +130,102 @@ function drupal_theme_rebuild() {
  *   The functions found, suitable for returning from hook_theme;
  */
 function drupal_find_theme_functions($cache, $prefixes) {
-  $implementations = [];
-  $grouped_functions = \Drupal::service('theme.registry')->getPrefixGroupedUserFunctions();
+  $implementations_grouped = array();
 
-  foreach ($cache as $hook => $info) {
-    foreach ($prefixes as $prefix) {
-      // Find theme functions that implement possible "suggestion" variants of
-      // registered theme hooks and add those as new registered theme hooks.
-      // The 'pattern' key defines a common prefix that all suggestions must
-      // start with. The default is the name of the hook followed by '__'. An
-      // 'base hook' key is added to each entry made for a found suggestion,
-      // so that common functionality can be implemented for all suggestions of
-      // the same base hook. To keep things simple, deep hierarchy of
-      // suggestions is not supported: each suggestion's 'base hook' key
-      // refers to a base hook, not to another suggestion, and all suggestions
-      // are found using the base hook's pattern, not a pattern from an
-      // intermediary suggestion.
-      $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
-      // Grep only the functions which are within the prefix group.
-      list($first_prefix,) = explode('_', $prefix, 2);
-      if (!isset($info['base hook']) && !empty($pattern) && isset($grouped_functions[$first_prefix])) {
-        $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $grouped_functions[$first_prefix]);
-        if ($matches) {
-          foreach ($matches as $match) {
-            $new_hook = substr($match, strlen($prefix) + 1);
-            $arg_name = isset($info['variables']) ? 'variables' : 'render element';
-            $implementations[$new_hook] = array(
-              'function' => $match,
-              $arg_name => $info[$arg_name],
-              'base hook' => $hook,
-            );
-          }
-        }
+  $weights = array_flip(array_keys($cache));
+
+  $functions = get_defined_functions()['user'];
+
+  if (count($prefixes) > 1) {
+    // Pre-filter the defined functions, to speed up the prefix-specific
+    // preg_grep() further below.
+    $functions = preg_grep('/^(' . implode('|', $prefixes) . ')_/', $functions);
+  }
+
+  // Analyze defined functions for $prefix . '_' . $hook.
+  $functions_by_hook = array();
+  foreach ($prefixes as $prefix) {
+    $prefix_strlen_1 = strlen($prefix) + 1;
+    foreach (preg_grep('/^' . $prefix . '_/', $functions) as $function) {
+      $hook = substr($function, $prefix_strlen_1);
+      // Overwrite implementations from other prefixes with lesser importance.
+      $functions_by_hook[$hook] = $function;
+    }
+  }
+
+  // Array of possible hooks in defined functions.
+  $hooks = array_keys($functions_by_hook);
+
+  // Check for $prefix . '_' . $base_hook . '__' . $suffix theme implementations.
+  foreach (preg_grep('/__/', $hooks) as $specialized_hook) {
+    $pos = -1;
+    while (FALSE !== $pos = strpos($specialized_hook, '__', $pos + 1)) {
+      $base_hook = substr($specialized_hook, 0, $pos);
+      if (!array_key_exists($base_hook, $cache)) {
+        continue;
       }
-      // Find theme functions that implement registered theme hooks and include
-      // that in what is returned so that the registry knows that the theme has
-      // this implementation.
-      if (function_exists($prefix . '_' . $hook)) {
-        $implementations[$hook] = array(
-          'function' => $prefix . '_' . $hook,
-        );
+      $info = $cache[$base_hook];
+      if (isset($info['pattern']) && !empty($info['pattern']) && $base_hook . '__' !== $info['pattern']) {
+        // This hook has a dedicated pattern, and will be dealt with further below instead of here.
+        continue;
       }
+      if (isset($info['base hook'])) {
+        continue;
+      }
+      $weight = $weights[$base_hook];
+      $arg_name = isset($info['variables']) ? 'variables' : 'render element';
+      $implementations_grouped[$weight][$specialized_hook] = array(
+        'function' => $functions_by_hook[$specialized_hook],
+        $arg_name => $info[$arg_name],
+        'base hook' => $base_hook,
+      );
+    }
+  }
+
+  // Check for $prefix . '_' . $pattern . $suffix theme implementations, where
+  // $pattern is something different than $base_hook . '__'.
+  foreach ($cache as $base_hook => $info) {
+    if (!isset($info['pattern'])) {
+      continue;
+    }
+    if (isset($info['base hook'])) {
+      // This is already an override.
+      continue;
+    }
+    $pattern = $info['pattern'];
+    if ($base_hook . '__' === $pattern || empty($pattern)) {
+      // This is just the default pattern, which is dealt with above.
+      continue;
+    }
+    $arg_name = isset($info['variables']) ? 'variables' : 'render element';
+    $weight = $weights[$base_hook];
+    foreach (preg_grep('/^' . $pattern . '/', $hooks) as $specialized_hook) {
+      $implementations_grouped[$weight][$specialized_hook] = array(
+        'function' => $functions_by_hook[$specialized_hook],
+        $arg_name => $info[$arg_name],
+        'base hook' => $base_hook,
+      );
+    }
+  }
+
+  // Check for regular $prefix . '_' . $base_hook theme implementations.
+  foreach ($functions_by_hook as $base_hook_candidate => $function) {
+    // Check if $base_hook_candidate is really a base hook.
+    if (!array_key_exists($base_hook_candidate, $cache)) {
+      continue;
+    }
+    $weight = $weights[$base_hook_candidate];
+    $implementations_grouped[$weight][$base_hook_candidate] = array(
+      'function' => $function,
+    );
+  }
+
+  // Sort by weight, and flatten the array.
+  ksort($implementations_grouped, SORT_NUMERIC);
+  $implementations = array();
+  foreach ($implementations_grouped as $weight => $weight_implementations) {
+    foreach ($weight_implementations as $base_hook => $implementation) {
+      $implementations[$base_hook] = $implementation;
     }
   }
 
