diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 1791efe..6aa0ffd 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -211,79 +211,15 @@ public function getLocalTasksForRoute($route_name) {
         $definitions = $this->getDefinitions();
         // We build the hierarchy by finding all tabs that should
         // appear on the current route.
-        $base_routes = array();
-        $parents = array();
+        list($definitions, $base_routes, $parents) = $this->calculateHierarchyTaskInformation($route_name, $definitions);
         $children = array();
-        foreach ($definitions as $plugin_id => $task_info) {
-          // Fill in the base_route from the parent to insure consistency.
-          if (!empty($task_info['parent_id']) && !empty($definitions[$task_info['parent_id']])) {
-            $task_info['base_route'] = $definitions[$task_info['parent_id']]['base_route'];
-            // Populate the definitions we use in the next loop. Using a
-            // reference like &$task_info causes bugs.
-            $definitions[$plugin_id]['base_route'] = $definitions[$task_info['parent_id']]['base_route'];
-          }
-          if ($route_name == $task_info['route_name']) {
-            if(!empty($task_info['base_route'])) {
-              $base_routes[$task_info['base_route']] = $task_info['base_route'];
-            }
-            // Tabs that link to the current route are viable parents
-            // and their parent and children should be visible also.
-            // @todo - this only works for 2 levels of tabs.
-            // instead need to iterate up.
-            $parents[$plugin_id] = TRUE;
-            if (!empty($task_info['parent_id'])) {
-              $parents[$task_info['parent_id']] = TRUE;
-            }
-          }
-        }
         if ($base_routes) {
-          // Find all the plugins with the same root and that are at the top
-          // level or that have a visible parent.
-          foreach ($definitions  as $plugin_id => $task_info) {
-            if (!empty($base_routes[$task_info['base_route']]) && (empty($task_info['parent_id']) || !empty($parents[$task_info['parent_id']]))) {
-              // Concat '> ' with root ID for the parent of top-level tabs.
-              $parent = empty($task_info['parent_id']) ? '> ' . $task_info['base_route'] : $task_info['parent_id'];
-              $children[$parent][$plugin_id] = $task_info;
-            }
-          }
+          $children = $this->findBaseRouteChildren($definitions, $base_routes, $parents);
         }
-        $data = array(
-          'base_routes' => $base_routes,
-          'parents' => $parents,
-          'children' => $children,
-        );
-        $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, Cache::PERMANENT, $this->cacheTags);
-      }
-      // Create a plugin instance for each element of the hierarchy.
-      foreach ($base_routes as $base_route) {
-        // Convert the tree keyed by plugin IDs into a simple one with
-        // integer depth.  Create instances for each plugin along the way.
-        $level = 0;
-        // We used this above as the top-level parent array key.
-        $next_parent = '> ' . $base_route;
-        do {
-          $parent = $next_parent;
-          $next_parent = FALSE;
-          foreach ($children[$parent] as $plugin_id => $task_info) {
-            $plugin = $this->createInstance($plugin_id);
-            $this->instances[$route_name][$level][$plugin_id] = $plugin;
-            // Normally, the link generator compares the href of every link with
-            // the current path and sets the active class accordingly. But the
-            // parents of the current local task may be on a different route in
-            // which case we have to set the class manually by flagging it
-            // active.
-            if (!empty($parents[$plugin_id]) && $route_name != $task_info['route_name']) {
-              $plugin->setActive();
-            }
-            if (isset($children[$plugin_id])) {
-              // This tab has visible children.
-              $next_parent = $plugin_id;
-            }
-          }
-          $level++;
-        } while ($next_parent);
+        $this->setLocalTasksCache($route_name, $base_routes, $parents, $children);
       }
 
+      $this->instances = $this->instanciatePluginInstances($route_name, $base_routes, $children, $parents) + $this->instances;
     }
     return $this->instances[$route_name];
   }
@@ -415,4 +351,141 @@ protected function isRouteActive($current_route_name, $route_name, $route_parame
     return $active;
   }
 
