diff --git a/core/authorize.php b/core/authorize.php
index 46c6a29..114dcd3 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -78,11 +78,11 @@ function authorize_access_allowed() {
 
 // We have to enable the user and system modules, even to check access and
 // display errors via the maintenance theme.
-$module_list['system']['filename'] = 'core/modules/system/system.module';
-$module_list['user']['filename'] = 'core/modules/user/user.module';
-module_list(NULL, $module_list);
-drupal_load('module', 'system');
-drupal_load('module', 'user');
+$module_list['system'] = 'core/modules/system/system.module';
+$module_list['user'] = 'core/modules/user/user.module';
+drupal_container()->get('module_handler')->setModuleList($module_list);
+drupal_container()->get('module_handler')->load('system');
+drupal_container()->get('module_handler')->load('user');
 
 // Initialize the language system.
 drupal_language_initialize();
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 3d2a116..8458c7c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -887,6 +887,14 @@ function drupal_get_filename($type, $name, $filename = NULL) {
     // nothing
   }
   else {
+    if ($type == 'module') {
+      if (empty($files[$type])) {
+        $files[$type] = drupal_container()->get('module_handler')->getModuleList();
+      }
+      if (isset($files[$type][$name])) {
+        return $files[$type][$name];
+      }
+    }
     // Verify that we have an keyvalue service before using it. This is required
     // because this function is called during installation.
     // @todo Inject database connection into KeyValueStore\DatabaseStorage.
@@ -1132,8 +1140,9 @@ function drupal_page_is_cacheable($allow_caching = NULL) {
  * @see bootstrap_hooks()
  */
 function bootstrap_invoke_all($hook) {
-  foreach (module_list('bootstrap') as $module) {
-    drupal_load('module', $module);
+  $module_handler = drupal_container()->get('module_handler');
+  foreach ($module_handler->getBootstrapModules() as $module) {
+    $module_handler->load($module);
     module_invoke($module, $hook);
   }
 }
@@ -1152,6 +1161,10 @@ function bootstrap_invoke_all($hook) {
  *   TRUE if the item is loaded or has already been loaded.
  */
 function drupal_load($type, $name) {
+  if ($type == 'module' && drupal_container()->get('module_handler')->moduleExists($name)) {
+    return drupal_container()->get('module_handler')->load($name);
+  }
+
   // Once a file is included this can't be reversed during a request so do not
   // use drupal_static() here.
   static $files = array();
@@ -2422,7 +2435,7 @@ function _drupal_bootstrap_variables() {
   $conf = variable_initialize(isset($conf) ? $conf : array());
   // Load bootstrap modules.
   require_once DRUPAL_ROOT . '/core/includes/module.inc';
-  module_load_all(TRUE);
+  drupal_container()->get('module_handler')->loadBootstrapModules();
 }
 
 /**
@@ -2476,6 +2489,69 @@ function drupal_container(Container $new_container = NULL) {
 }
 
 /**
+ * Determines which modules are implementing a hook.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   drupal_container()->get('module_handler')->getImplementations($hook).
+ *
+ * @see ModuleHandler::getImplementations().
+ */
+function module_implements($hook) {
+  return drupal_container()->get('module_handler')->getImplementations($hook);
+}
+
+/**
+ * Invokes a hook in all enabled modules that implement it.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   drupal_container()->get('module_handler')->invokeAll($hook).
+ *
+ * @see ModuleHandler::invokeAll().
+ */
+function module_invoke_all($hook) {
+  $args = func_get_args();
+  // Remove $hook from the arguments.
+  array_shift($args);
+  return drupal_container()->get('module_handler')->invokeAll($hook, $args);
+}
+
+/**
+ * Passes alterable variables to specific hook_TYPE_alter() implementations.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   drupal_container()->get('module_handler')->alter($hook).
+ *
+ * @see ModuleHandler::alter().
+ */
+function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
+  return drupal_container()->get('module_handler')->alter($type, $data, $context1, $context2);
+}
+
+/**
+ * Determines whether a given module exists.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   drupal_container()->get('module_handler')->moduleExists($hook).
+ *
+ * @see ModuleHandler::moduleExists().
+ */
+function module_exists($module) {
+  return drupal_container()->get('module_handler')->moduleExists($module);
+}
+
+/**
+ * Determines whether a module implements a hook.
+ *
+ * @deprecated as of Drupal 8.0. Use
+ *   drupal_container()->get('module_handler')->implementsHook($module, $hook).
+ *
+ * @see ModuleHandler::implementsHook().
+ */
+function module_hook($module, $hook) {
+  return drupal_container()->get('module_handler')->implementsHook($module, $hook);
+}
+
+/**
  * Returns the state storage service.
  *
  * Use this to store machine-generated data, local to a specific environment
diff --git a/core/includes/common.inc b/core/includes/common.inc
index bd263ec..48f1fd4 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -4774,7 +4774,7 @@ function _drupal_bootstrap_code() {
   require_once DRUPAL_ROOT . '/core/includes/entity.inc';
 
   // Load all enabled modules
-  module_load_all();
+  drupal_container()->get('module_handler')->loadAll();
 
   // Make sure all stream wrappers are registered.
   file_get_stream_wrappers();
@@ -6373,7 +6373,7 @@ function drupal_flush_all_caches() {
 
   // Ensure that all modules that are currently supposed to be enabled are
   // actually loaded.
-  module_load_all();
+  drupal_container()->get('module_handler')->loadAll();
 
   // Update the list of bootstrap modules.
   // Allows developers to get new hook_boot() implementations registered without
@@ -6447,68 +6447,10 @@ function debug($data, $label = NULL, $print_r = FALSE) {
 }
 
 /**
- * Parses a dependency for comparison by drupal_check_incompatibility().
- *
- * @param $dependency
- *   A dependency string, for example 'foo (>=8.x-4.5-beta5, 3.x)'.
- *
- * @return
- *   An associative array with three keys:
- *   - 'name' includes the name of the thing to depend on (e.g. 'foo').
- *   - 'original_version' contains the original version string (which can be
- *     used in the UI for reporting incompatibilities).
- *   - 'versions' is a list of associative arrays, each containing the keys
- *     'op' and 'version'. 'op' can be one of: '=', '==', '!=', '<>', '<',
- *     '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'.
- *   Callers should pass this structure to drupal_check_incompatibility().
- *
- * @see drupal_check_incompatibility()
- */
-function drupal_parse_dependency($dependency) {
-  // We use named subpatterns and support every op that version_compare
-  // supports. Also, op is optional and defaults to equals.
-  $p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
-  // Core version is always optional: 8.x-2.x and 2.x is treated the same.
-  $p_core = '(?:' . preg_quote(DRUPAL_CORE_COMPATIBILITY) . '-)?';
-  $p_major = '(?P<major>\d+)';
-  // By setting the minor version to x, branches can be matched.
-  $p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
-  $value = array();
-  $parts = explode('(', $dependency, 2);
-  $value['name'] = trim($parts[0]);
-  if (isset($parts[1])) {
-    $value['original_version'] = ' (' . $parts[1];
-    foreach (explode(',', $parts[1]) as $version) {
-      if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) {
-        $op = !empty($matches['operation']) ? $matches['operation'] : '=';
-        if ($matches['minor'] == 'x') {
-          // Drupal considers "2.x" to mean any version that begins with
-          // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(),
-          // on the other hand, treats "x" as a string; so to
-          // version_compare(), "2.x" is considered less than 2.0. This
-          // means that >=2.x and <2.x are handled by version_compare()
-          // as we need, but > and <= are not.
-          if ($op == '>' || $op == '<=') {
-            $matches['major']++;
-          }
-          // Equivalence can be checked by adding two restrictions.
-          if ($op == '=' || $op == '==') {
-            $value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x');
-            $op = '>=';
-          }
-        }
-        $value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']);
-      }
-    }
-  }
-  return $value;
-}
-
-/**
  * Checks whether a version is compatible with a given dependency.
  *
  * @param $v
- *   The parsed dependency structure from drupal_parse_dependency().
+ *   A parsed dependency structure e.g. from ModuleHandler::parseDependency().
  * @param $current_version
  *   The version to check against (like 4.2).
  *
@@ -6516,7 +6458,7 @@ function drupal_parse_dependency($dependency) {
  *   NULL if compatible, otherwise the original dependency version string that
  *   caused the incompatibility.
  *
- * @see drupal_parse_dependency()
+ * @see ModuleHandler::parseDependency()
  */
 function drupal_check_incompatibility($v, $current_version) {
   if (!empty($v['versions'])) {
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 7f4b26b..1ba401c 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -338,6 +338,7 @@ function install_begin_request(&$install_state) {
     $container->register('config.factory', 'Drupal\Core\Config\ConfigFactory')
       ->addArgument(new Reference('config.storage'))
       ->addArgument(new Reference('event_dispatcher'));
+
     // The install process cannot use the database lock backend since the database
     // is not fully up, so we use a null backend implementation during the
     // installation process. This will also speed up the installation process.
@@ -346,6 +347,10 @@ function install_begin_request(&$install_state) {
     // (as opposed to the cache backend) so we can afford having a null
     // implementation here.
     $container->register('lock', 'Drupal\Core\Lock\NullLockBackend');
+
+    // Register a module handler for managing enabled modules.
+    $container
+      ->register('module_handler', 'Drupal\Core\ModuleHandler');
     drupal_container($container);
   }
 
@@ -353,10 +358,13 @@ function install_begin_request(&$install_state) {
   drupal_language_initialize();
 
   require_once DRUPAL_ROOT . '/core/includes/ajax.inc';
-  // Override the module list with a minimal set of modules.
-  $module_list['system']['filename'] = 'core/modules/system/system.module';
-  module_list(NULL, $module_list);
-  drupal_load('module', 'system');
+
+  $module_handler = drupal_container()->get('module_handler');
+  if (!$module_handler->moduleExists('system')) {
+    // Override the module list with a minimal set of modules.
+    $module_handler->setModuleList(array('system' => 'core/modules/system/system.module'));
+  }
+  $module_handler->load('system');
 
   require_once DRUPAL_ROOT . '/core/includes/cache.inc';
   $conf['cache_classes'] = array('cache' => 'Drupal\Core\Cache\MemoryBackend');
@@ -1570,9 +1578,7 @@ function install_bootstrap_full(&$install_state) {
   // cache backend will be used again.
   unset($GLOBALS['conf']['cache_classes']['cache']);
   drupal_static_reset('cache');
-  // Clear the module list that was overriden earlier in the process.
-  // This will allow all freshly installed modules to be loaded.
-  module_list_reset();
+
   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 }
 
diff --git a/core/includes/install.inc b/core/includes/install.inc
index 9223b9c..c6b3c50 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -424,15 +424,10 @@ function drupal_install_system() {
     ->set('enabled.system', 0)
     ->save();
 
-  // Clear out module list and hook implementation statics.
-  system_list_reset();
-  module_list_reset();
-  module_implements_reset();
-
-  // To ensure that the system module can be found by the plugin system, warm
-  // the module list cache.
-  // @todo Remove this in http://drupal.org/node/1798732.
-  module_list();
+  // Reset the module list.
+  drupal_container()->get('module_handler')->setModuleList(array('system' => $system_path . '/system.module'));
+  drupal_container()->get('module_handler')->resetImplementations();
+
   config_install_default_config('module', 'system');
 
   module_invoke('system', 'install');
diff --git a/core/includes/module.inc b/core/includes/module.inc
index f6d47b6..e46fa95 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -10,114 +10,6 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Loads all enabled modules.
- *
- * @param bool $bootstrap
- *   Whether to load only the reduced set of modules loaded in "bootstrap mode"
- *   for cached pages. See bootstrap.inc. Pass NULL to only check the current
- *   status without loading of modules.
- * @param bool $reset
- *   (optional) Internal use only. Whether to reset the internal statically
- *   cached flag of whether modules have been loaded. If TRUE, all modules are
- *   (re)loaded in the same call. Used by the testing framework to override and
- *   persist a limited module list for the duration of a unit test (in which no
- *   module system exists).
- *
- * @return bool
- *   A Boolean indicating whether all modules have been loaded. This means all
- *   modules; the load status of bootstrap modules cannot be checked.
- */
-function module_load_all($bootstrap = FALSE, $reset = FALSE) {
-  static $has_run = FALSE;
-
-  if ($reset) {
-    $has_run = FALSE;
-  }
-
-  // Unless $boostrap is NULL, load the requested set of modules.
-  if (isset($bootstrap) && !$has_run) {
-    $type = $bootstrap ? 'bootstrap' : 'module_enabled';
-    foreach (module_list($type) as $module) {
-      drupal_load('module', $module);
-    }
-    // $has_run will be TRUE if $bootstrap is FALSE.
-    $has_run = !$bootstrap;
-  }
-  return $has_run;
-}
-
-/**
- * Returns a list of currently active modules.
- *
- * Acts as a wrapper around system_list(), returning either a list of all
- * enabled modules, or just modules needed for bootstrap.
- *
- * The returned module list is always based on system_list(). The only exception
- * to that is when a fixed list of modules has been passed in previously, in
- * which case system_list() is omitted and the fixed list is always returned in
- * subsequent calls until manually reverted via module_list_reset().
- *
- * @param string $type
- *   The type of list to return:
- *   - module_enabled: All enabled modules.
- *   - bootstrap: All enabled modules required for bootstrap.
- * @param array $fixed_list
- *   (optional) An array of module names to override the list of modules. This
- *   list will persist until the next call with a new $fixed_list passed in.
- *   Primarily intended for internal use (e.g., in install.php and update.php).
- *   Use module_list_reset() to undo the $fixed_list override.
- * @param bool $reset
- *   (optional) Whether to reset/remove the $fixed_list.
- *
- * @return array
- *   An associative array whose keys and values are the names of the modules in
- *   the list.
- *
- * @see module_list_reset()
- */
-function module_list($type = 'module_enabled', array $fixed_list = NULL, $reset = FALSE) {
-  // This static is only used for $fixed_list. It must not be a drupal_static(),
-  // since any call to drupal_static_reset() in unit tests would cause an
-  // attempt to retrieve the list of modules from the database (which does not
-  // exist).
-  static $module_list;
-
-  if ($reset) {
-    $module_list = NULL;
-    // Do nothing if no $type and no $fixed_list have been passed.
-    if (!isset($type) && !isset($fixed_list)) {
-      return;
-    }
-  }
-
-  // The list that will be be returned. Separate from $module_list in order
-  // to not duplicate the static cache of system_list().
-  $list = $module_list;
-
-  if (isset($fixed_list)) {
-    $module_list = array();
-    foreach ($fixed_list as $name => $module) {
-      system_register('module', $name, $module['filename']);
-      $module_list[$name] = $name;
-    }
-    $list = $module_list;
-  }
-  elseif (!isset($module_list)) {
-    $list = system_list($type);
-  }
-  return $list;
-}
-
-/**
- * Reverts an enforced fixed list of module_list().
- *
- * Subsequent calls to module_list() will no longer use a fixed list.
- */
-function module_list_reset() {
-  module_list(NULL, NULL, TRUE);
-}
-
-/**
  * Builds a list of bootstrap modules and enabled modules and themes.
  *
  * @param $type
@@ -132,7 +24,6 @@ function module_list_reset() {
  *   For $type 'theme', the array values are objects representing the
  *   respective database row, with the 'info' property already unserialized.
  *
- * @see module_list()
  * @see list_themes()
  *
  * @todo There are too many layers/levels of caching involved for system_list()
@@ -142,126 +33,80 @@ function module_list_reset() {
  */
 function system_list($type) {
   $lists = &drupal_static(__FUNCTION__);
-
-  // For bootstrap modules, attempt to fetch the list from cache if possible.
-  // if not fetch only the required information to fire bootstrap hooks
-  // in case we are going to serve the page from cache.
-  if ($type == 'bootstrap') {
-    if (isset($lists['bootstrap'])) {
-      return $lists['bootstrap'];
-    }
-    if ($cached = cache('bootstrap')->get('bootstrap_modules')) {
-      $bootstrap_list = $cached->data;
-    }
-    else {
-      $bootstrap_list = state()->get('system.module.bootstrap') ?: array();
-      cache('bootstrap')->set('bootstrap_modules', $bootstrap_list);
-    }
-    // To avoid a separate database lookup for the filepath, prime the
-    // drupal_get_filename() static cache for bootstrap modules only.
-    // The rest is stored separately to keep the bootstrap module cache small.
-    foreach ($bootstrap_list as $name => $filename) {
-      system_register('module', $name, $filename);
-    }
-    // We only return the module names here since module_list() doesn't need
-    // the filename itself.
-    $lists['bootstrap'] = array_keys($bootstrap_list);
+  if ($cached = cache('bootstrap')->get('system_list')) {
+    $lists = $cached->data;
   }
-  // Otherwise build the list for enabled modules and themes.
-  elseif (!isset($lists['module_enabled'])) {
-    if ($cached = cache('bootstrap')->get('system_list')) {
-      $lists = $cached->data;
-    }
-    else {
-      $lists = array(
-        'module_enabled' => array(),
-        'theme' => array(),
-        'filepaths' => array(),
-      );
-      // The module name (rather than the filename) is used as the fallback
-      // weighting in order to guarantee consistent behavior across different
-      // Drupal installations, which might have modules installed in different
-      // locations in the file system. The ordering here must also be
-      // consistent with the one used in module_implements().
-      $enabled_modules = (array) config('system.module')->get('enabled');
-      $module_files = state()->get('system.module.files');
-      foreach ($enabled_modules as $name => $weight) {
-        // Build a list of all enabled modules.
-        $lists['module_enabled'][$name] = $name;
-        // Build a list of filenames so drupal_get_filename can use it.
+  else {
+    $lists = array(
+      'theme' => array(),
+      'filepaths' => array(),
+    );
+    // Build a list of themes.
+    $enabled_themes = (array) config('system.theme')->get('enabled');
+    // @todo Themes include all themes, including disabled/uninstalled. This
+    //   system.theme.data state will go away entirely as soon as themes have
+    //   a proper installation status.
+    // @see http://drupal.org/node/1067408
+    $theme_data = state()->get('system.theme.data');
+    if (empty($theme_data)) {
+      // @todo: system_list() may be called from _drupal_bootstrap_code(), in
+      // which case system.module is not loaded yet.
+      // Prevent a filesystem scan in drupal_load() and include it directly.
+      // @see http://drupal.org/node/1067408
+      require_once DRUPAL_ROOT . '/core/modules/system/system.module';
+      $theme_data = system_rebuild_theme_data();
+    }
+    foreach ($theme_data as $name => $theme) {
+      $theme->status = (int) isset($enabled_themes[$name]);
+      $lists['theme'][$name] = $theme;
+      // Build a list of filenames so drupal_get_filename can use it.
+      if (isset($enabled_themes[$name])) {
         $lists['filepaths'][] = array(
-          'type' => 'module',
+          'type' => 'theme',
           'name' => $name,
-          'filepath' => $module_files[$name],
+          'filepath' => $theme->filename,
         );
       }
-
-      // Build a list of themes.
-      $enabled_themes = (array) config('system.theme')->get('enabled');
-      // @todo Themes include all themes, including disabled/uninstalled. This
-      //   system.theme.data state will go away entirely as soon as themes have
-      //   a proper installation status.
-      // @see http://drupal.org/node/1067408
-      $theme_data = state()->get('system.theme.data');
-      if (empty($theme_data)) {
-        // @todo: system_list() may be called from _drupal_bootstrap_code() and
-        // module_load_all(), in which case system.module is not loaded yet.
-        // Prevent a filesystem scan in drupal_load() and include it directly.
-        // @see http://drupal.org/node/1067408
-        require_once DRUPAL_ROOT . '/core/modules/system/system.module';
-        $theme_data = system_rebuild_theme_data();
-      }
-      foreach ($theme_data as $name => $theme) {
-        $theme->status = (int) isset($enabled_themes[$name]);
-        $lists['theme'][$name] = $theme;
-        // Build a list of filenames so drupal_get_filename can use it.
-        if (isset($enabled_themes[$name])) {
-          $lists['filepaths'][] = array(
-            'type' => 'theme',
-            'name' => $name,
-            'filepath' => $theme->filename,
-          );
-        }
-      }
-      // @todo Move into list_themes(). Read info for a particular requested
-      //   theme from state instead.
-      foreach ($lists['theme'] as $key => $theme) {
-        if (!empty($theme->info['base theme'])) {
-          // Make a list of the theme's base themes.
-          require_once DRUPAL_ROOT . '/core/includes/theme.inc';
-          $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
-          // Don't proceed if there was a problem with the root base theme.
-          if (!current($lists['theme'][$key]->base_themes)) {
-            continue;
-          }
-          // Determine the root base theme.
-          $base_key = key($lists['theme'][$key]->base_themes);
-          // Add to the list of sub-themes for each of the theme's base themes.
-          foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
-            $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
-          }
-          // Add the base theme's theme engine info.
-          $lists['theme'][$key]->info['engine'] = $lists['theme'][$base_key]->info['engine'];
+    }
+    // @todo Move into list_themes(). Read info for a particular requested
+    //   theme from state instead.
+    foreach ($lists['theme'] as $key => $theme) {
+      if (!empty($theme->info['base theme'])) {
+        // Make a list of the theme's base themes.
+        require_once DRUPAL_ROOT . '/core/includes/theme.inc';
+        $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
+        // Don't proceed if there was a problem with the root base theme.
+        if (!current($lists['theme'][$key]->base_themes)) {
+          continue;
         }
-        else {
-          // A plain theme is its own base theme.
-          $base_key = $key;
+        // Determine the root base theme.
+        $base_key = key($lists['theme'][$key]->base_themes);
+        // Add to the list of sub-themes for each of the theme's base themes.
+        foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
+          $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
         }
-        // Set the theme engine prefix.
-        $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
+        // Add the base theme's theme engine info.
+        $lists['theme'][$key]->info['engine'] = $lists['theme'][$base_key]->info['engine'];
       }
-      cache('bootstrap')->set('system_list', $lists);
-    }
-    // To avoid a separate database lookup for the filepath, prime the
-    // drupal_get_filename() static cache with all enabled modules and themes.
-    foreach ($lists['filepaths'] as $item) {
-      system_register($item['type'], $item['name'], $item['filepath']);
+      else {
+        // A plain theme is its own base theme.
+        $base_key = $key;
+      }
+      // Set the theme engine prefix.
+      $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
     }
+    cache('bootstrap')->set('system_list', $lists);
+  }
+  // To avoid a separate database lookup for the filepath, prime the
+  // drupal_get_filename() static cache with all enabled modules and themes.
+  foreach ($lists['filepaths'] as $item) {
+    system_register($item['type'], $item['name'], $item['filepath']);
   }
 
   return $lists[$type];
 }
 
+
 /**
  * Resets all system_list() caches.
  */
@@ -281,6 +126,7 @@ function system_list_reset() {
   state()->delete('system.theme.data');
 }
 
+
 /**
  * Registers an extension in runtime registries for execution.
  *
@@ -298,53 +144,6 @@ function system_register($type, $name, $uri) {
 }
 
 /**
- * Determines which modules require and are required by each module.
- *
- * @param $files
- *   The array of filesystem objects used to rebuild the cache.
- *
- * @return
- *   The same array with the new keys for each module:
- *   - requires: An array with the keys being the modules that this module
- *     requires.
- *   - required_by: An array with the keys being the modules that will not work
- *     without this module.
- */
-function _module_build_dependencies($files) {
-  foreach ($files as $filename => $file) {
-    $graph[$file->name]['edges'] = array();
-    if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) {
-      foreach ($file->info['dependencies'] as $dependency) {
-        $dependency_data = drupal_parse_dependency($dependency);
-        $graph[$file->name]['edges'][$dependency_data['name']] = $dependency_data;
-      }
-    }
-  }
-  $graph_object = new Graph($graph);
-  $graph = $graph_object->searchAndSort();
-  foreach ($graph as $module => $data) {
-    $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
-    $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array();
-    $files[$module]->sort = $data['weight'];
-  }
-  return $files;
-}
-
-/**
- * Determines whether a given module exists.
- *
- * @param $module
- *   The name of the module (without the .module extension).
- *
- * @return
- *   TRUE if the module is both installed and enabled.
- */
-function module_exists($module) {
-  $list = module_list();
-  return isset($list[$module]);
-}
-
-/**
  * Loads a module's installation hooks.
  *
  * @param $module
@@ -386,6 +185,11 @@ function module_load_install($module) {
  *
  * @return
  *   The name of the included file, if successful; FALSE otherwise.
+ *
+ * @todo The module_handler service has a loadInclude() method which performs
+ *   this same task but only for enabled modules. Figure out a way to move this
+ *   functionality entirely into the module_handler while keeping the ability to
+ *   load the files of disabled modules.
  */
 function module_load_include($type, $module, $name = NULL) {
   if (!isset($name)) {
@@ -402,15 +206,6 @@ function module_load_include($type, $module, $name = NULL) {
   return FALSE;
 }
 
-/**
- * Loads an include file for each enabled module.
- */
-function module_load_all_includes($type, $name = NULL) {
-  $modules = module_list();
-  foreach ($modules as $module) {
-    module_load_include($type, $module, $name);
-  }
-}
 
 /**
  * Enables or installs a given list of modules.
@@ -494,10 +289,11 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
   $schema_store = drupal_container()->get('keyvalue')->get('system.schema');
   $module_config = config('system.module');
   $disabled_config = config('system.module.disabled');
-  $module_filenames = drupal_container()->getParameter('container.modules');
+  $module_handler = drupal_container()->get('module_handler');
   foreach ($module_list as $module) {
+    $module_filenames = $module_handler->getModuleList();
     // Only process modules that are not already enabled.
-    $enabled = $module_config->get("enabled.$module") !== NULL;
+    $enabled = isset($module_filenames[$module]);
     if (!$enabled) {
       $weight = $disabled_config->get($module);
       if ($weight === NULL) {
@@ -510,21 +306,35 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
       $disabled_config
         ->clear($module)
         ->save();
+
+      $module_filenames[$module] = drupal_get_filename('module', $module);
+
+      $sorted_modules = $module_config->get('enabled');
+      $sorted_with_filenames = array();
+      foreach (array_keys($sorted_modules) as $sorted_module) {
+        $filename = isset($module_filenames[$sorted_module]) ? $module_filenames[$sorted_module] : drupal_get_filename('module', $sorted_module);
+        $sorted_with_filenames[$sorted_module] = $filename;
+      }
+
+      // Refresh the module list in the extension handler.
+      $module_handler->setModuleList($module_filenames);
+
       // Load the module's code.
-      drupal_load('module', $module);
+      $module_handler->load($module);
       module_load_install($module);
 
       // Refresh the module list to include it.
-      system_list_reset();
-      module_implements_reset();
+      $module_handler->resetImplementations();
+
       _system_update_bootstrap_status();
-      $module_filenames[$module] = drupal_get_filename('module', $module);
-      // Update the kernel to include it.
+
+      // Update the kernel to include the new module.
       // @todo The if statement is here because install_begin_request() creates
       //   a container without a kernel. It probably shouldn't.
       if ($kernel = drupal_container()->get('kernel', ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
-        $kernel->updateModules(module_list(), $module_filenames);
+        $kernel->updateModules($sorted_modules, $sorted_with_filenames);
       }
+
       // Refresh the schema to include it.
       drupal_get_schema(NULL, TRUE);
       // Update the theme registry to include it.
@@ -632,8 +442,10 @@ function module_disable($module_list, $disable_dependents = TRUE) {
 
   $module_config = config('system.module');
   $disabled_config = config('system.module.disabled');
+  $module_handler = drupal_container()->get('module_handler');
   foreach ($module_list as $module) {
-    if (module_exists($module)) {
+    $enabled = $module_handler->getModuleList();
+    if (isset($enabled[$module])) {
       module_load_install($module);
       module_invoke($module, 'disable');
       $disabled_config
@@ -642,22 +454,27 @@ function module_disable($module_list, $disable_dependents = TRUE) {
       $module_config
         ->clear("enabled.$module")
         ->save();
+      unset($enabled[$module]);
+      $module_handler->setModuleList($enabled);
       $invoke_modules[] = $module;
       watchdog('system', '%module module disabled.', array('%module' => $module), WATCHDOG_INFO);
     }
   }
 
   if (!empty($invoke_modules)) {
-    // Refresh the module list to exclude the disabled modules.
+    // Refresh the system list to exclude the disabled modules.
+    // @todo This call is only needed so that the theme info gets rebuilt - see
+    //   the todo in system_list_reset().
     system_list_reset();
-    module_implements_reset();
+    // Refresh the module list to exclude the disabled modules.
+    drupal_container()->get('module_handler')->resetImplementations();
     entity_info_cache_clear();
     // Invoke hook_modules_disabled before disabling modules,
     // so we can still call module hooks to get information.
     module_invoke_all('modules_disabled', $invoke_modules);
     _system_update_bootstrap_status();
     // Update the kernel to exclude the disabled modules.
-    drupal_container()->get('kernel')->updateModules(module_list());
+    drupal_container()->get('kernel')->updateModules($module_config->get('enabled'), $enabled);
     // Update the theme registry to remove the newly-disabled module.
     drupal_theme_rebuild();
   }
@@ -766,200 +583,6 @@ function module_uninstall($module_list = array(), $uninstall_dependents = TRUE)
  */
 
 /**
- * Determines whether a module implements a hook.
- *
- * @param $module
- *   The name of the module (without the .module extension).
- * @param $hook
- *   The name of the hook (e.g. "help" or "menu").
- *
- * @return
- *   TRUE if the module is both installed and enabled, and the hook is
- *   implemented in that module.
- */
-function module_hook($module, $hook) {
-  $function = $module . '_' . $hook;
-  if (function_exists($function)) {
-    return TRUE;
-  }
-  // If the hook implementation does not exist, check whether it may live in an
-  // optional include file registered via hook_hook_info().
-  $hook_info = module_hook_info();
-  if (isset($hook_info[$hook]['group'])) {
-    module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
-    if (function_exists($function)) {
-      return TRUE;
-    }
-  }
-  return FALSE;
-}
-
-/**
- * Determines which modules are implementing a hook.
- *
- * @param $hook
- *   The name of the hook (e.g. "help" or "menu").
- *
- * @return
- *   An array with the names of the modules which are implementing this hook.
- *
- * @see module_implements_write_cache()
- */
-function module_implements($hook) {
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['implementations'] = &drupal_static(__FUNCTION__);
-  }
-  $implementations = &$drupal_static_fast['implementations'];
-
-  // Fetch implementations from cache.
-  if (empty($implementations)) {
-    $implementations = cache('bootstrap')->get('module_implements');
-    if ($implementations === FALSE) {
-      $implementations = array();
-    }
-    else {
-      $implementations = $implementations->data;
-    }
-  }
-
-  if (!isset($implementations[$hook])) {
-    // The hook is not cached, so ensure that whether or not it has
-    // implementations, that the cache is updated at the end of the request.
-    $implementations['#write_cache'] = TRUE;
-    $hook_info = module_hook_info();
-    $implementations[$hook] = array();
-    foreach (module_list() as $module) {
-      $include_file = isset($hook_info[$hook]['group']) && module_load_include('inc', $module, $module . '.' . $hook_info[$hook]['group']);
-      // Since module_hook() may needlessly try to load the include file again,
-      // function_exists() is used directly here.
-      if (function_exists($module . '_' . $hook)) {
-        $implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
-      }
-    }
-    // Allow modules to change the weight of specific implementations but avoid
-    // an infinite loop.
-    if ($hook != 'module_implements_alter') {
-      drupal_alter('module_implements', $implementations[$hook], $hook);
-    }
-  }
-  else {
-    foreach ($implementations[$hook] as $module => $group) {
-      // If this hook implementation is stored in a lazy-loaded file, so include
-      // that file first.
-      if ($group) {
-        module_load_include('inc', $module, "$module.$group");
-      }
-      // It is possible that a module removed a hook implementation without the
-      // implementations cache being rebuilt yet, so we check whether the
-      // function exists on each request to avoid undefined function errors.
-      // Since module_hook() may needlessly try to load the include file again,
-      // function_exists() is used directly here.
-      if (!function_exists($module . '_' . $hook)) {
-        // Clear out the stale implementation from the cache and force a cache
-        // refresh to forget about no longer existing hook implementations.
-        unset($implementations[$hook][$module]);
-        $implementations['#write_cache'] = TRUE;
-      }
-    }
-  }
-
-  return array_keys($implementations[$hook]);
-}
-
-/**
- * Regenerates the stored list of hook implementations.
- */
-function module_implements_reset() {
-  // We maintain a persistent cache of hook implementations in addition to the
-  // static cache to avoid looping through every module and every hook on each
-  // request. Benchmarks show that the benefit of this caching outweighs the
-  // additional database hit even when using the default database caching
-  // backend and only a small number of modules are enabled. The cost of the
-  // cache('bootstrap')->get() is more or less constant and reduced further when
-  // non-database caching backends are used, so there will be more significant
-  // gains when a large number of modules are installed or hooks invoked, since
-  // this can quickly lead to module_hook() being called several thousand times
-  // per request.
-  drupal_static_reset('module_implements');
-  cache('bootstrap')->set('module_implements', array());
-  drupal_static_reset('module_hook_info');
-  drupal_static_reset('drupal_alter');
-  cache('bootstrap')->delete('hook_info');
-}
-
-/**
- * Retrieves a list of hooks that are declared through hook_hook_info().
- *
- * @return
- *   An associative array whose keys are hook names and whose values are an
- *   associative array containing a group name. The structure of the array
- *   is the same as the return value of hook_hook_info().
- *
- * @see hook_hook_info()
- */
-function module_hook_info() {
-  // When this function is indirectly invoked from bootstrap_invoke_all() prior
-  // to all modules being loaded, we do not want to cache an incomplete
-  // hook_hook_info() result, so instead return an empty array. This requires
-  // bootstrap hook implementations to reside in the .module file, which is
-  // optimal for performance anyway.
-  if (!module_load_all(NULL)) {
-    return array();
-  }
-  $hook_info = &drupal_static(__FUNCTION__);
-
-  if (!isset($hook_info)) {
-    $hook_info = array();
-    $cache = cache('bootstrap')->get('hook_info');
-    if ($cache === FALSE) {
-      // Rebuild the cache and save it.
-      // We can't use module_invoke_all() here or it would cause an infinite
-      // loop.
-      foreach (module_list() as $module) {
-        $function = $module . '_hook_info';
-        if (function_exists($function)) {
-          $result = $function();
-          if (isset($result) && is_array($result)) {
-            $hook_info = NestedArray::mergeDeep($hook_info, $result);
-          }
-        }
-      }
-      // We can't use drupal_alter() for the same reason as above.
-      foreach (module_list() as $module) {
-        $function = $module . '_hook_info_alter';
-        if (function_exists($function)) {
-          $function($hook_info);
-        }
-      }
-      cache('bootstrap')->set('hook_info', $hook_info);
-    }
-    else {
-      $hook_info = $cache->data;
-    }
-  }
-
-  return $hook_info;
-}
-
-/**
- * Writes the hook implementation cache.
- *
- * @see module_implements()
- */
-function module_implements_write_cache() {
-  $implementations = &drupal_static('module_implements');
-  // Check whether we need to write the cache. We do not want to cache hooks
-  // which are only invoked on HTTP POST requests since these do not need to be
-  // optimized as tightly, and not doing so keeps the cache entry smaller.
-  if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
-    unset($implementations['#write_cache']);
-    cache('bootstrap')->set('module_implements', $implementations);
-  }
-}
-
-/**
  * Invokes a hook in a particular module.
  *
  * @param $module
@@ -982,39 +605,6 @@ function module_invoke($module, $hook) {
 }
 
 /**
- * Invokes a hook in all enabled modules that implement it.
- *
- * @param $hook
- *   The name of the hook to invoke.
- * @param ...
- *   Arguments to pass to the hook.
- *
- * @return
- *   An array of return values of the hook implementations. If modules return
- *   arrays from their implementations, those are merged into one array.
- */
-function module_invoke_all($hook) {
-  $args = func_get_args();
-  // Remove $hook from the arguments.
-  unset($args[0]);
-  $return = array();
-  foreach (module_implements($hook) as $module) {
-    $function = $module . '_' . $hook;
-    if (function_exists($function)) {
-      $result = call_user_func_array($function, $args);
-      if (isset($result) && is_array($result)) {
-        $return = NestedArray::mergeDeep($return, $result);
-      }
-      elseif (isset($result)) {
-        $return[] = $result;
-      }
-    }
-  }
-
-  return $return;
-}
-
-/**
  * @} End of "defgroup hooks".
  */
 
@@ -1039,172 +629,6 @@ function drupal_required_modules() {
 }
 
 /**
- * Passes alterable variables to specific hook_TYPE_alter() implementations.
- *
- * This dispatch function hands off the passed-in variables to type-specific
- * hook_TYPE_alter() implementations in modules. It ensures a consistent
- * interface for all altering operations.
- *
- * A maximum of 2 alterable arguments is supported. In case more arguments need
- * to be passed and alterable, modules provide additional variables assigned by
- * reference in the last $context argument:
- * @code
- *   $context = array(
- *     'alterable' => &$alterable,
- *     'unalterable' => $unalterable,
- *     'foo' => 'bar',
- *   );
- *   drupal_alter('mymodule_data', $alterable1, $alterable2, $context);
- * @endcode
- *
- * Note that objects are always passed by reference in PHP5. If it is absolutely
- * required that no implementation alters a passed object in $context, then an
- * object needs to be cloned:
- * @code
- *   $context = array(
- *     'unalterable_object' => clone $object,
- *   );
- *   drupal_alter('mymodule_data', $data, $context);
- * @endcode
- *
- * @param $type
- *   A string describing the type of the alterable $data. 'form', 'links',
- *   'node_content', and so on are several examples. Alternatively can be an
- *   array, in which case hook_TYPE_alter() is invoked for each value in the
- *   array, ordered first by module, and then for each module, in the order of
- *   values in $type. For example, when Form API is using drupal_alter() to
- *   execute both hook_form_alter() and hook_form_FORM_ID_alter()
- *   implementations, it passes array('form', 'form_' . $form_id) for $type.
- * @param $data
- *   The variable that will be passed to hook_TYPE_alter() implementations to be
- *   altered. The type of this variable depends on the value of the $type
- *   argument. For example, when altering a 'form', $data will be a structured
- *   array. When altering a 'profile', $data will be an object.
- * @param $context1
- *   (optional) An additional variable that is passed by reference.
- * @param $context2
- *   (optional) An additional variable that is passed by reference. If more
- *   context needs to be provided to implementations, then this should be an
- *   associative array as described above.
- */
-function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['functions'] = &drupal_static(__FUNCTION__);
-  }
-  $functions = &$drupal_static_fast['functions'];
-
-  // Most of the time, $type is passed as a string, so for performance,
-  // normalize it to that. When passed as an array, usually the first item in
-  // the array is a generic type, and additional items in the array are more
-  // specific variants of it, as in the case of array('form', 'form_FORM_ID').
-  if (is_array($type)) {
-    $cid = implode(',', $type);
-    $extra_types = $type;
-    $type = array_shift($extra_types);
-    // Allow if statements in this function to use the faster isset() rather
-    // than !empty() both when $type is passed as a string, or as an array with
-    // one item.
-    if (empty($extra_types)) {
-      unset($extra_types);
-    }
-  }
-  else {
-    $cid = $type;
-  }
-
-  // Some alter hooks are invoked many times per page request, so statically
-  // cache the list of functions to call, and on subsequent calls, iterate
-  // through them quickly.
-  if (!isset($functions[$cid])) {
-    $functions[$cid] = array();
-    $hook = $type . '_alter';
-    $modules = module_implements($hook);
-    if (!isset($extra_types)) {
-      // For the more common case of a single hook, we do not need to call
-      // function_exists(), since module_implements() returns only modules with
-      // implementations.
-      foreach ($modules as $module) {
-        $functions[$cid][] = $module . '_' . $hook;
-      }
-    }
-    else {
-      // For multiple hooks, we need $modules to contain every module that
-      // implements at least one of them.
-      $extra_modules = array();
-      foreach ($extra_types as $extra_type) {
-        $extra_modules = array_merge($extra_modules, module_implements($extra_type . '_alter'));
-      }
-      // If any modules implement one of the extra hooks that do not implement
-      // the primary hook, we need to add them to the $modules array in their
-      // appropriate order. module_implements() can only return ordered
-      // implementations of a single hook. To get the ordered implementations
-      // of multiple hooks, we mimic the module_implements() logic of first
-      // ordering by module_list(), and then calling
-      // drupal_alter('module_implements').
-      if (array_diff($extra_modules, $modules)) {
-        // Merge the arrays and order by module_list().
-        $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
-        // Since module_implements() already took care of loading the necessary
-        // include files, we can safely pass FALSE for the array values.
-        $implementations = array_fill_keys($modules, FALSE);
-        // Let modules adjust the order solely based on the primary hook. This
-        // ensures the same module order regardless of whether this if block
-        // runs. Calling drupal_alter() recursively in this way does not result
-        // in an infinite loop, because this call is for a single $type, so we
-        // won't end up in this code block again.
-        drupal_alter('module_implements', $implementations, $hook);
-        $modules = array_keys($implementations);
-      }
-      foreach ($modules as $module) {
-        // Since $modules is a merged array, for any given module, we do not
-        // know whether it has any particular implementation, so we need a
-        // function_exists().
-        $function = $module . '_' . $hook;
-        if (function_exists($function)) {
-          $functions[$cid][] = $function;
-        }
-        foreach ($extra_types as $extra_type) {
-          $function = $module . '_' . $extra_type . '_alter';
-          if (function_exists($function)) {
-            $functions[$cid][] = $function;
-          }
-        }
-      }
-    }
-    // Allow the theme to alter variables after the theme system has been
-    // initialized.
-    global $theme, $base_theme_info;
-    if (isset($theme)) {
-      $theme_keys = array();
-      foreach ($base_theme_info as $base) {
-        $theme_keys[] = $base->name;
-      }
-      $theme_keys[] = $theme;
-      foreach ($theme_keys as $theme_key) {
-        $function = $theme_key . '_' . $hook;
-        if (function_exists($function)) {
-          $functions[$cid][] = $function;
-        }
-        if (isset($extra_types)) {
-          foreach ($extra_types as $extra_type) {
-            $function = $theme_key . '_' . $extra_type . '_alter';
-            if (function_exists($function)) {
-              $functions[$cid][] = $function;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  foreach ($functions[$cid] as $function) {
-    $function($data, $context1, $context2);
-  }
-}
-
-/**
  * Sets weight of a particular module.
  *
  * The weight of uninstalled modules cannot be changed.
@@ -1217,11 +641,20 @@ function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
 function module_set_weight($module, $weight) {
   // Update the module weight in the config file that contains it.
   $module_config = config('system.module');
+  $module_handler = drupal_container()->get('module_handler');
+  $enabled_modules = $module_handler->getModuleList();
   if ($module_config->get("enabled.$module") !== NULL) {
     $module_config
       ->set("enabled.$module", $weight)
       ->set('enabled', module_config_sort($module_config->get('enabled')))
       ->save();
+    $sorted_modules = $module_config->get('enabled');
+    $sorted_with_filenames = array();
+    foreach (array_keys($sorted_modules) as $m) {
+      $sorted_with_filenames[$m] = $enabled_modules[$m];
+    }
+    // Refresh the module list in the extension handler.
+    $module_handler->setModuleList($sorted_with_filenames);
     return;
   }
   $disabled_config = config('system.module.disabled');
diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index b370145..e570f97 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -79,13 +79,13 @@ function drupal_get_complete_schema($rebuild = FALSE) {
       // Load the .install files to get hook_schema.
       // On some databases this function may be called before bootstrap has
       // been completed, so we force the functions we need to load just in case.
-      if (function_exists('module_load_all_includes')) {
+      if (function_exists('system_list_reset')) {
         // This function can be called very early in the bootstrap process, so
         // we force the system_list() static cache to be refreshed to ensure
         // that it contains the complete list of modules before we go on to call
         // module_load_all_includes().
         system_list_reset();
-        module_load_all_includes('install');
+        drupal_container()->get('module_handler')->loadAllIncludes('install');
       }
 
       require_once DRUPAL_ROOT . '/core/includes/common.inc';
@@ -130,8 +130,7 @@ function drupal_get_schema_versions($module) {
   $updates = &drupal_static(__FUNCTION__, NULL);
   if (!isset($updates[$module])) {
     $updates = array();
-
-    foreach (module_list() as $loaded_module) {
+    foreach (drupal_container()->get('module_handler')->getModuleList() as $loaded_module => $filename) {
       $updates[$loaded_module] = array();
     }
 
@@ -341,18 +340,18 @@ function _drupal_schema_initialize(&$schema, $module, $remove_descriptions = TRU
  *   An array of fields.
  */
 function drupal_schema_fields_sql($table, $prefix = NULL) {
-  $schema = drupal_get_schema($table);
-  $fields = array_keys($schema['fields']);
-  if ($prefix) {
-    $columns = array();
-    foreach ($fields as $field) {
-      $columns[] = "$prefix.$field";
+  if ($schema = drupal_get_schema($table)) {
+    $fields = array_keys($schema['fields']);
+    if ($prefix) {
+      $columns = array();
+      foreach ($fields as $field) {
+        $columns[] = "$prefix.$field";
+      }
+      return $columns;
     }
-    return $columns;
-  }
-  else {
     return $fields;
   }
+  return array();
 }
 
 /**
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index bab2af5..5dd028b 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -368,14 +368,14 @@ function _theme_load_registry($theme, $base_theme = NULL, $theme_engine = NULL,
       $registry = _theme_build_registry($theme, $base_theme, $theme_engine);
       // Only persist this registry if all modules are loaded. This assures a
       // complete set of theme hooks.
-      if (module_load_all(NULL)) {
+      if (drupal_container()->get('module_handler')->isLoaded()) {
         _theme_save_registry($theme, $registry);
       }
     }
     return $registry;
   }
   else {
-    return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache', array('theme_registry' => TRUE));
+    return new ThemeRegistry('theme_registry:runtime:' . $theme->name, 'cache', array('theme_registry' => TRUE), drupal_container()->get('module_handler')->isLoaded());
   }
 }
 
@@ -441,7 +441,6 @@ function drupal_theme_rebuild() {
  *   themes/bartik.
  *
  * @see theme()
- * @see _theme_process_registry()
  * @see hook_theme()
  * @see list_themes()
  */
@@ -548,7 +547,7 @@ function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
             // Add all modules so they can intervene with their own variable
             // processors. This allows them to provide variable processors even
             // if they are not the owner of the current hook.
-            $prefixes += module_list();
+            $prefixes = array_merge($prefixes, array_keys(drupal_container()->get('module_handler')->getModuleList()));
           }
           elseif ($type == 'theme_engine' || $type == 'base_theme_engine') {
             // Theme engines get an extra set that come before the normally
@@ -644,7 +643,7 @@ function _theme_build_registry($theme, $base_theme, $theme_engine) {
       _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
     }
     // Only cache this registry if all modules are loaded.
-    if (module_load_all(NULL)) {
+    if (drupal_container()->get('module_handler')->isLoaded()) {
       cache()->set("theme_registry:build:modules", $cache, CacheBackendInterface::CACHE_PERMANENT, array('theme_registry' => TRUE));
     }
   }
@@ -959,7 +958,7 @@ function theme($hook, $variables = array()) {
   // If called before all modules are loaded, we do not necessarily have a full
   // theme registry to work with, and therefore cannot process the theme
   // request properly. See also _theme_load_registry().
-  if (!module_load_all(NULL) && !defined('MAINTENANCE_MODE')) {
+  if (!drupal_container()->get('module_handler')->isLoaded() && !defined('MAINTENANCE_MODE')) {
     throw new Exception(t('theme() may not be called until all modules are loaded.'));
   }
 
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index ba88661..71127ad 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -56,8 +56,8 @@ function _drupal_maintenance_theme() {
   // Ensure that system.module is loaded.
   if (!function_exists('_system_rebuild_theme_data')) {
     $module_list['system']['filename'] = 'core/modules/system/system.module';
-    module_list(NULL, $module_list);
-    drupal_load('module', 'system');
+    drupal_container()->get('module_handler')->setModuleList($module_list);
+    drupal_container()->get('module_handler')->load('system');
   }
 
   $themes = list_themes();
diff --git a/core/includes/update.inc b/core/includes/update.inc
index fb81b76..c5292ed 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -9,6 +9,7 @@
  */
 
 use Drupal\Component\Graph\Graph;
+use Drupal\Core\ModuleHandler;
 use Drupal\Core\Config\FileStorage;
 use Drupal\Core\Config\ConfigException;
 use Drupal\Component\Uuid\Uuid;
@@ -91,7 +92,7 @@ function update_prepare_d8_bootstrap() {
   include_once DRUPAL_ROOT . '/core/includes/install.inc';
   include_once DRUPAL_ROOT . '/core/includes/schema.inc';
   // Bootstrap to configuration.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+  drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL);
 
   // Check whether settings.php needs to be rewritten.
   $settings_exist = !empty($GLOBALS['config_directories']);
@@ -125,9 +126,10 @@ function update_prepare_d8_bootstrap() {
 
     include_once DRUPAL_ROOT . '/core/includes/module.inc';
     include_once DRUPAL_ROOT . '/core/includes/cache.inc';
-    $module_list['system']['filename'] = 'core/modules/system/system.module';
-    module_list(NULL, $module_list);
-    require_once DRUPAL_ROOT . '/' . $module_list['system']['filename'];
+    $module_handler = drupal_container()->get('module_handler');
+    $module_handler->setModuleList(array('system' => 'core/modules/system/system.module'));
+
+    $module_handler->load('system');
     // Ensure the configuration directories exist and are writable, or create
     // them. If the directories have not been specified in settings.php and
     // created manually already, and either directory cannot be created by the
@@ -353,8 +355,8 @@ function update_prepare_d8_bootstrap() {
 
       // Populate a fixed module list (again, why did it get lost?) to avoid
       // errors due to the drupal_alter() in _system_rebuild_module_data().
-      $module_list['system']['filename'] = 'core/modules/system/system.module';
-      module_list(NULL, $module_list);
+      $module_list['system'] = 'core/modules/system/system.module';
+      drupal_container()->get('module_handler')->setModuleList($module_list);
       $module_data = _system_rebuild_module_data();
 
       // Migrate each extension into configuration, varying by the extension's
@@ -378,7 +380,14 @@ function update_prepare_d8_bootstrap() {
         }
         $schema_store->set($record->name, $record->schema_version);
       }
-      $module_config->set('enabled', module_config_sort($module_config->get('enabled')))->save();
+      $sorted_modules = module_config_sort($module_config->get('enabled'));
+      $module_config->set('enabled', $sorted_modules)->save();
+      $sorted_with_filenames = array();
+      foreach (array_keys($sorted_modules) as $m) {
+        $sorted_with_filenames[$m] = drupal_get_filename('module', $m);
+      }
+
+      drupal_container()->get('module_handler')->setModuleList($sorted_with_filenames);
       $disabled_modules->save();
       $theme_config->save();
       $disabled_themes->save();
@@ -388,8 +397,6 @@ function update_prepare_d8_bootstrap() {
       update_prepare_stored_includes();
       // Update the environment for the language bootstrap if needed.
       update_prepare_d8_language();
-      // Prime the classloader.
-      system_list('module_enabled');
 
       // Change language column to langcode in url_alias.
       if (db_table_exists('url_alias') && db_field_exists('url_alias', 'language')) {
diff --git a/core/lib/Drupal/Core/CachedModuleHandler.php b/core/lib/Drupal/Core/CachedModuleHandler.php
new file mode 100644
index 0000000..46e0ea5
--- /dev/null
+++ b/core/lib/Drupal/Core/CachedModuleHandler.php
@@ -0,0 +1,177 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\CachedModuleHandler.
+ */
+
+namespace Drupal\Core;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+
+/**
+ * Class that manages enabled modules in a Drupal installation.
+ */
+class CachedModuleHandler extends ModuleHandler implements CachedModuleHandlerInterface {
+
+  /**
+   * State key/value store.
+   *
+   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
+   */
+  protected $state;
+
+  /**
+   * Cache backend for storing enabled modules.
+   *
+   * @var \Drupal\Core\Cache\CacheBackendInterface
+   */
+  protected $bootstrapCache;
+
+  /**
+   * Whether the cache needs to be written.
+   *
+   * @var boolean
+   */
+  protected $cacheNeedsWriting = FALSE;
+
+  /**
+   * Constructs a ModuleHandler object.
+   */
+  public function __construct(array $module_list = array(), KeyValueStoreInterface $state, CacheBackendInterface $bootstrap_cache) {
+    $this->moduleList = $module_list;
+    $this->state = $state;
+    $this->bootstrapCache = $bootstrap_cache;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::getBootstrapModules().
+   */
+  public function getBootstrapModules() {
+    if (isset($this->bootstrapModules)) {
+      return $this->bootstrapModules;
+    }
+    if ($cached = $this->bootstrapCache->get('bootstrap_modules')) {
+      $bootstrap_list = $cached->data;
+    }
+    else {
+      $bootstrap_list = $this->state->get('system.module.bootstrap') ?: array();
+      $this->bootstrapCache->set('bootstrap_modules', $bootstrap_list);
+    }
+    $this->bootstrapModules = array_keys($bootstrap_list);
+    return $this->bootstrapModules;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::resetImplementations().
+   */
+  public function resetImplementations() {
+    // We maintain a persistent cache of hook implementations in addition to the
+    // static cache to avoid looping through every module and every hook on each
+    // request. Benchmarks show that the benefit of this caching outweighs the
+    // additional database hit even when using the default database caching
+    // backend and only a small number of modules are enabled. The cost of the
+    // $this->bootstrapCache->get() is more or less constant and reduced further when
+    // non-database caching backends are used, so there will be more significant
+    // gains when a large number of modules are installed or hooks invoked, since
+    // this can quickly lead to module_hook() being called several thousand times
+    // per request.
+    parent::resetImplementations();
+    $this->bootstrapCache->set('module_implements', array());
+    $this->bootstrapCache->delete('hook_info');
+  }
+
+  /**
+   * Implements \Drupal\Core\CachedModuleHandlerInterface::writeCache().
+   */
+  public function writeCache() {
+    if ($this->cacheNeedsWriting) {
+      $this->bootstrapCache->set('module_implements', $this->implementations);
+      $this->cacheNeedsWriting = FALSE;
+    }
+  }
+
+  /**
+   * Overrides \Drupal\Core\ModuleHandler::getImplementationInfo().
+   */
+  protected function getImplementationInfo($hook) {
+    $implementations = $this->getCachedImplementations();
+    if (!isset($implementations[$hook])) {
+      // The hook is not cached, so ensure that whether or not it has
+      // implementations, the cache is updated at the end of the request.
+      $this->cacheNeedsWriting = TRUE;
+      $implementations[$hook] = parent::getImplementationInfo($hook);
+    }
+    else {
+      foreach ($implementations[$hook] as $module => $group) {
+        // If this hook implementation is stored in a lazy-loaded file, include
+        // that file first.
+        if ($group) {
+          $this->loadInclude($module, 'inc', "$module.$group");
+        }
+        // It is possible that a module removed a hook implementation without the
+        // implementations cache being rebuilt yet, so we check whether the
+        // function exists on each request to avoid undefined function errors.
+        // Since module_hook() may needlessly try to load the include file again,
+        // function_exists() is used directly here.
+        if (!function_exists($module . '_' . $hook)) {
+          // Clear out the stale implementation from the cache and force a cache
+          // refresh to forget about no longer existing hook implementations.
+          unset($implementations[$hook][$module]);
+          $this->cacheNeedsWriting = TRUE;
+        }
+      }
+    }
+    $this->implementations = $implementations;
+    return $implementations[$hook];
+  }
+
+  /**
+   * Overrides \Drupal\Core\ModuleHandler::getHookInfo().
+   */
+  protected function getHookInfo() {
+    // When this function is indirectly invoked from bootstrap_invoke_all() prior
+    // to all modules being loaded, we do not want to cache an incomplete
+    // hook_hookInfo() result, so instead return an empty array. This requires
+    // bootstrap hook implementations to reside in the .module file, which is
+    // optimal for performance anyway.
+    if (!$this->loaded) {
+      return array();
+    }
+    // Optimize for fast access to definitions if they are already in memory.
+    if (isset($this->hookInfo)) {
+      return $this->hookInfo;
+    }
+
+    $this->hookInfo = array();
+    $cache = $this->bootstrapCache->get('hook_info');
+    if ($cache === FALSE) {
+      $this->hookInfo = parent::getHookInfo();
+      $this->bootstrapCache->set('hook_info', $this->hookInfo);
+    }
+    else {
+      $this->hookInfo = $cache->data;
+    }
+    return $this->hookInfo;
+  }
+
+  /**
+   * Retrieves hook implementation info from the cache.
+   */
+  protected function getCachedImplementations() {
+    if (isset($this->implementations)) {
+      return $this->implementations;
+    }
+
+    $implementations = $this->bootstrapCache->get('module_implements');
+    if ($implementations === FALSE) {
+      $implementations = array();
+    }
+    else {
+      $implementations = $implementations->data;
+    }
+    $this->implementations = $implementations;
+    return $implementations;
+  }
+}
diff --git a/core/lib/Drupal/Core/CachedModuleHandlerInterface.php b/core/lib/Drupal/Core/CachedModuleHandlerInterface.php
new file mode 100644
index 0000000..4eabc8b
--- /dev/null
+++ b/core/lib/Drupal/Core/CachedModuleHandlerInterface.php
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\CachedModuleHandlerInterface.
+ */
+
+namespace Drupal\Core;
+
+/**
+ * Interface for cacheable module handlers.
+ */
+interface CachedModuleHandlerInterface extends ModuleHandlerInterface {
+
+  /**
+   * Write the hook implementation info to the cache.
+   */
+  public function writeCache();
+
+}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 52af901..84896e6 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -73,6 +73,12 @@ public function build(ContainerBuilder $container) {
       ->register('keyvalue.database', 'Drupal\Core\KeyValueStore\KeyValueDatabaseFactory')
       ->addArgument(new Reference('database'));
 
+    // Register the state k/v store as a service.
+    $container->register('state', 'Drupal\Core\KeyValueStore\KeyValueStoreInterface')
+      ->setFactoryService(new Reference('keyvalue'))
+      ->setFactoryMethod('get')
+      ->addArgument('state');
+
     $container->register('path.alias_manager', 'Drupal\Core\Path\AliasManager')
       ->addArgument(new Reference('database'))
       ->addArgument(new Reference('keyvalue'));
@@ -101,6 +107,20 @@ public function build(ContainerBuilder $container) {
       ->addArgument(new Reference('service_container'));
     $container->register('controller_resolver', 'Drupal\Core\ControllerResolver')
       ->addArgument(new Reference('service_container'));
+
+    $container
+      ->register('cache.cache', 'Drupal\Core\Cache\CacheBackendInterface')
+      ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+      ->setFactoryMethod('get')
+      ->addArgument('cache');
+    $container
+      ->register('cache.bootstrap', 'Drupal\Core\Cache\CacheBackendInterface')
+      ->setFactoryClass('Drupal\Core\Cache\CacheFactory')
+      ->setFactoryMethod('get')
+      ->addArgument('bootstrap');
+
+    $this->registerModuleHandler($container);
+
     $container->register('http_kernel', 'Drupal\Core\HttpKernel')
       ->addArgument(new Reference('event_dispatcher'))
       ->addArgument(new Reference('service_container'))
@@ -130,8 +150,8 @@ public function build(ContainerBuilder $container) {
     $container->register('router.builder', 'Drupal\Core\Routing\RouteBuilder')
       ->addArgument(new Reference('router.dumper'))
       ->addArgument(new Reference('lock'))
-      ->addArgument(new Reference('event_dispatcher'));
-
+      ->addArgument(new Reference('event_dispatcher'))
+      ->addArgument(new Reference('module_handler'));
 
     $container->register('matcher', 'Drupal\Core\Routing\ChainMatcher');
     $container->register('legacy_url_matcher', 'Drupal\Core\LegacyUrlMatcher')
@@ -213,6 +233,7 @@ public function build(ContainerBuilder $container) {
       ->setScope('request')
       ->addTag('event_subscriber');
     $container->register('request_close_subscriber', 'Drupal\Core\EventSubscriber\RequestCloseSubscriber')
+      ->addArgument(new Reference('module_handler'))
       ->addTag('event_subscriber');
     $container->register('config_global_override_subscriber', 'Drupal\Core\EventSubscriber\ConfigGlobalOverrideSubscriber')
       ->addTag('event_subscriber');
@@ -250,6 +271,25 @@ public function build(ContainerBuilder $container) {
   }
 
   /**
+   * Registers the module handler.
+   */
+  protected function registerModuleHandler(ContainerBuilder $container) {
+    // The ModuleHandler manages enabled modules and provides the ability to
+    // invoke hooks in all enabled modules.
+    if ($container->getParameter('kernel.environment') == 'install') {
+      // During installation we use the non-cached version.
+      $container->register('module_handler', 'Drupal\Core\ModuleHandler')
+        ->addArgument('%container.modules%');
+    }
+    else {
+      $container->register('module_handler', 'Drupal\Core\CachedModuleHandler')
+        ->addArgument('%container.modules%')
+        ->addArgument(new Reference('state'))
+        ->addArgument(new Reference('cache.bootstrap'));
+    }
+  }
+
+  /**
    * Registers Twig services.
    */
   protected function registerTwig(ContainerBuilder $container) {
diff --git a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
index 8d5f87a..2358a09 100644
--- a/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/RequestCloseSubscriber.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\Core\EventSubscriber;
 
+use Drupal\Core\ModuleHandlerInterface;
 use Symfony\Component\HttpKernel\KernelEvents;
 use Symfony\Component\HttpKernel\Event\PostResponseEvent;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -16,6 +17,18 @@
  */
 class RequestCloseSubscriber implements EventSubscriberInterface {
 
+   /**
+   * @var ModuleHandlerInterface
+   */
+  protected $ModuleHandler;
+
+  /**
+   * Constructor.
+   */
+  function __construct(ModuleHandlerInterface $module_handler) {
+    $this->ModuleHandler = $module_handler;
+  }
+
   /**
    * Performs end of request tasks.
    *
@@ -28,8 +41,15 @@ class RequestCloseSubscriber implements EventSubscriberInterface {
    *   The Event to process.
    */
   public function onTerminate(PostResponseEvent $event) {
-    module_invoke_all('exit');
-    module_implements_write_cache();
+    $this->ModuleHandler->invokeAll('exit');
+    $request_method = $event->getRequest()->getMethod();
+    // Check whether we need to write the module implementations cache. We do
+    // not want to cache hooks which are only invoked on HTTP POST requests
+    // since these do not need to be optimized as tightly, and not doing so
+    // keeps the cache entry smaller.
+    if (($request_method == 'GET' || $request_method == 'HEAD') && is_callable(array($this->ModuleHandler, 'writeCache'))) {
+      $this->ModuleHandler->writeCache();
+    }
     system_run_automated_cron();
   }
 
diff --git a/core/lib/Drupal/Core/ModuleHandler.php b/core/lib/Drupal/Core/ModuleHandler.php
new file mode 100644
index 0000000..698aa7e
--- /dev/null
+++ b/core/lib/Drupal/Core/ModuleHandler.php
@@ -0,0 +1,499 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ModuleHandler.
+ */
+
+namespace Drupal\Core;
+
+use Drupal\Component\Graph\Graph;
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
+use Drupal\Core\ModuleHandlerInterface;
+
+/**
+ * Class that manages enabled modules in a Drupal installation.
+ */
+class ModuleHandler implements ModuleHandlerInterface {
+
+  /**
+   * Keeps track internally of loaded files.
+   */
+  protected $loadedFiles;
+
+  /**
+   * Keeps track internally of enabled modules and themes.
+   */
+  protected $bootstrapModules;
+
+  /**
+   * Array of enabled modules.
+   */
+  protected $moduleList;
+
+  /**
+   * Boolean indicating whether modules have been loaded.
+   */
+  protected $loaded = FALSE;
+
+  /**
+   * Keeps track internally of hook implementations.
+   */
+  protected $implementations;
+
+  /**
+   * Keeps track internally of hook info.
+   */
+  protected $hookInfo;
+
+  /**
+   * Keeps track internally of alter functions.
+   */
+  protected $alterFunctions;
+
+  /**
+   * Constructs a ModuleHandler object.
+   */
+  public function __construct(array $module_list = array()) {
+    $this->moduleList = $module_list;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::load().
+   */
+  public function load($name) {
+    if (isset($this->loadedFiles[$name])) {
+      return TRUE;
+    }
+
+    if (isset($this->moduleList[$name])) {
+      $filename = $this->moduleList[$name];
+      include_once DRUPAL_ROOT . '/' . $filename;
+      $this->loadedFiles[$name] = TRUE;
+      return TRUE;
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::loadAll().
+   */
+  public function loadAll() {
+    if (!$this->loaded) {
+      foreach ($this->moduleList as $module => $filename) {
+        $this->load($module);
+      }
+      $this->loaded = TRUE;
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::reload().
+   */
+  public function reload() {
+    $this->loaded = FALSE;
+    $this->loadAll();
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::loadBootstrapModules().
+   */
+  public function loadBootstrapModules() {
+    if (!$this->loaded) {
+      foreach ($this->getBootstrapModules() as $module) {
+        $this->load($module);
+      }
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::isLoaded().
+   */
+  public function isLoaded() {
+    return $this->loaded;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::getModuelList().
+   */
+  public function getModuleList() {
+    return $this->moduleList;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::setModuleList().
+   */
+  public function setModuleList(array $module_list = array()) {
+    $this->moduleList = $module_list;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::getBootstrapModules().
+   */
+  public function getBootstrapModules() {
+    // The basic module handler does not know anything about how to retrieve a
+    // list of bootstrap modules.
+    return array();
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::buildModuleDependencies().
+   */
+  public function buildModuleDependencies(array $modules) {
+    foreach ($modules as $name => $module) {
+      $graph[$module->name]['edges'] = array();
+      if (isset($module->info['dependencies']) && is_array($module->info['dependencies'])) {
+        foreach ($module->info['dependencies'] as $dependency) {
+          $dependency_data = $this->parseDependency($dependency);
+          $graph[$module->name]['edges'][$dependency_data['name']] = $dependency_data;
+        }
+      }
+    }
+    $graph_object = new Graph($graph);
+    $graph = $graph_object->searchAndSort();
+    foreach ($graph as $module_name => $data) {
+      $modules[$module_name]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array();
+      $modules[$module_name]->requires = isset($data['paths']) ? $data['paths'] : array();
+      $modules[$module_name]->sort = $data['weight'];
+    }
+    return $modules;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::moduleExists().
+   */
+  public function moduleExists($module) {
+    return isset($this->moduleList[$module]);
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::loadAllIncludes().
+   */
+  public function loadAllIncludes($type, $name = NULL) {
+    foreach ($this->moduleList as $module => $filename) {
+      $this->loadInclude($module, $type, $name);
+    }
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::loadInclude().
+   */
+  public function loadInclude($module, $type, $name = NULL) {
+    if ($type == 'install') {
+      // Make sure the installation API is available
+      include_once DRUPAL_ROOT . '/core/includes/install.inc';
+    }
+
+    $name = $name ?: $module;
+    $file = DRUPAL_ROOT . '/' . dirname($this->moduleList[$module]) . "/$name.$type";
+    if (is_file($file)) {
+      require_once $file;
+      return $file;
+    }
+
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::getImplementations().
+   */
+  public function getImplementations($hook) {
+    $implementations = $this->getImplementationInfo($hook);
+    return array_keys($implementations);
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::resetImplementations().
+   */
+  public function resetImplementations() {
+    $this->implementations = NULL;
+    $this->hookInfo = NULL;
+    $this->alterFunctions = NULL;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::implementsHook().
+   */
+  public function implementsHook($module, $hook) {
+    $function = $module . '_' . $hook;
+    if (function_exists($function)) {
+      return TRUE;
+    }
+    // If the hook implementation does not exist, check whether it lives in an
+    // optional include file registered via hook_hook_info().
+    $hook_info = $this->getHookInfo();
+    if (isset($hook_info[$hook]['group'])) {
+      $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']);
+      if (function_exists($function)) {
+        return TRUE;
+      }
+    }
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::invokeAll().
+   */
+  public function invokeAll($hook, $args = array()) {
+    $return = array();
+    $implementations = $this->getImplementations($hook);
+    foreach ($implementations as $module) {
+      $function = $module . '_' . $hook;
+      if (function_exists($function)) {
+        $result = call_user_func_array($function, $args);
+        if (isset($result) && is_array($result)) {
+          $return = NestedArray::mergeDeep($return, $result);
+        }
+        elseif (isset($result)) {
+          $return[] = $result;
+        }
+      }
+    }
+
+    return $return;
+  }
+
+  /**
+   * Implements \Drupal\Core\ModuleHandlerInterface::alter().
+   */
+  public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
+    // Most of the time, $type is passed as a string, so for performance,
+    // normalize it to that. When passed as an array, usually the first item in
+    // the array is a generic type, and additional items in the array are more
+    // specific variants of it, as in the case of array('form', 'form_FORM_ID').
+    if (is_array($type)) {
+      $cid = implode(',', $type);
+      $extra_types = $type;
+      $type = array_shift($extra_types);
+      // Allow if statements in this function to use the faster isset() rather
+      // than !empty() both when $type is passed as a string, or as an array with
+      // one item.
+      if (empty($extra_types)) {
+        unset($extra_types);
+      }
+    }
+    else {
+      $cid = $type;
+    }
+
+    // Some alter hooks are invoked many times per page request, so store the
+    // list of functions to call, and on subsequent calls, iterate through them
+    // quickly.
+    if (!isset($this->alterFunctions[$cid])) {
+      $this->alterFunctions[$cid] = array();
+      $hook = $type . '_alter';
+      $modules = $this->getImplementations($hook);
+      if (!isset($extra_types)) {
+        // For the more common case of a single hook, we do not need to call
+        // function_exists(), since $this->getImplementations() returns only modules with
+        // implementations.
+        foreach ($modules as $module) {
+          $this->alterFunctions[$cid][] = $module . '_' . $hook;
+        }
+      }
+      else {
+        // For multiple hooks, we need $modules to contain every module that
+        // implements at least one of them.
+        $extra_modules = array();
+        foreach ($extra_types as $extra_type) {
+          $extra_modules = array_merge($extra_modules, $this->getImplementations($extra_type . '_alter'));
+        }
+        // If any modules implement one of the extra hooks that do not implement
+        // the primary hook, we need to add them to the $modules array in their
+        // appropriate order. $this->getImplementations() can only return ordered
+        // implementations of a single hook. To get the ordered implementations
+        // of multiple hooks, we mimic the $this->getImplementations() logic of first
+        // ordering by $this->getModuleList(), and then calling
+        // $this->alter('module_implements').
+        if (array_diff($extra_modules, $modules)) {
+          // Merge the arrays and order by getModuleList().
+          $modules = array_intersect(array_keys($this->moduleList), array_merge($modules, $extra_modules));
+          // Since $this->getImplementations() already took care of loading the necessary
+          // include files, we can safely pass FALSE for the array values.
+          $implementations = array_fill_keys($modules, FALSE);
+          // Let modules adjust the order solely based on the primary hook. This
+          // ensures the same module order regardless of whether this if block
+          // runs. Calling $this->alter() recursively in this way does not result
+          // in an infinite loop, because this call is for a single $type, so we
+          // won't end up in this code block again.
+          $this->alter('module_implements', $implementations, $hook);
+          $modules = array_keys($implementations);
+        }
+        foreach ($modules as $module) {
+          // Since $modules is a merged array, for any given module, we do not
+          // know whether it has any particular implementation, so we need a
+          // function_exists().
+          $function = $module . '_' . $hook;
+          if (function_exists($function)) {
+            $this->alterFunctions[$cid][] = $function;
+          }
+          foreach ($extra_types as $extra_type) {
+            $function = $module . '_' . $extra_type . '_alter';
+            if (function_exists($function)) {
+              $this->alterFunctions[$cid][] = $function;
+            }
+          }
+        }
+      }
+      // Allow the theme to alter variables after the theme system has been
+      // initialized.
+      global $theme, $base_theme_info;
+      if (isset($theme)) {
+        $theme_keys = array();
+        foreach ($base_theme_info as $base) {
+          $theme_keys[] = $base->name;
+        }
+        $theme_keys[] = $theme;
+        foreach ($theme_keys as $theme_key) {
+          $function = $theme_key . '_' . $hook;
+          if (function_exists($function)) {
+            $this->alterFunctions[$cid][] = $function;
+          }
+          if (isset($extra_types)) {
+            foreach ($extra_types as $extra_type) {
+              $function = $theme_key . '_' . $extra_type . '_alter';
+              if (function_exists($function)) {
+                $this->alterFunctions[$cid][] = $function;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    foreach ($this->alterFunctions[$cid] as $function) {
+      $function($data, $context1, $context2);
+    }
+  }
+
+  /**
+   * Provides information about modules' implementations of a hook.
+   *
+   * @param $hook
+   *   The name of the hook (e.g. "help" or "menu").
+   *
+   * @return
+   *   An array whose keys are the names of the modules which are implementing
+   *   this hook and whose values are either an array of information from
+   *   hook_hook_info or FALSE if the implementation is in the module file.
+   *
+   */
+  protected function getImplementationInfo($hook) {
+    $this->implementations = $this->implementations ?: array();
+    if (isset($this->implementations[$hook])) {
+      return $this->implementations[$hook];
+    }
+    $hook_info = $this->getHookInfo();
+    $this->implementations[$hook] = array();
+    foreach ($this->moduleList as $module => $filename) {
+      $include_file = isset($hook_info[$hook]['group']) && $this->loadInclude($module, 'inc', $module . '.' . $hook_info[$hook]['group']);
+      // Since $this->hookImplements() may needlessly try to load the include
+      // file again, function_exists() is used directly here.
+      if (function_exists($module . '_' . $hook)) {
+        $this->implementations[$hook][$module] = $include_file ? $hook_info[$hook]['group'] : FALSE;
+      }
+    }
+    // Allow modules to change the weight of specific implementations but avoid
+    // an infinite loop.
+    if ($hook != 'module_implements_alter') {
+      $this->alter('module_implements', $this->implementations[$hook], $hook);
+    }
+    return $this->implementations[$hook];
+  }
+
+  /**
+   * Retrieves a list of hooks that are declared through hook_hook_info().
+   *
+   * @return
+   *   An associative array whose keys are hook names and whose values are an
+   *   associative array containing a group name. The structure of the array
+   *   is the same as the return value of hook_hook_info().
+   *
+   * @see hook_hook_info()
+   */
+  protected function getHookInfo() {
+    if ($this->hookInfo) {
+      return $this->hookInfo;
+    }
+    $this->hookInfo = array();
+    // We can't use $this->invokeAll() here or it would cause an infinite
+    // loop.
+    foreach ($this->moduleList as $module => $filename) {
+      $function = $module . '_hook_info';
+      if (function_exists($function)) {
+        $result = $function();
+        if (isset($result) && is_array($result)) {
+          $this->hookInfo = NestedArray::mergeDeep($this->hookInfo, $result);
+        }
+      }
+    }
+    // We can't use $this->alter() for the same reason as above.
+    foreach ($this->moduleList as $module => $filename) {
+      $function = $module . '_hook_info_alter';
+      if (function_exists($function)) {
+        $function($this->hookInfo);
+      }
+    }
+    return $this->hookInfo;
+  }
+
+  /**
+   * Parses a dependency for comparison by drupal_check_incompatibility().
+   *
+   * @param $dependency
+   *   A dependency string, for example 'foo (>=8.x-4.5-beta5, 3.x)'.
+   *
+   * @return
+   *   An associative array with three keys:
+   *   - 'name' includes the name of the thing to depend on (e.g. 'foo').
+   *   - 'original_version' contains the original version string (which can be
+   *     used in the UI for reporting incompatibilities).
+   *   - 'versions' is a list of associative arrays, each containing the keys
+   *     'op' and 'version'. 'op' can be one of: '=', '==', '!=', '<>', '<',
+   *     '<=', '>', or '>='. 'version' is one piece like '4.5-beta3'.
+   *   Callers should pass this structure to drupal_check_incompatibility().
+   *
+   * @see drupal_check_incompatibility()
+   */
+  protected function parseDependency($dependency) {
+    // We use named subpatterns and support every op that version_compare
+    // supports. Also, op is optional and defaults to equals.
+    $p_op = '(?P<operation>!=|==|=|<|<=|>|>=|<>)?';
+    // Core version is always optional: 8.x-2.x and 2.x is treated the same.
+    $p_core = '(?:' . preg_quote(DRUPAL_CORE_COMPATIBILITY) . '-)?';
+    $p_major = '(?P<major>\d+)';
+    // By setting the minor version to x, branches can be matched.
+    $p_minor = '(?P<minor>(?:\d+|x)(?:-[A-Za-z]+\d+)?)';
+    $value = array();
+    $parts = explode('(', $dependency, 2);
+    $value['name'] = trim($parts[0]);
+    if (isset($parts[1])) {
+      $value['original_version'] = ' (' . $parts[1];
+      foreach (explode(',', $parts[1]) as $version) {
+        if (preg_match("/^\s*$p_op\s*$p_core$p_major\.$p_minor/", $version, $matches)) {
+          $op = !empty($matches['operation']) ? $matches['operation'] : '=';
+          if ($matches['minor'] == 'x') {
+            // Drupal considers "2.x" to mean any version that begins with
+            // "2" (e.g. 2.0, 2.9 are all "2.x"). PHP's version_compare(),
+            // on the other hand, treats "x" as a string; so to
+            // version_compare(), "2.x" is considered less than 2.0. This
+            // means that >=2.x and <2.x are handled by version_compare()
+            // as we need, but > and <= are not.
+            if ($op == '>' || $op == '<=') {
+              $matches['major']++;
+            }
+            // Equivalence can be checked by adding two restrictions.
+            if ($op == '=' || $op == '==') {
+              $value['versions'][] = array('op' => '<', 'version' => ($matches['major'] + 1) . '.x');
+              $op = '>=';
+            }
+          }
+          $value['versions'][] = array('op' => $op, 'version' => $matches['major'] . '.' . $matches['minor']);
+        }
+      }
+    }
+    return $value;
+  }
+}
diff --git a/core/lib/Drupal/Core/ModuleHandlerInterface.php b/core/lib/Drupal/Core/ModuleHandlerInterface.php
new file mode 100644
index 0000000..ed8daff
--- /dev/null
+++ b/core/lib/Drupal/Core/ModuleHandlerInterface.php
@@ -0,0 +1,228 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\ModuleHandlerInterface.
+ */
+
+namespace Drupal\Core;
+
+/**
+ * Interface for classes that manage a set of enabled modules.
+ *
+ * Classes implementing this interface work with a fixed list of modules and are
+ * responsible for loading module files and maintaining information about module
+ * dependencies and hook implementations.
+ */
+interface ModuleHandlerInterface {
+
+  /**
+   * Includes a file with the provided type and name.
+   *
+   * This prevents including a module more than once.
+   *
+   * @param $name
+   *   The name of the module to load.
+   *
+   * @return
+   *   TRUE if the item is loaded or has already been loaded.
+   */
+  public function load($name);
+
+  /**
+   * Loads all the modules that have been enabled.
+   */
+  public function loadAll();
+
+  /**
+   * Loads all bootstrap modules.
+   */
+  public function loadBootstrapModules();
+
+  /**
+   * Returns whether all modules have been loaded.
+   *
+   * @return bool
+   *   A Boolean indicating whether all modules have been loaded. This means all
+   *   modules; the load status of bootstrap modules cannot be checked.
+   */
+  public function isLoaded();
+
+  /**
+   * Reloads all enabled modules.
+   */
+  public function reload();
+
+  /**
+   * Returns a list of currently active modules.
+   *
+   * @return array
+   *   An associative array whose keys are the names of the modules and whose
+   *   values are the module filenames.
+   */
+  public function getModuleList();
+
+  /**
+   * Explicitly sets the moduleList property to the passed in array of modules.
+   */
+  public function setModuleList(array $module_list = array());
+
+  /**
+   * Retrieves the list of bootstrap modules.
+   */
+  public function getBootstrapModules();
+
+  /**
+   * Determines which modules require and are required by each module.
+   *
+   * @param $modules
+   *   An array of module objects keyed by module name. Each object contains
+   *   information discovered during a Drupal\Core\SystemListing scan.
+   *
+   * @return
+   *   The same array with the new keys for each module:
+   *   - requires: An array with the keys being the modules that this module
+   *     requires.
+   *   - required_by: An array with the keys being the modules that will not work
+   *     without this module.
+   *
+   * @see \Drupal\Core\SystemListing
+   */
+  public function buildModuleDependencies(array $modules);
+
+  /**
+   * Determines whether a given module exists.
+   *
+   * @param $module
+   *   The name of the module (without the .module extension).
+   *
+   * @return
+   *   TRUE if the module is both installed and enabled.
+   */
+  public function moduleExists($module);
+
+  /**
+   * Loads an include file for each module enabled.
+   */
+  public function loadAllIncludes($type, $name = NULL);
+
+  /**
+   * Loads a module include file.
+   *
+   * Examples:
+   * @code
+   *   // Load node.admin.inc from the node module.
+   *   $this->loadInclude('node', 'inc', 'node.admin');
+   *   // Load content_types.inc from the node module.
+   *   $this->loadInclude('node', 'inc', ''content_types');
+   * @endcode
+   *
+   * @param $module
+   *   The module to which the include file belongs.
+   * @param $type
+   *   The include file's type (file extension).
+   * @param $name
+   *   (optional) The base file name (without the $type extension). If omitted,
+   *   $module is used; i.e., resulting in "$module.$type" by default.
+   *
+   * @return
+   *   The name of the included file, if successful; FALSE otherwise.
+   */
+  public function loadInclude($module, $type, $name = NULL);
+
+  /**
+   * Determines which modules are implementing a hook.
+   *
+   * @param $hook
+   *   The name of the hook (e.g. "help" or "menu").
+   *
+   * @return
+   *   An array with the names of the modules which are implementing this hook.
+   *
+   */
+  public function getImplementations($hook);
+
+  /**
+   * Regenerates the stored list of hook implementations.
+   */
+  public function resetImplementations();
+
+  /**
+   * Determines whether a module implements a hook.
+   *
+   * @param $module
+   *   The name of the module (without the .module extension).
+   * @param $hook
+   *   The name of the hook (e.g. "help" or "menu").
+   *
+   * @return
+   *   TRUE if the module is both installed and enabled, and the hook is
+   *   implemented in that module.
+   */
+  public function implementsHook($module, $hook);
+
+  /**
+   * Invokes a hook in all enabled modules that implement it.
+   *
+   * @param $hook
+   *   The name of the hook to invoke.
+   * @param ...
+   *   Arguments to pass to the hook.
+   *
+   * @return
+   *   An array of return values of the hook implementations. If modules return
+   *   arrays from their implementations, those are merged into one array.
+   */
+  public function invokeAll($hook, $args = array());
+
+  /**
+   * Passes alterable variables to specific hook_TYPE_alter() implementations.
+   *
+   * This dispatch function hands off the passed-in variables to type-specific
+   * hook_TYPE_alter() implementations in modules. It ensures a consistent
+   * interface for all altering operations.
+   *
+   * A maximum of 2 alterable arguments is supported. In case more arguments need
+   * to be passed and alterable, modules provide additional variables assigned by
+   * reference in the last $context argument:
+   * @code
+   *   $context = array(
+   *     'alterable' => &$alterable,
+   *     'unalterable' => $unalterable,
+   *     'foo' => 'bar',
+   *   );
+   *   $this->alter('mymodule_data', $alterable1, $alterable2, $context);
+   * @endcode
+   *
+   * Note that objects are always passed by reference in PHP5. If it is absolutely
+   * required that no implementation alters a passed object in $context, then an
+   * object needs to be cloned:
+   * @code
+   *   $context = array(
+   *     'unalterable_object' => clone $object,
+   *   );
+   *   $this->alter('mymodule_data', $data, $context);
+   * @endcode
+   *
+   * @param $type
+   *   A string describing the type of the alterable $data. 'form', 'links',
+   *   'node_content', and so on are several examples. Alternatively can be an
+   *   array, in which case hook_TYPE_alter() is invoked for each value in the
+   *   array, ordered first by module, and then for each module, in the order of
+   *   values in $type. For example, when Form API is using $this->alter() to
+   *   execute both hook_form_alter() and hook_form_FORM_ID_alter()
+   *   implementations, it passes array('form', 'form_' . $form_id) for $type.
+   * @param $data
+   *   The variable that will be passed to hook_TYPE_alter() implementations to be
+   *   altered. The type of this variable depends on the value of the $type
+   *   argument. For example, when altering a 'form', $data will be a structured
+   *   array. When altering a 'profile', $data will be an object.
+   * @param $context1
+   *   (optional) An additional variable that is passed by reference.
+   * @param $context2
+   *   (optional) An additional variable that is passed by reference. If more
+   *   context needs to be provided to implementations, then this should be an
+   *   associative array as described above.
+   */
+  public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL);
+}
diff --git a/core/lib/Drupal/Core/Routing/RouteBuilder.php b/core/lib/Drupal/Core/Routing/RouteBuilder.php
index 6f7a86e..f6ec656 100644
--- a/core/lib/Drupal/Core/Routing/RouteBuilder.php
+++ b/core/lib/Drupal/Core/Routing/RouteBuilder.php
@@ -13,6 +13,7 @@
 use Symfony\Component\Routing\RouteCollection;
 use Symfony\Component\Routing\Route;
 
+use Drupal\Core\ModuleHandlerInterface;
 use Drupal\Core\Lock\LockBackendInterface;
 
 /**
@@ -45,6 +46,13 @@ class RouteBuilder {
   protected $dispatcher;
 
   /**
+   * The extension handler for retieving the list of enabled modules.
+   *
+   * @var \Drupal\Core\ModuleHandlerInterface
+   */
+  protected $ModuleHandler;
+
+  /**
    * Construcs the RouteBuilder using the passed MatcherDumperInterface.
    *
    * @param \Symfony\Component\Routing\Matcher\Dumper\MatcherDumperInterface $dumper
@@ -54,10 +62,11 @@ class RouteBuilder {
    * @param \Symfony\Component\EventDispatcherEventDispatcherInterface
    *   The event dispatcher to notify of routes.
    */
-  public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher) {
+  public function __construct(MatcherDumperInterface $dumper, LockBackendInterface $lock, EventDispatcherInterface $dispatcher, ModuleHandlerInterface $module_handler) {
     $this->dumper = $dumper;
     $this->lock = $lock;
     $this->dispatcher = $dispatcher;
+    $this->ModuleHandler = $module_handler;
   }
 
   /**
@@ -76,11 +85,9 @@ public function rebuild() {
 
     // We need to manually call each module so that we can know which module
     // a given item came from.
-    // @todo Use an injected Extension service rather than module_list():
-    //   http://drupal.org/node/1331486.
-    foreach (module_list() as $module) {
+    foreach ($this->ModuleHandler->getModuleList() as $module => $filename) {
       $collection = new RouteCollection();
-      $routing_file = DRUPAL_ROOT . '/' . drupal_get_path('module', $module) . '/' . $module . '.routing.yml';
+      $routing_file = DRUPAL_ROOT . '/' . dirname($filename) . '/' . $module . '.routing.yml';
       if (file_exists($routing_file)) {
         $routes = $parser->parse(file_get_contents($routing_file));
         if (!empty($routes)) {
diff --git a/core/lib/Drupal/Core/Utility/ThemeRegistry.php b/core/lib/Drupal/Core/Utility/ThemeRegistry.php
index bc9691c..eb2dd80 100644
--- a/core/lib/Drupal/Core/Utility/ThemeRegistry.php
+++ b/core/lib/Drupal/Core/Utility/ThemeRegistry.php
@@ -42,12 +42,14 @@ class ThemeRegistry extends CacheArray {
    *   The bin to cache the array.
    * @param array $tags
    *   (optional) The tags to specify for the cache item.
+   * @param bool $modules_loaded
+   *   Whether all modules have already been loaded.
    */
-  function __construct($cid, $bin, $tags) {
+  function __construct($cid, $bin, $tags, $modules_loaded = FALSE) {
     $this->cid = $cid;
     $this->bin = $bin;
     $this->tags = $tags;
-    $this->persistable = module_load_all(NULL) && $_SERVER['REQUEST_METHOD'] == 'GET';
+    $this->persistable = $modules_loaded && $_SERVER['REQUEST_METHOD'] == 'GET';
 
     $data = array();
     if ($this->persistable && $cached = cache($this->bin)->get($this->cid)) {
diff --git a/core/modules/breakpoint/breakpoint.install b/core/modules/breakpoint/breakpoint.install
index 0e6bc30..cba7b1b 100644
--- a/core/modules/breakpoint/breakpoint.install
+++ b/core/modules/breakpoint/breakpoint.install
@@ -18,6 +18,5 @@ function breakpoint_enable() {
   _breakpoint_theme_enabled(array_keys($themes));
 
   // Import breakpoints from modules.
-  $modules = module_list();
-  _breakpoint_modules_enabled(array_keys($modules));
+  _breakpoint_modules_enabled(array_keys(drupal_container()->get('module_handler')->getModuleList()));
 }
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
index ab03d41..4b40e7d 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentFieldsTest.php
@@ -72,6 +72,7 @@ function testCommentEnable() {
     $edit = array();
     $edit['modules[Core][comment][enable]'] = FALSE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->resetAll();
     $this->assertFalse(module_exists('comment'), 'Comment module disabled.');
 
@@ -80,11 +81,14 @@ function testCommentEnable() {
     $edit['modules[Core][book][enable]'] = 'book';
     $edit['modules[Core][poll][enable]'] = 'poll';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
 
     // Now enable the comment module.
     $edit = array();
     $edit['modules[Core][comment][enable]'] = 'comment';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
+
     $this->resetAll();
     $this->assertTrue(module_exists('comment'), 'Comment module enabled.');
 
diff --git a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
index 573ce93..813a3a3 100644
--- a/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
+++ b/core/modules/edit/lib/Drupal/edit/Tests/EditTestBase.php
@@ -20,7 +20,7 @@ class EditTestBase extends DrupalUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('system', 'entity', 'field_test', 'field', 'number', 'text', 'edit', 'edit_test');
+  public static $modules = array('system', 'entity', 'number', 'text', 'edit', 'edit_test');
 
   /**
    * Sets the default field storage backend for fields created during tests.
diff --git a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
index fcfd62a..62937bb 100644
--- a/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
+++ b/core/modules/email/lib/Drupal/email/Tests/EmailItemTest.php
@@ -17,13 +17,6 @@
  */
 class EmailItemTest extends DrupalUnitTestBase {
 
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('email', 'entity_test');
-
   public static function getInfo() {
     return array(
       'name' => 'E-mail field item',
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
index 8b0ce69..93e10c7 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
@@ -14,6 +14,7 @@
  */
 class EntityDisplayTest extends DrupalUnitTestBase {
 
+  public static $install = array('system', 'entity', 'field');
   public static $modules = array('entity_test');
 
   public static function getInfo() {
@@ -24,12 +25,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system', 'entity', 'field'));
-  }
-
   /**
    * Tests basic CRUD operations on EntityDisplay objects.
    */
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index df37a5b..662c866 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -504,7 +504,7 @@ function field_modules_disabled($modules) {
 function field_sync_field_status() {
   // Refresh the 'active' and 'storage_active' columns according to the current
   // set of enabled modules.
-  $modules = module_list();
+  $modules = array_keys(drupal_container()->get('module_handler')->getModuleList());
   foreach ($modules as $module_name) {
     field_associate_fields($module_name);
   }
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
index 7b0bef7..4390600 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
@@ -108,7 +108,7 @@ function testEnableForumField() {
     $edit['modules[Core][forum][enable]'] = FALSE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
-    system_list_reset();
+    $this->rebuildContainer();
     $this->assertFalse(module_exists('forum'), 'Forum module is not enabled.');
 
     // Attempt to re-enable the Forum module and ensure it does not try to
@@ -117,7 +117,7 @@ function testEnableForumField() {
     $edit['modules[Core][forum][enable]'] = 'forum';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
-    system_list_reset();
+    $this->rebuildContainer();
     $this->assertTrue(module_exists('forum'), 'Forum module is enabled.');
   }
 
diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php
index c4422aa..b22eb63 100644
--- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php
+++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/RdfSchemaSerializationTest.php
@@ -15,6 +15,8 @@
 
 class RdfSchemaSerializationTest extends DrupalUnitTestBase {
 
+  public static $install = array('system');
+
   public static function getInfo() {
     return array(
       'name' => 'Site schema JSON-LD serialization',
@@ -27,9 +29,6 @@ public static function getInfo() {
    * Tests the serialization of site schemas.
    */
   function testSchemaSerialization() {
-    // In order to use url() the url_alias table must be installed, so system
-    // is enabled.
-    $this->enableModules(array('system'));
 
     $entity_type = $bundle = 'entity_test';
 
diff --git a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
index 436b371..38096db 100644
--- a/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
+++ b/core/modules/language/lib/Drupal/language/Tests/LanguageNegotiationInfoTest.php
@@ -139,7 +139,7 @@ protected function languageNegotiationUpdate($op = 'enable') {
       $function = "module_{$op}";
       $function($modules);
       // Reset hook implementation cache.
-      module_implements_reset();
+      drupal_container()->get('module_handler')->resetImplementations();
     }
 
     drupal_static_reset('language_types_info');
diff --git a/core/modules/language/lib/Drupal/language/Tests/Views/LanguageTestBase.php b/core/modules/language/lib/Drupal/language/Tests/Views/LanguageTestBase.php
index e84844b..002072e 100644
--- a/core/modules/language/lib/Drupal/language/Tests/Views/LanguageTestBase.php
+++ b/core/modules/language/lib/Drupal/language/Tests/Views/LanguageTestBase.php
@@ -15,11 +15,11 @@
  */
 abstract class LanguageTestBase extends ViewUnitTestBase {
 
+  public static $install = array('system', 'language');
+
   protected function setUp() {
     parent::setUp();
 
-    $this->enableModules(array('system', 'language'));
-
     // Create another language beside English.
     $language = new Language(array('langcode' => 'xx-lolspeak', 'name' => 'Lolspeak'));
     language_save($language);
diff --git a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
index a6c4ea9..1efbc10 100644
--- a/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
+++ b/core/modules/layout/lib/Drupal/layout/Plugin/Derivative/Layout.php
@@ -10,6 +10,7 @@
 use DirectoryIterator;
 use Drupal\Component\Plugin\Derivative\DerivativeInterface;
 use Drupal\Core\Config\FileStorage;
+use Drupal\Core\ModuleHandlerInterface;
 
 /**
  * Layout plugin derivative definition.
@@ -58,11 +59,13 @@ public function getDerivativeDefinitions(array $base_plugin_definition) {
     $available_layout_providers = array();
 
     // Add all modules as possible layout providers.
-    foreach (module_list() as $module) {
+    // @todo Change this class so that it gets the extension handler injected
+    //   into it.
+    foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) {
       $available_layout_providers[$module] = array(
         'type' => 'module',
         'provider' => $module,
-        'dir' => drupal_get_path('module', $module),
+        'dir' => dirname($filename),
       );
     }
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
index b09df75..aa02cb7 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
@@ -50,18 +50,6 @@
    */
   public static $modules = array();
 
-  /**
-   * Fixed module list being used by this test.
-   *
-   * @var array
-   *   An associative array containing the required data for the $fixed_list
-   *   argument of module_list().
-   *
-   * @see UnitTestBase::setUp()
-   * @see UnitTestBase::enableModules()
-   */
-  private $moduleList = array();
-
   private $moduleFiles;
   private $themeFiles;
   private $themeData;
@@ -104,17 +92,27 @@ protected function setUp() {
     $this->kernel = new DrupalKernel('testing', TRUE, drupal_classloader(), FALSE);
     $this->kernel->boot();
 
-    // Ensure that the module list is initially empty.
-    $this->moduleList = array();
     // Collect and set a fixed module list.
     $class = get_class($this);
     $modules = array();
+    $install = array();
     while ($class) {
+      if (property_exists($class, 'install')) {
+        $install = array_merge($install, $class::$install);
+      }
       if (property_exists($class, 'modules')) {
         $modules = array_merge($modules, $class::$modules);
       }
       $class = get_parent_class($class);
     }
+    $system = array_search('system', $install);
+    if ($system !== FALSE) {
+      unset($install[$system]);
+      array_unshift($install, 'system');
+    }
+    if ($install) {
+      $this->enableModules($install);
+    }
     $this->enableModules($modules, FALSE);
   }
 
@@ -199,6 +197,9 @@ protected function installSchema($module, $table) {
    * enables the new modules in the system.module configuration only, but that
    * has no effect, since we are operating with a fixed module list.
    *
+   * Typically, the $modules static property should be used instead.
+   * Particularly, 'system' must not be passed to this function manually.
+   *
    * @param array $modules
    *   A list of modules to enable. Dependencies are not resolved; i.e.,
    *   multiple modules have to be specified with dependent modules first.
@@ -211,23 +212,18 @@ protected function installSchema($module, $table) {
    *   implementation that is able to manage a fixed module list.
    */
   protected function enableModules(array $modules, $install = TRUE) {
-    // Set the modules in the fixed module_list().
-    $new_enabled = array();
+    // Explicitly set the list of modules in the extension handler.
+    $enabled = $this->container->get('module_handler')->getModuleList();
     foreach ($modules as $module) {
-      $this->moduleList[$module]['filename'] = drupal_get_filename('module', $module);
-      $new_enabled[$module] = dirname($this->moduleList[$module]['filename']);
-      module_list(NULL, $this->moduleList);
-
+      $enabled[$module] = drupal_get_filename('module', $module);
       // Call module_enable() to enable (install) the new module.
       if ($install) {
         module_enable(array($module), FALSE);
       }
+      $this->container->get('module_handler')->setModuleList($enabled);
     }
-    // Otherwise, only ensure that the new modules are loaded.
-    if (!$install) {
-      module_load_all(FALSE, TRUE);
-      module_implements_reset();
-    }
+    $this->container->get('module_handler')->resetImplementations();
+    $this->container->get('module_handler')->reload();
   }
 
 }
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index e8068fa..fd4a8b9 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -1033,10 +1033,6 @@ protected function tearDown() {
       drupal_valid_test_ua($this->originalPrefix);
     }
 
-    // Reset module list and module load status.
-    module_list_reset();
-    module_load_all(FALSE, TRUE);
-
     // Restore original shutdown callbacks.
     $callbacks = &drupal_register_shutdown_function();
     $callbacks = $this->originalShutdownCallbacks;
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
index 5813ffd..75c016e 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
@@ -39,7 +39,7 @@ function testSetUp() {
     // Verify that specified $modules have been loaded.
     $this->assertTrue(function_exists('entity_test_permission'), "$module.module was loaded.");
     // Verify that there is a fixed module list.
-    $this->assertIdentical(module_list(), array($module => $module));
+    $this->assertIdentical(array_keys(drupal_container()->get('module_handler')->getModuleList()), array($module));
     $this->assertIdentical(module_implements('permission'), array($module));
 
     // Verify that no modules have been installed.
@@ -54,9 +54,9 @@ function testEnableModulesLoad() {
 
     // Verify that the module does not exist yet.
     $this->assertFalse(module_exists($module), "$module module not found.");
-    $list = module_list();
-    $this->assertFalse(in_array($module, $list), "$module module in module_list() not found.");
-    $list = module_list('permission');
+    $list = array_keys(drupal_container()->get('module_handler')->getModuleList());
+    $this->assertFalse(in_array($module, $list), "$module module not found in the extension handler's module list.");
+    $list = module_implements('permission');
     $this->assertFalse(in_array($module, $list), "{$module}_permission() in module_implements() not found.");
 
     // Enable the module.
@@ -64,9 +64,9 @@ function testEnableModulesLoad() {
 
     // Verify that the module exists.
     $this->assertTrue(module_exists($module), "$module module found.");
-    $list = module_list();
-    $this->assertTrue(in_array($module, $list), "$module module in module_list() found.");
-    $list = module_list('permission');
+    $list = array_keys(drupal_container()->get('module_handler')->getModuleList());
+    $this->assertTrue(in_array($module, $list), "$module module found in the extension handler's module list.");
+    $list = module_implements('permission');
     $this->assertTrue(in_array($module, $list), "{$module}_permission() in module_implements() found.");
   }
 
@@ -83,9 +83,9 @@ function testEnableModulesInstall() {
 
     // Verify that the module does not exist yet.
     $this->assertFalse(module_exists($module), "$module module not found.");
-    $list = module_list();
-    $this->assertFalse(in_array($module, $list), "$module module in module_list() not found.");
-    $list = module_list('permission');
+    $list = array_keys(drupal_container()->get('module_handler')->getModuleList());
+    $this->assertFalse(in_array($module, $list), "$module module not found in the extension handler's module list.");
+    $list = module_implements('permission');
     $this->assertFalse(in_array($module, $list), "{$module}_permission() in module_implements() not found.");
 
     $this->assertFalse(db_table_exists($table), "'$table' database table not found.");
@@ -97,9 +97,9 @@ function testEnableModulesInstall() {
 
     // Verify that the enabled module exists.
     $this->assertTrue(module_exists($module), "$module module found.");
-    $list = module_list();
-    $this->assertTrue(in_array($module, $list), "$module module in module_list() found.");
-    $list = module_list('permission');
+    $list = array_keys(drupal_container()->get('module_handler')->getModuleList());
+    $this->assertTrue(in_array($module, $list), "$module module found in the extension handler's module list.");
+    $list = module_implements('permission');
     $this->assertTrue(in_array($module, $list), "{$module}_permission() in module_implements() found.");
 
     $this->assertTrue(db_table_exists($table), "'$table' database table found.");
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php
index 648aa42..d7bd225 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/UnitTestBase.php
@@ -56,9 +56,6 @@ protected function setUp() {
     $conf = array();
     drupal_static_reset();
 
-    // Enforce an empty module list.
-    module_list(NULL, array());
-
     $conf['file_public_path'] = $this->public_files_directory;
 
     // Change the database prefix.
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 85aba85..c47e10b 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -796,6 +796,7 @@ protected function setUp() {
     foreach ($variables as $name => $value) {
       $GLOBALS['conf'][$name] = $value;
     }
+
     // Execute the non-interactive installer.
     require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
     install_drupal($settings);
diff --git a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php
index f301257..18cc65e 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Cache/DatabaseBackendUnitTest.php
@@ -36,6 +36,9 @@ protected function createCacheBackend($bin) {
    * Installs system schema.
    */
   public function setUpCacheBackend() {
+    // Calling drupal_install_schema() entails a call to module_invoke, for which
+    // we need a ModuleHandler. Register one to the container.
+    $this->container->register('module_handler', 'Drupal\Core\ModuleHandler');
     drupal_install_schema('system');
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php b/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php
index 7821dbc..0ea4a99 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Database/RangeQueryTest.php
@@ -17,7 +17,7 @@ class RangeQueryTest extends DatabaseTestBase {
    *
    * @var array
    */
-  public static $modules = array('database_test');
+  public static $install = array('database_test');
 
   public static function getInfo() {
     return array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php
index 8fa84fe..1379382 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/DependencyTest.php
@@ -36,7 +36,7 @@ function testEnableWithoutDependency() {
 
     $this->drupalPost(NULL, NULL, t('Continue'));
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
-
+    $this->rebuildContainer();
     $this->assertModules(array('translation_entity', 'language'), TRUE);
 
     // Assert that the language tables were enabled.
@@ -65,6 +65,7 @@ function testMissingModules() {
     // Confirm.
     $this->drupalPost(NULL, NULL, t('Continue'));
 
+    $this->rebuildContainer();
     // Verify that the module has been disabled.
     $this->assertModules(array('system_dependencies_test'), FALSE);
   }
@@ -112,6 +113,7 @@ function testEnableRequirementsFailureDependency() {
     $edit['modules[Testing][requirements1_test][enable]'] = 'requirements1_test';
     $edit['modules[Testing][requirements2_test][enable]'] = 'requirements2_test';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
 
     // Makes sure the modules were NOT installed.
     $this->assertText(t('Requirements 1 Test failed requirements'), 'Modules status has been updated.');
@@ -154,6 +156,7 @@ function testModuleEnableOrder() {
     $edit['modules[Core][poll][enable]'] = 'poll';
     $edit['modules[Core][php][enable]'] = 'php';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertModules(array('forum', 'poll', 'php', 'comment', 'history', 'taxonomy', 'options'), TRUE);
 
     // Check the actual order which is saved by module_test_modules_enabled().
@@ -169,14 +172,17 @@ function testUninstallDependents() {
     $edit = array('modules[Core][forum][enable]' => 'forum');
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
     $this->drupalPost(NULL, array(), t('Continue'));
+    $this->rebuildContainer();
     $this->assertModules(array('forum'), TRUE);
 
     // Disable forum and comment. Both should now be installed but disabled.
     $edit = array('modules[Core][forum][enable]' => FALSE);
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertModules(array('forum'), FALSE);
     $edit = array('modules[Core][comment][enable]' => FALSE);
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertModules(array('comment'), FALSE);
 
     // Check that the taxonomy module cannot be uninstalled.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
index e8602f4..8ad23c4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/EnableDisableTest.php
@@ -43,7 +43,7 @@ function testEnableDisable() {
 
     // Remove already enabled modules (via installation profile).
     // @todo Remove this after removing all dependencies from Testing profile.
-    foreach (module_list() as $dependency) {
+    foreach ($this->container->get('module_handler')->getModuleList() as $dependency => $filename) {
       // Exclude required modules. Only installation profile "suggestions" can
       // be disabled and uninstalled.
       if (isset($modules[$dependency])) {
@@ -95,10 +95,12 @@ function testEnableDisable() {
         $package = $module->info['package'];
         $edit['modules[' . $package . '][' . $name . '][enable]'] = $name;
         $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+        $this->rebuildContainer();
         // Handle the case where modules were installed along with this one and
         // where we therefore hit a confirmation screen.
         if (count($modules_to_enable) > 1) {
           $this->drupalPost(NULL, array(), t('Continue'));
+          $this->rebuildContainer();
         }
         $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
 
@@ -169,6 +171,7 @@ function testEnableDisable() {
       $edit['modules[' . $module->info['package'] . '][' . $name . '][enable]'] = $name;
     }
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
   }
 
@@ -186,6 +189,7 @@ function assertSuccessfulDisableAndUninstall($module, $package = 'Core') {
     $edit = array();
     $edit['modules[' . $package . '][' . $module . '][enable]'] = FALSE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
     $this->assertModules(array($module), FALSE);
 
@@ -204,6 +208,7 @@ function assertSuccessfulDisableAndUninstall($module, $package = 'Core') {
     $edit['uninstall[' . $module . ']'] = $module;
     $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
     $this->drupalPost(NULL, NULL, t('Uninstall'));
+    $this->rebuildContainer();
     $this->assertText(t('The selected modules have been uninstalled.'), 'Modules status has been updated.');
     $this->assertModules(array($module), FALSE);
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php
index 85a4184..5ea5306 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleApiTest.php
@@ -25,7 +25,7 @@ public static function getInfo() {
   }
 
   /**
-   * The basic functionality of module_list().
+   * The basic functionality of retrieving enabled modules.
    */
   function testModuleList() {
     // Build a list of modules, sorted alphabetically.
@@ -36,8 +36,8 @@ function testModuleList() {
     $module_list[] = 'standard';
 
     sort($module_list);
-    // Compare this list to the one returned by module_list(). We expect them
-    // to match, since all default profile modules have a weight equal to 0
+    // Compare this list to the one returned by the extension handler. We expect
+    // them to match, since all default profile modules have a weight equal to 0
     // (except for block.module, which has a lower weight but comes first in
     // the alphabet anyway).
     $this->assertModuleList($module_list, t('Standard profile'));
@@ -50,8 +50,7 @@ function testModuleList() {
 
     // Try to mess with the module weights.
     module_set_weight('contact', 20);
-    // Reset the module list.
-    system_list_reset();
+
     // Move contact to the end of the array.
     unset($module_list[array_search('contact', $module_list)]);
     $module_list[] = 'contact';
@@ -59,33 +58,32 @@ function testModuleList() {
 
     // Test the fixed list feature.
     $fixed_list = array(
-      'system' => array('filename' => drupal_get_path('module', 'system')),
-      'menu' => array('filename' => drupal_get_path('module', 'menu')),
+      'system' => 'core/modules/system/system.module',
+      'menu' => 'core/modules/menu/menu.module',
     );
-    module_list(NULL, $fixed_list);
+    $this->container->get('module_handler')->setModuleList($fixed_list);
     $new_module_list = array_combine(array_keys($fixed_list), array_keys($fixed_list));
     $this->assertModuleList($new_module_list, t('When using a fixed list'));
 
-    // Reset the module list.
-    module_list_reset();
-    $this->assertModuleList($module_list, t('After reset'));
   }
 
   /**
-   * Assert that module_list() return the expected values.
+   * Assert that the extension handler returns the expected values.
    *
    * @param $expected_values
    *   The expected values, sorted by weight and module name.
    */
   protected function assertModuleList(Array $expected_values, $condition) {
-    $expected_values = array_combine($expected_values, $expected_values);
-    $this->assertEqual($expected_values, module_list(), format_string('@condition: module_list() returns correct results', array('@condition' => $condition)));
+    $expected_values = array_values(array_unique($expected_values));
+    $enabled_modules = array_keys($this->container->get('module_handler')->getModuleList());
+    $enabled_modules = sort($enabled_modules);
+    $this->assertEqual($expected_values, $enabled_modules, format_string('@condition: extension handler returns correct results', array('@condition' => $condition)));
   }
 
   /**
    * Test module_implements() caching.
    */
-  function testModuleImplements() {
+  function testgetImplementations() {
     // Clear the cache.
     cache('bootstrap')->delete('module_implements');
     $this->assertFalse(cache('bootstrap')->get('module_implements'), 'The module implements cache is empty.');
@@ -103,12 +101,11 @@ function testModuleImplements() {
     // already loaded when the cache is rebuilt.
     // For that activate the module_test which provides the file to load.
     module_enable(array('module_test'));
-
+    $module_handler = drupal_container()->get('module_handler');
+    $module_handler->loadAll();
     module_load_include('inc', 'module_test', 'module_test.file');
-    $modules = module_implements('test_hook');
-    $static = drupal_static('module_implements');
+    $modules = $module_handler->getImplementations('test_hook');
     $this->assertTrue(in_array('module_test', $modules), 'Hook found.');
-    $this->assertEqual($static['test_hook']['module_test'], 'file', 'Include file detected.');
   }
 
   /**
@@ -124,7 +121,7 @@ function testModuleInvoke() {
   /**
    * Test that module_invoke_all() can load a hook defined in hook_hook_info().
    */
-  function testModuleInvokeAll() {
+  function testinvokeAll() {
     module_enable(array('module_test'), FALSE);
     $this->resetAll();
     $this->drupalGet('module-test/hook-dynamic-loading-invoke-all');
@@ -134,10 +131,10 @@ function testModuleInvokeAll() {
   /**
    * Test that a menu item load function can invoke hooks defined in hook_hook_info().
    *
-   * We test this separately from testModuleInvokeAll(), because menu item load
+   * We test this separately from testinvokeAll(), because menu item load
    * functions execute early in the request handling.
    */
-  function testModuleInvokeAllDuringLoadFunction() {
+  function testinvokeAllDuringLoadFunction() {
     module_enable(array('module_test'), FALSE);
     $this->resetAll();
     $this->drupalGet('module-test/hook-dynamic-loading-invoke-all-during-load/module_test');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
index 916555d..a45a616 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Module/ModuleTestBase.php
@@ -144,7 +144,6 @@ function assertNoModuleConfig($module) {
    *   Expected module state.
    */
   function assertModules(array $modules, $enabled) {
-    system_list_reset();
     foreach ($modules as $module) {
       if ($enabled) {
         $message = 'Module "@module" is enabled.';
@@ -152,7 +151,7 @@ function assertModules(array $modules, $enabled) {
       else {
         $message = 'Module "@module" is not enabled.';
       }
-      $this->assertEqual(module_exists($module), $enabled, format_string($message, array('@module' => $module)));
+      $this->assertEqual($this->container->get('module_handler')->moduleExists($module), $enabled, format_string($message, array('@module' => $module)));
     }
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php
index 2de5ad3..d83bdc3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/MainContentFallbackTest.php
@@ -55,8 +55,8 @@ function testMainContentFallback() {
     // Disable the block module.
     $edit['modules[Core][block][enable]'] = FALSE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
-    system_list_reset();
     $this->assertFalse(module_exists('block'), 'Block module disabled.');
 
     // At this point, no region is filled and fallback should be triggered.
@@ -89,8 +89,8 @@ function testMainContentFallback() {
     $edit = array();
     $edit['modules[Core][block][enable]'] = 'block';
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
+    $this->rebuildContainer();
     $this->assertText(t('The configuration options have been saved.'), 'Modules status has been updated.');
-    system_list_reset();
     $this->assertTrue(module_exists('block'), 'Block module re-enabled.');
   }
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php
index 7ea187f..5ab43ca 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/RegistryTest.php
@@ -40,7 +40,7 @@ function testRaceCondition() {
 
     // Directly instantiate the theme registry, this will cause a base cache
     // entry to be written in __construct().
-    $registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE));
+    $registry = new ThemeRegistry($cid, 'cache', array('theme_registry' => TRUE), $this->container->get('module_handler')->isLoaded());
 
     $this->assertTrue(cache()->get($cid), 'Cache entry was created.');
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
index 5267300..6e9b383 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/ThemeTest.php
@@ -175,9 +175,19 @@ function testRegistryRebuild() {
     $this->assertIdentical(theme('theme_test_foo', array('foo' => 'a')), 'a', 'The theme registry contains theme_test_foo.');
 
     module_disable(array('theme_test'), FALSE);
+    // After enabling/disabling a module during a test, we need to rebuild the
+    // container and ensure the extension handler is loaded, otherwise theme()
+    // throws an exception.
+    $this->rebuildContainer();
+    $this->container->get('module_handler')->loadAll();
     $this->assertIdentical(theme('theme_test_foo', array('foo' => 'b')), '', 'The theme registry does not contain theme_test_foo, because the module is disabled.');
 
     module_enable(array('theme_test'), FALSE);
+    // After enabling/disabling a module during a test, we need to rebuild the
+    // container and ensure the extension handler is loaded, otherwise theme()
+    // throws an exception.
+    $this->rebuildContainer();
+    $this->container->get('module_handler')->loadAll();
     $this->assertIdentical(theme('theme_test_foo', array('foo' => 'c')), 'c', 'The theme registry contains theme_test_foo again after re-enabling the module.');
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php
index 8d4da51..499acf2 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/BareMinimalUpgradePathTest.php
@@ -82,7 +82,7 @@ public function testBasicMinimalUpgrade() {
     $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
 
     // Verify that all required modules are enabled.
-    $enabled = module_list();
+    $enabled = $this->container->get('module_handler')->getModuleList();
     $required = array_filter(system_rebuild_module_data(), function ($data) {
       return !empty($data->info['required']);
     });
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php
index c4c6f75..2e3c725 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/ModulesDisabledUpgradePathTest.php
@@ -37,7 +37,7 @@ public function testDisabledUpgrade() {
     $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
 
     // Get enabled modules.
-    $enabled = module_list();
+    $enabled = drupal_container()->get('module_handler')->getModuleList();
     // Get all available modules.
     $available = system_rebuild_module_data();
     // Filter out hidden test modules.
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
index 106d726..c4dda65 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -268,9 +268,8 @@ protected function performUpgrade($register_errors = TRUE) {
 
     // Reload module list for modules that are enabled in the test database
     // but not on the test client.
-    system_list_reset();
-    module_implements_reset();
-    module_load_all(FALSE, TRUE);
+    drupal_container()->get('module_handler')->resetImplementations();
+    drupal_container()->get('module_handler')->reload();
 
     // Rebuild the container and all caches.
     $this->rebuildContainer();
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index c3c2ce4..37a2bf2 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1204,7 +1204,7 @@ function system_modules_submit($form, &$form_state) {
 
   // Gets list of modules prior to install process, unsets $form_state['storage']
   // so we don't get redirected back to the confirmation form.
-  $pre_install_list = module_list();
+  $pre_install_list = drupal_container()->get('module_handler')->getModuleList();
   unset($form_state['storage']);
 
   // Reverse the 'enable' list, to order dependencies before dependents.
@@ -1216,7 +1216,7 @@ function system_modules_submit($form, &$form_state) {
 
   // Gets module list after install process, flushes caches and displays a
   // message if there are changes.
-  $post_install_list = module_list();
+  $post_install_list = drupal_container()->get('module_handler')->getModuleList();
   if ($pre_install_list != $post_install_list) {
     drupal_flush_all_caches();
     drupal_set_message(t('The configuration options have been saved.'));
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index ca5d6de..f8921be 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -400,7 +400,7 @@ function system_requirements($phase) {
     );
 
     // Check installed modules.
-    foreach (module_list() as $module) {
+    foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) {
       $updates = drupal_get_schema_versions($module);
       if ($updates !== FALSE) {
         $default = drupal_get_installed_schema_version($module);
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index cdf7b90..2be63d0 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -2775,7 +2775,7 @@ function system_get_info($type, $name = NULL) {
   $info = array();
   if ($type == 'module') {
     $data = system_rebuild_module_data();
-    foreach (module_list() as $module) {
+    foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) {
       $info[$module] = $data[$module]->info;
     }
   }
@@ -2918,7 +2918,7 @@ function system_rebuild_module_data() {
       $record->schema_version = SCHEMA_UNINSTALLED;
       $files[$module] = $record->filename;
     }
-    $modules = _module_build_dependencies($modules);
+    $modules = drupal_container()->get('module_handler')->buildModuleDependencies($modules);
     $modules_cache = $modules;
 
     // Store filenames to allow system_list() and drupal_get_filename() to
diff --git a/core/modules/update/lib/Drupal/update/Tests/UpdateUploadTest.php b/core/modules/update/lib/Drupal/update/Tests/UpdateUploadTest.php
index d3bcdb8..f785151 100644
--- a/core/modules/update/lib/Drupal/update/Tests/UpdateUploadTest.php
+++ b/core/modules/update/lib/Drupal/update/Tests/UpdateUploadTest.php
@@ -36,7 +36,7 @@ public function setUp() {
   /**
    * Tests upload and extraction of a module.
    */
-  public function testUploadModule() {
+  public function testUpload() {
     // Images are not valid archives, so get one and try to install it. We
     // need an extra variable to store the result of drupalGetTestFiles()
     // since reset() takes an argument by reference and passing in a constant
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/AreaTextTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/AreaTextTest.php
index 43b807e..59327cf 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/AreaTextTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/AreaTextTest.php
@@ -22,7 +22,7 @@ class AreaTextTest extends ViewUnitTestBase {
    * @var array
    */
   public static $testViews = array('test_view');
-
+  public static $install = array('system', 'filter');
   public static function getInfo() {
     return array(
       'name' => 'Area: Text',
@@ -31,13 +31,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-    $this->enableModules(array('filter'));
-  }
-
   public function testAreaText() {
     $view = views_get_view('test_view');
     $view->setDisplay();
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUrlTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUrlTest.php
index 530d53b..e98577f 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUrlTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FieldUrlTest.php
@@ -14,6 +14,8 @@
  */
 class FieldUrlTest extends ViewUnitTestBase {
 
+  public static $install = array('system');
+
   /**
    * Views used by this test.
    *
@@ -29,11 +31,6 @@ public static function getInfo() {
     );
   }
 
-  public function setup() {
-    parent::setup();
-    $this->enableModules(array('system'));
-  }
-
   function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['name']['field']['id'] = 'url';
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
index 05a42a4..96102ec 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterEqualityTest.php
@@ -20,7 +20,7 @@ class FilterEqualityTest extends ViewUnitTestBase {
    * @var array
    */
   public static $testViews = array('test_view');
-
+  public static $install = array('system', 'menu');
   protected $column_map = array(
     'views_test_data_name' => 'name',
   );
@@ -33,12 +33,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['name']['filter']['id'] = 'equality';
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
index 6b6a8e8..adf33ac 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterInOperatorTest.php
@@ -20,7 +20,7 @@ class FilterInOperatorTest extends ViewUnitTestBase {
    * @var array
    */
   public static $testViews = array('test_view');
-
+  public static $install = array('system', 'menu');
   protected $column_map = array(
     'views_test_data_name' => 'name',
     'views_test_data_age' => 'age',
@@ -34,12 +34,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['age']['filter']['id'] = 'in_operator';
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
index d497954..5985cd6 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterNumericTest.php
@@ -20,7 +20,7 @@ class FilterNumericTest extends ViewUnitTestBase {
    * @var array
    */
   public static $testViews = array('test_view');
-
+  public static $install = array('system', 'menu');
   protected $column_map = array(
     'views_test_data_name' => 'name',
     'views_test_data_age' => 'age',
@@ -34,12 +34,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['age']['filter']['allow empty'] = TRUE;
diff --git a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
index 65c71e5..e7479b7 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Handler/FilterStringTest.php
@@ -20,7 +20,7 @@ class FilterStringTest extends ViewUnitTestBase {
    * @var array
    */
   public static $testViews = array('test_view');
-
+  public static $install = array('system', 'menu');
   protected $column_map = array(
     'views_test_data_name' => 'name',
   );
@@ -33,12 +33,6 @@ public static function getInfo() {
     );
   }
 
-  protected function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   function viewsData() {
     $data = parent::viewsData();
     $data['views_test_data']['name']['filter']['allow empty'] = TRUE;
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleMappingTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleMappingTest.php
index c0db658..b837d58 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleMappingTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/StyleMappingTest.php
@@ -12,6 +12,8 @@
  */
 class StyleMappingTest extends StyleTestBase {
 
+  public static $install = array('system');
+
   /**
    * Views used by this test.
    *
@@ -27,12 +29,6 @@ public static function getInfo() {
     );
   }
 
-  public function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   /**
    * Verifies that the fields were mapped correctly.
    */
diff --git a/core/modules/views/lib/Drupal/views/Tests/TokenReplaceTest.php b/core/modules/views/lib/Drupal/views/Tests/TokenReplaceTest.php
index c3c24b1..b573145 100644
--- a/core/modules/views/lib/Drupal/views/Tests/TokenReplaceTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/TokenReplaceTest.php
@@ -12,6 +12,8 @@
  */
 class TokenReplaceTest extends ViewUnitTestBase {
 
+  public static $install = array('system');
+
   /**
    * Views used by this test.
    *
@@ -27,12 +29,6 @@ public static function getInfo() {
     );
   }
 
-  public function setUp() {
-    parent::setUp();
-
-    $this->enableModules(array('system'));
-  }
-
   /**
    * Tests core token replacements generated from a view.
    */
diff --git a/core/scripts/dump-database-d6.sh b/core/scripts/dump-database-d6.sh
index d39bb43..106568d 100644
--- a/core/scripts/dump-database-d6.sh
+++ b/core/scripts/dump-database-d6.sh
@@ -44,7 +44,7 @@
 
 ENDOFHEADER;
 
-foreach (module_list() as $module) {
+foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) {
   $output .= " *  - $module\n";
 }
 $output .= " */\n\n";
diff --git a/core/scripts/dump-database-d7.sh b/core/scripts/dump-database-d7.sh
index 3440fa2..3b8597d 100644
--- a/core/scripts/dump-database-d7.sh
+++ b/core/scripts/dump-database-d7.sh
@@ -45,7 +45,7 @@
 
 ENDOFHEADER;
 
-foreach (module_list() as $module) {
+foreach (drupal_container()->get('module_handler')->getModuleList() as $module => $filename) {
   $output .= " *  - $module\n";
 }
 $output .= " */\n\n";
diff --git a/core/update.php b/core/update.php
index 17b44fd..69f058a 100644
--- a/core/update.php
+++ b/core/update.php
@@ -435,13 +435,14 @@ function update_check_requirements($skip_warnings = FALSE) {
 
   // Load module basics.
   include_once DRUPAL_ROOT . '/core/includes/module.inc';
-  $module_list['system']['filename'] = 'core/modules/system/system.module';
-  module_list(NULL, $module_list);
-  drupal_load('module', 'system');
+  $module_list['system'] = 'core/modules/system/system.module';
+  $module_handler = drupal_container()->get('module_handler');
+  $module_handler->setModuleList($module_list);
+  $module_handler->load('system');
 
-  // Reset the module_implements() cache so that any new hook implementations
+  // Reset the module implementations cache so that any new hook implementations
   // in updated code are picked up.
-  module_implements_reset();
+  $module_handler->resetImplementations();
 
   // Set up $language, since the installer components require it.
   drupal_language_initialize();
