Index: includes/bootstrap.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/bootstrap.inc,v
retrieving revision 1.242
diff -u -p -r1.242 bootstrap.inc
--- includes/bootstrap.inc	25 Oct 2008 01:13:40 -0000	1.242
+++ includes/bootstrap.inc	25 Oct 2008 11:26:36 -0000
@@ -1406,18 +1406,7 @@ function drupal_function_exists($functio
     return TRUE;
   }
 
-  $file = db_query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array(
-      ':name' => $function,
-      ':type' => 'function',
-    ))
-    ->fetchField();
-  if ($file) {
-    require_once DRUPAL_ROOT . '/' . $file;
-    $checked[$function] = function_exists($function);
-    if ($checked[$function]) {
-      registry_mark_code('function', $function);
-    }
-  }
+  $checked[$function] = _registry_check_code('function', $function);
 
   return $checked[$function];
 }
@@ -1455,7 +1444,7 @@ function drupal_autoload_class($class) {
 }
 
 /**
- * Helper for registry_check_{interface, class}.
+ * Helper to check for a resource in the registry.
  */
 function _registry_check_code($type, $name) {
   $file = db_query("SELECT filename FROM {registry} WHERE name = :name AND type = :type", array(
@@ -1468,6 +1457,7 @@ function _registry_check_code($type, $na
     registry_mark_code($type, $name);
     return TRUE;
   }
+  return FALSE;
 }
 
 /**
@@ -1509,31 +1499,6 @@ function registry_rebuild() {
 }
 
 /**
- * Save hook implementations cache.
- *
- * @param $hook
- *   Array with the hook name and list of modules that implement it.
- * @param $write_to_persistent_cache
- *   Whether to write to the persistent cache.
- */
-function registry_cache_hook_implementations($hook, $write_to_persistent_cache = FALSE) {
-  static $implementations;
-
-  if ($hook) {
-    // Newer is always better, so overwrite anything that's come before.
-    $implementations[$hook['hook']] = $hook['modules'];
-  }
-
-  if ($write_to_persistent_cache === TRUE) {
-    // Only write this to cache if the implementations data we are going to cache
-    // is different to what we loaded earlier in the request.
-    if ($implementations != module_implements()) {
-      cache_set('hooks', $implementations, 'cache_registry');
-    }
-  }
-}
-
-/**
  * Save the files required by the registry for this path.
  */
 function registry_cache_path_files() {
Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.810
diff -u -p -r1.810 common.inc
--- includes/common.inc	22 Oct 2008 19:39:36 -0000	1.810
+++ includes/common.inc	25 Oct 2008 11:26:38 -0000
@@ -1598,7 +1598,7 @@ function drupal_page_footer() {
 
   module_invoke_all('exit');
 
-  registry_cache_hook_implementations(FALSE, TRUE);
+  module_implements(MODULE_IMPLEMENTS_WRITE_CACHE);
   registry_cache_path_files();
 }
 
@@ -2629,8 +2629,6 @@ function _drupal_bootstrap_full() {
   fix_gpc_magic();
   // Load all enabled modules
   module_load_all();
-  // Rebuild the module hook cache
-  module_implements('', NULL, TRUE);
 
   // Let all modules take action before menu system handles the request
   // We do not want this while running update.php.
Index: includes/menu.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/menu.inc,v
retrieving revision 1.298
diff -u -p -r1.298 menu.inc
--- includes/menu.inc	19 Oct 2008 21:15:58 -0000	1.298
+++ includes/menu.inc	25 Oct 2008 11:26:39 -0000
@@ -1728,7 +1728,7 @@ function menu_router_build($reset = FALS
       // We need to manually call each module so that we can know which module
       // a given item came from.
       $callbacks = array();
-      foreach (module_implements('menu', NULL, TRUE) as $module) {
+      foreach (module_implements('menu', TRUE) as $module) {
         $router_items = call_user_func($module . '_menu');
         if (isset($router_items) && is_array($router_items)) {
           foreach (array_keys($router_items) as $path) {
Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.131
diff -u -p -r1.131 module.inc
--- includes/module.inc	12 Oct 2008 04:30:05 -0000	1.131
+++ includes/module.inc	25 Oct 2008 11:26:39 -0000
@@ -7,6 +7,17 @@
  */
 
 /**
+ * Pass this to module_implements when its cache needs to be written.
+ */
+define('MODULE_IMPLEMENTS_WRITE_CACHE', -1);
+
+/**
+ * Pass this to module_implements when its cache needs to be cleared.
+ */
+define('MODULE_IMPLEMENTS_CLEAR_CACHE', -2);
+
+
+/**
  * Load all the modules that have been enabled in the system table.
  */
 function module_load_all() {
@@ -391,48 +402,98 @@ function module_hook($module, $hook) {
  * Determine which modules are implementing a hook.
  *
  * @param $hook
- *   The name of the hook (e.g. "help" or "menu").
+ *   The name of the hook (e.g. "help" or "menu"). Special cases:
+ *     MODULE_IMPLEMENTS_CLEAR_CACHE: Force the stored list of hook
+ *     implementations to be regenerated (such as after enabling a new module,
+ *     before processing hook_enable).
+ *     MODULE_IMPLEMENTS_WRITE_CACHE: Write the stored list of hook
+ *     implementations into the cache_registry table.
  * @param $sort
- *   By default, modules are ordered by weight and filename, settings this option
- *   to TRUE, module list will be ordered by module name.
- * @param $refresh
- *   For internal use only: Whether to force the stored list of hook
- *   implementations to be regenerated (such as after enabling a new module,
- *   before processing hook_enable).  Note that if $refresh is TRUE this function
- *   will always return NULL.
+ *   By default, modules are ordered by weight and filename.  By setting this
+ *   option to TRUE, modules will be ordered by module name.
  * @return
  *   An array with the names of the modules which are implementing this hook.
- *   If $hook is NULL then it will return the implementation cache.
+ *   All enabled modules are taken into consideration and the files containing
+ *   the implementations are loaded as necessary.
  */
-function module_implements($hook = NULL, $sort = FALSE, $refresh = FALSE) {
-  static $implementations = array();
+function module_implements($hook, $sort = FALSE) {
+  static $implementations = array(), $sorted_implementations = array(), $loaded = array(), $cached_hooks = 0;
 
-  if (!isset($hook)) {
-    return $implementations;
+  if (defined('MAINTENANCE_MODE')) {
+    return _module_implements_maintenance($hook, $sort);
   }
-  if ($refresh) {
+  if ($hook === MODULE_IMPLEMENTS_CLEAR_CACHE) {
     $implementations = array();
-  }
-  if (!defined('MAINTENANCE_MODE') && empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) {
-    $implementations = $cache->data;
-  }
-
-  if ($hook) {
+    $sorted_implementations = array();
+    $loaded = array();
+    $cached_hooks = 0;
+    cache_clear_all('hooks', 'cache_registry');
+    return;
+  }
+  if ($hook === MODULE_IMPLEMENTS_WRITE_CACHE) {
+    // Only write this to cache if we loaded new implementations.
+    if (count($implementations) > $cached_hooks) {
+      cache_set('hooks', $implementations, 'cache_registry');
+    }
+    return;
+  }
+
+  if (!isset($loaded[$hook])) {
+    if (empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) {
+      $implementations = $cache->data;
+      $cached_hooks = count($implementations);
+    }
     if (!isset($implementations[$hook])) {
-      $implementations[$hook] = array();
-      foreach (module_list() as $module) {
-        if (module_hook($module, $hook)) {
-          $implementations[$hook][] = $module;
-        }
+      $implementations[$hook] = db_query("SELECT module FROM {registry} WHERE type = 'function' AND suffix = :hook ORDER BY weight, module", array(':hook' => $hook))->fetchCol();
+    }
+    foreach ($implementations[$hook] as $module) {
+      $function = $module . '_' . $hook;
+      if (!function_exists($function)) {
+        drupal_function_exists($function);
       }
     }
-    registry_cache_hook_implementations(array('hook' => $hook, 'modules' => $implementations[$hook]));
+    $loaded[$hook] = TRUE;
+  }
 
+  if ($sort) {
+    if (!isset($sorted_implementations[$hook])) {
+      $sorted_implementations[$hook] = $implementations[$hook];
+      sort($sorted_implementations[$hook]);
+    }
+    return $sorted_implementations[$hook];
+  }
+  else {
     return $implementations[$hook];
   }
 }
 
 /**
+ * This is the maintenance version of module_implements.
+ *
+ * @param $hook
+ *   The name of the hook (e.g. "help" or "menu").
+ * @param $sort
+ *   By default, modules are ordered by weight and filename, settings this
+ *   option to TRUE, module list will be ordered by module name.
+ * @return
+ *   An array with the names of the modules which are implementing this hook.
+ *   Only enabled and already loaded modules are taken into consideration.
+ */
+function _module_implements_maintenance($hook, $sort = FALSE) {
+  $implementations = array();
+  foreach (module_list() as $module) {
+    $function = $module . '_' . $hook;
+    if (function_exists($function)) {
+      $implementations[] = $module;
+    }
+    if ($sort) {
+      sort($implementations);
+    }
+  }
+  return $implementations;
+}
+
+/**
  * Invoke a hook in a particular module.
  *
  * @param $module
Index: includes/registry.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/registry.inc,v
retrieving revision 1.6
diff -u -p -r1.6 registry.inc
--- includes/registry.inc	11 Oct 2008 19:23:36 -0000	1.6
+++ includes/registry.inc	25 Oct 2008 11:26:39 -0000
@@ -45,12 +45,12 @@ function _registry_rebuild() {
     if ($module->status) {
       $dir = dirname($module->filename);
       foreach ($module->info['files'] as $file) {
-        $files["$dir/$file"] = array();
+        $files["$dir/$file"] = array('module' => $module->name, 'weight' => $module->weight);
       }
     }
   }
   foreach (file_scan_directory('includes', '/\.inc$/') as $filename => $file) {
-    $files["$filename"] = array();
+    $files["$filename"] = array('module' => '', 'weight' => 0);
   }
 
   foreach (registry_get_parsed_files() as $filename => $file) {
@@ -71,6 +71,7 @@ function _registry_rebuild() {
   }
   _registry_parse_files($files);
 
+  module_implements(MODULE_IMPLEMENTS_CLEAR_CACHE);
   cache_clear_all('*', 'cache_registry', TRUE);
 }
 
@@ -99,7 +100,7 @@ function _registry_parse_files($files) {
     if ($new_file || $md5 != $file['md5']) {
       // We update the md5 after we've saved the files resources rather than here, so if we
       // don't make it through this rebuild, the next run will reparse the file.
-      _registry_parse_file($filename, $contents);
+      _registry_parse_file($filename, $contents, $file['module'], $file['weight']);
       $file['md5'] = $md5;
       db_merge('registry_file')
         ->key(array('filename' => $filename))
@@ -113,11 +114,15 @@ function _registry_parse_files($files) {
  * Parse a file and save its function and class listings.
  *
  * @param $filename
- *  Name of the file we are going to parse.
+ *   Name of the file we are going to parse.
  * @param $contents
- *  Contents of the file we are going to parse as a string.
+ *   Contents of the file we are going to parse as a string.
+ * @param $module
+ *   (optional) Name of the module this file belongs to.
+ * @param $weight
+ *   (optional) Weight of the module.
  */
-function _registry_parse_file($filename, $contents) {
+function _registry_parse_file($filename, $contents, $module = '', $weight = 0) {
   static $map = array(T_FUNCTION => 'function', T_CLASS => 'class', T_INTERFACE => 'interface');
   // Delete registry entries for this file, so we can insert the new resources.
   db_delete('registry')
@@ -129,6 +134,19 @@ function _registry_parse_file($filename,
     if (is_array($token) && isset($map[$token[0]])) {
       $type = $map[$token[0]];
       if ($resource_name = _registry_get_resource_name($tokens, $type)) {
+        $suffix = '';
+        if ($type == 'function' && !empty($module)) {
+          $n = strlen($module);
+          if (substr($resource_name, 0, $n) == $module) {
+            $suffix = substr($resource_name, $n + 1);
+          }
+        }
+        $fields = array(
+          'filename' => $filename,
+          'module' => $module,
+          'suffix' => $suffix,
+          'weight' => $weight,
+        );
         // Because some systems, such as cache, currently use duplicate function
         // names in separate files an insert query cannot be used here as it
         // would cause a key constraint violation.  Instead we use a merge query.
@@ -140,7 +158,7 @@ function _registry_parse_file($filename,
         // function names have been purged from Drupal.
         db_merge('registry')
           ->key(array('name' => $resource_name, 'type' => $type))
-          ->fields(array('filename' => $filename))
+          ->fields($fields)
           ->execute();
 
         // We skip the body because classes may contain functions.
Index: modules/simpletest/tests/registry.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/registry.test,v
retrieving revision 1.2
diff -u -p -r1.2 registry.test
--- modules/simpletest/tests/registry.test	20 Sep 2008 20:22:24 -0000	1.2
+++ modules/simpletest/tests/registry.test	25 Oct 2008 11:26:40 -0000
@@ -122,11 +122,9 @@ class RegistryParseFilesTestCase extends
   function getFiles() {
     $files = array();
     foreach ($this->fileTypes as $fileType) {
+      $files[$this->$fileType->fileName] = array('module' => '', 'weight' => 0);
       if ($fileType == 'existing_changed') {
-        $files[$this->$fileType->fileName] = array('md5' => $this->$fileType->fakeMD5);
-      }
-      else {
-        $files[$this->$fileType->fileName] = array();
+        $files[$this->$fileType->fileName]['md5'] = $this->$fileType->fakeMD5;
       }
     }
     return $files;
Index: modules/system/system.install
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.install,v
retrieving revision 1.272
diff -u -p -r1.272 system.install
--- modules/system/system.install	13 Oct 2008 20:29:42 -0000	1.272
+++ modules/system/system.install	25 Oct 2008 11:26:41 -0000
@@ -1092,8 +1092,31 @@ function system_schema() {
         'length' => 255,
         'not null' => TRUE,
       ),
+      'module' => array(
+        'description' => t('Name of the module the file belongs to.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'suffix' => array(
+        'description' => t("The part of the name after the module. It'the name of the hook this function implements, if any."),
+        'type' => 'varchar',
+        'length' => 68,
+        'not null' => TRUE,
+        'default' => ''
+      ),
+      'weight' => array(
+        'description' => t("The order in which this module's hooks should be invoked relative to other modules. Equal-weighted modules are ordered by name."),
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+      ),
     ),
     'primary key' => array('name', 'type'),
+    'indexes' => array(
+      'hook' => array('type', 'suffix', 'weight', 'module'),
+    ),
   );
 
   $schema['registry_file'] = array(
@@ -2928,11 +2951,17 @@ function system_update_7006() {
   db_drop_field($ret, 'menu_router', 'file');
   $schema['registry'] = array(
     'fields' => array(
-      'name'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
-      'type'   => array('type' => 'varchar', 'length' => 9, 'not null' => TRUE, 'default' => ''),
-      'filename'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'name'     => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'type'     => array('type' => 'varchar', 'length' => 9,   'not null' => TRUE, 'default' => ''),
+      'filename' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'module'   => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => ''),
+      'suffix'   => array('type' => 'varchar', 'length' => 69, 'not null' => TRUE, 'default' => ''),
+      'weight'   => array('type' => 'int', 'not null' => TRUE, 'default' => 0),
     ),
     'primary key' => array('name', 'type'),
+    'indexes' => array(
+      'hook' => array('type', 'suffix', 'weight', 'module'),
+    ),
   );
   $schema['registry_file'] = array(
     'fields' => array(
@@ -3067,7 +3096,7 @@ function system_update_7011() {
     'permission' => 'bypass node access',
     ));
   }
-  $insert->execute();  
+  $insert->execute();
   return $ret;
 }
 
Index: modules/system/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system/system.module,v
retrieving revision 1.632
diff -u -p -r1.632 system.module
--- modules/system/system.module	14 Oct 2008 20:44:57 -0000	1.632
+++ modules/system/system.module	25 Oct 2008 11:26:42 -0000
@@ -935,7 +935,7 @@ function system_check_directory($form_el
  */
 function system_get_files_database(&$files, $type) {
   // Extract current files from database.
-  $result = db_query("SELECT filename, name, type, status, schema_version FROM {system} WHERE type = '%s'", $type);
+  $result = db_query("SELECT filename, name, type, status, schema_version, weight FROM {system} WHERE type = '%s'", $type);
   while ($file = db_fetch_object($result)) {
     if (isset($files[$file->name]) && is_object($files[$file->name])) {
       $file->old_filename = $file->filename;