+  /**
+   * Find all plugins with the same root.
+   *
+   * Find all the plugins with the same root and that are at the top level or
+   * that have a visible parent.
+   *
+   * @param array $definitions
+   *   An array of all plugin definitions.
+   * @param string[] $base_routes
+   *   A list of all base route names.
+   * @param bool[] $parents
+   *   An array keyed by parent ID and boolean whether its a local task parent.
+   *
+   * @return array
+   *   An array of plugin information keyed by parent ID and plugin ID.
+   */
+  protected function findBaseRouteChildren(array $definitions, array $base_routes, array $parents) {
+    $children = [];
+    foreach ($definitions as $plugin_id => $task_info) {
+      if (!empty($base_routes[$task_info['base_route']]) && (empty($task_info['parent_id']) || !empty($parents[$task_info['parent_id']]))) {
+        // Concat '> ' with root ID for the parent of top-level tabs.
+        $parent = empty($task_info['parent_id']) ? '> ' . $task_info['base_route'] : $task_info['parent_id'];
+        $children[$parent][$plugin_id] = $task_info;
+      }
+    }
+    return $children;
+  }
+
+  /**
+   * Create a plugin instance for each element of the hierarchy.
+   *
+   * @param string $route_name
+   *   The current route name.
+   * @param string[] $base_routes
+   *   A list of all base route names.
+   * @param array $children
+   *   The plugin information as determined by ::findBaseRouteChildren().
+   * @param bool[] $parents
+   *   An array keyed by parent ID and boolean whether its a local task parent.
+   *
+   * @return \Drupal\Core\Menu\LocalTaskInterface[][][]
+   *   An array of local tasks keyed by route name, level and plugin ID.
+   */
+  protected function instanciatePluginInstances($route_name, array $base_routes, array $children, array $parents) {
+    $instances = [];
+    foreach ($base_routes as $base_route) {
+      // Convert the tree keyed by plugin IDs into a simple one with
+      // integer depth.  Create instances for each plugin along the way.
+      $level = 0;
+      // We used this above as the top-level parent array key.
+      $next_parent = '> ' . $base_route;
+      do {
+        $parent = $next_parent;
+        $next_parent = FALSE;
+        foreach ($children[$parent] as $plugin_id => $task_info) {
+          $plugin = $this->createInstance($plugin_id);
+          $instances[$route_name][$level][$plugin_id] = $plugin;
+          // Normally, the link generator compares the href of every link with
+          // the current path and sets the active class accordingly. But the
+          // parents of the current local task may be on a different route in
+          // which case we have to set the class manually by flagging it
+          // active.
+          if (!empty($parents[$plugin_id]) && $route_name != $task_info['route_name']) {
+            $plugin->setActive();
+          }
+          if (isset($children[$plugin_id])) {
+            // This tab has visible children.
+            $next_parent = $plugin_id;
+          }
+        }
+        $level++;
+      } while ($next_parent);
+    }
+
+    return $instances;
+  }
+
+  /**
+   * @param string $route_name
+   *   The current route name.
+   * @param string[] $base_routes
+   *   A list of all base route names.
+   * @param bool[] $parents
+   *   An array keyed by parent ID and boolean whether its a local task parent.
+   * @param array $children
+   *   The plugin information as determined by ::findBaseRouteChildren().
+   */
+  protected function setLocalTasksCache($route_name, array $base_routes, array $parents, array $children) {
+    $data = array(
+      'base_routes' => $base_routes,
+      'parents' => $parents,
+      'children' => $children,
+    );
+    $this->cacheBackend->set($this->cacheKey . ':' . $route_name, $data, Cache::PERMANENT, $this->cacheTags);
+  }
+
+  /**
+   * Calculates the local task hierarchy information.
+   *
+   * @param string $route_name
+   *   The current route name.
+   * @param array $definitions
+   *   An array of all plugin definitions.
+   *
+   * @return array
+   *   The definitions, base routes and parents.
+   */
+  protected function calculateHierarchyTaskInformation($route_name, $definitions) {
+    $base_routes = [];
+    $parents = [];
+    // We build the hierarchy by finding all tabs that should
+    // appear on the current route.
+    foreach ($definitions as $plugin_id => $task_info) {
+      // Fill in the base_route from the parent to insure consistency.
+      if (!empty($task_info['parent_id']) && !empty($definitions[$task_info['parent_id']])) {
+        $task_info['base_route'] = $definitions[$task_info['parent_id']]['base_route'];
+        // Populate the definitions we use in the next loop. Using a
+        // reference like &$task_info causes bugs.
+        $definitions[$plugin_id]['base_route'] = $definitions[$task_info['parent_id']]['base_route'];
+      }
+      if ($route_name == $task_info['route_name']) {
+        if (!empty($task_info['base_route'])) {
+          $base_routes[$task_info['base_route']] = $task_info['base_route'];
+        }
+        // Tabs that link to the current route are viable parents
+        // and their parent and children should be visible also.
+        // @todo - this only works for 2 levels of tabs.
+        // instead need to iterate up.
+        $parents[$plugin_id] = TRUE;
+        if (!empty($task_info['parent_id'])) {
+          $parents[$task_info['parent_id']] = TRUE;
+        }
+      }
+    }
+    return [$definitions, $base_routes, $parents];
+  }
+
 }
