diff --git a/core/includes/module.inc b/core/includes/module.inc
index f40161d..0f0f705 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -83,14 +83,7 @@ function module_list($type = 'module_enabled', array $fixed_list = NULL) {
     $list = $module_list;
   }
   elseif (!isset($module_list)) {
-    if ($type == 'bootstrap') {
-      $list = system_list('bootstrap');
-    }
-    else {
-      // Not using drupal_map_assoc() here as that requires common.inc.
-      $list = array_keys(system_list($type));
-      $list = (!empty($list) ? array_combine($list, $list) : array());
-    }
+    $list = system_list($type);
   }
   return $list;
 }
@@ -115,9 +108,9 @@ function module_list_reset() {
  *
  * @return
  *   An associative array of modules or themes, keyed by name. For $type
- *   'bootstrap', the array values equal the keys. For $type 'module_enabled'
- *   or 'theme', the array values are objects representing the respective
- *   database row, with the 'info' property already unserialized.
+ *   'bootstrap' and 'module_enabled', the array values equal the keys.
+ *   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()
@@ -168,13 +161,13 @@ function system_list($type) {
       // consistent with the one used in module_implements().
       $result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC");
       foreach ($result as $record) {
-        $record->info = unserialize($record->info);
         // Build a list of all enabled modules.
         if ($record->type == 'module') {
-          $lists['module_enabled'][$record->name] = $record;
+          $lists['module_enabled'][$record->name] = $record->name;
         }
         // Build a list of themes.
         if ($record->type == 'theme') {
+          $record->info = unserialize($record->info);
           $lists['theme'][$record->name] = $record;
         }
         // Build a list of filenames so drupal_get_filename can use it.
@@ -227,6 +220,7 @@ function system_list_reset() {
   drupal_static_reset('system_rebuild_module_data');
   drupal_static_reset('list_themes');
   cache('bootstrap')->deleteMultiple(array('bootstrap_modules', 'system_list'));
+  cache()->delete('system_info');
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Utility/ModuleInfo.php b/core/lib/Drupal/Core/Utility/ModuleInfo.php
new file mode 100644
index 0000000..e5391f2
--- /dev/null
+++ b/core/lib/Drupal/Core/Utility/ModuleInfo.php
@@ -0,0 +1,41 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Utility\ModuleInfo.
+ */
+
+namespace Drupal\Core\Utility;
+
+use Drupal\Core\Utility\CacheArray;
+
+/**
+ * Extends CacheArray to lazy load .info properties for modules.
+ *
+ * Use system_get_module_info() rather than instantiating this class directly.
+ */
+class ModuleInfo extends CacheArray {
+
+  /**
+   * The full module info array as returned by system_get_info().
+   */
+  protected $info;
+
+  /**
+   * Overrides DrupalCacheArray::resolveCacheMiss().
+   */
+  function resolveCacheMiss($offset) {
+    $data = array();
+    if (!isset($this->info)) {
+      $this->info = system_get_info('module');
+    }
+    foreach ($this->info as $module => $info) {
+      if (isset($info[$offset])) {
+        $data[$module] = $info[$offset];
+      }
+    }
+    $this->storage[$offset] = $data;
+    $this->persist($offset);
+    return $data;
+  }
+}
diff --git a/core/modules/search/search.admin.inc b/core/modules/search/search.admin.inc
index bef8fd9..7acb65d 100644
--- a/core/modules/search/search.admin.inc
+++ b/core/modules/search/search.admin.inc
@@ -29,13 +29,9 @@ function search_reindex_confirm_submit(&$form, &$form_state) {
  * Helper function to get real module names.
  */
 function _search_get_module_names() {
-
   $search_info = search_get_info(TRUE);
-  $system_info = system_get_info('module');
-  $names = array();
-  foreach ($search_info as $module => $info) {
-    $names[$module] = $system_info[$module]['name'];
-  }
+  $names = system_get_module_info('name');
+  $names = array_intersect_key($names, $search_info);
   asort($names, SORT_STRING);
   return $names;
 }
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 48a25ec..160ef4c 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -5,6 +5,7 @@
  * Configuration system that lets administrators modify the workings of the site.
  */
 
+use Drupal\Core\Utility\ModuleInfo;
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
 
@@ -2181,18 +2182,16 @@ function system_get_localized_date_format($languages) {
  * Adds CSS and JavaScript files declared in module .info files.
  */
 function system_add_module_assets() {
-  foreach (system_get_info('module') as $module => $info) {
-    if (!empty($info['stylesheets'])) {
-      foreach ($info['stylesheets'] as $media => $stylesheets) {
-        foreach ($stylesheets as $stylesheet) {
-          drupal_add_css($stylesheet, array('every_page' => TRUE, 'media' => $media));
-        }
+  foreach (system_get_module_info('stylesheets') as $module => $value) {
+    foreach ($value as $media => $stylesheets) {
+      foreach ($stylesheets as $stylesheet) {
+        drupal_add_css($stylesheet, array('every_page' => TRUE, 'media' => $media));
       }
     }
-    if (!empty($info['scripts'])) {
-      foreach ($info['scripts'] as $script) {
-        drupal_add_js($script, array('every_page' => TRUE));
-      }
+  }
+  foreach (system_get_module_info('scripts') as $module => $scripts) {
+    foreach ($scripts as $script) {
+      drupal_add_js($script, array('every_page' => TRUE));
     }
   }
 }
@@ -2598,12 +2597,17 @@ function system_update_files_database(&$files, $type) {
 function system_get_info($type, $name = NULL) {
   $info = array();
   if ($type == 'module') {
-    $type = 'module_enabled';
+    $result = db_query('SELECT name, info FROM {system} WHERE type = :type AND status = 1', array(':type' => 'module'));
+    foreach ($result as $record) {
+      $info[$record->name] = unserialize($record->info);
+    }
   }
-  $list = system_list($type);
-  foreach ($list as $shortname => $item) {
-    if (!empty($item->status)) {
-      $info[$shortname] = $item->info;
+  else {
+    $list = system_list($type);
+    foreach ($list as $shortname => $item) {
+      if (!empty($item->status)) {
+        $info[$shortname] = $item->info;
+      }
     }
   }
   if (isset($name)) {
@@ -2613,6 +2617,27 @@ function system_get_info($type, $name = NULL) {
 }
 
 /**
+ * Return .info data for modules.
+ *
+ * @param string $property
+ *   The .info property to retrieve.
+ *
+ * @return array
+ *   An array keyed by module name, with the .info file property as values.
+ *   Only modules with the property specified in their .info file will be
+ *   returned.
+ *
+ * @see Drupal\Core\Utility\ModuleInfo
+ */
+function system_get_module_info($property) {
+  static $info;
+  if (!isset($info)) {
+    $info = new ModuleInfo('system_info', 'cache');
+  }
+  return $info[$property];
+}
+
+/**
  * Helper function to scan and collect module .info data.
  *
  * @return
