=== modified file 'includes/bootstrap.inc'
--- includes/bootstrap.inc	2008-09-08 21:24:30 +0000
+++ includes/bootstrap.inc	2008-09-11 02:37:21 +0000
@@ -820,7 +820,7 @@ function watchdog($type, $message, $vari
     );
 
     // Call the logging hooks to log/process the message
-    foreach (module_implements('watchdog', TRUE) as $module) {
+    foreach (module_implements('watchdog') as $module) {
       module_invoke($module, 'watchdog', $log_message);
     }
   }
@@ -1430,60 +1430,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() {
-  if ($used_code = registry_mark_code(NULL, NULL, TRUE)) {
-    $files = array();
-    $type_sql = array();
-    $params = array();
-    foreach ($used_code as $type => $names) {
-      $type_sql[] = "(name IN (" . db_placeholders($names, 'varchar') . ") AND type = '%s')";
-      $params = array_merge($params, $names);
-      $params[] = $type;
-    }
-    $res = db_query("SELECT DISTINCT filename FROM {registry} WHERE " . implode(' OR ', $type_sql), $params);
-    while ($row = db_fetch_object($res)) {
-      $files[] = $row->filename;
-    }
-    if ($files) {
-      sort($files);
-      // Only write this to cache if the file list we are going to cache
-      // is different to what we loaded earlier in the request.
-      if ($files != registry_load_path_files(TRUE)) {
-        $menu = menu_get_item();
-        cache_set('registry:' . $menu['path'], implode(';', $files), 'cache_registry');
-      }
-    }
-  }
-}
-
-/**
  * registry_load_path_files
  */
 function registry_load_path_files($return = FALSE) {

=== modified file 'includes/menu.inc'
--- includes/menu.inc	2008-09-05 08:24:08 +0000
+++ includes/menu.inc	2008-09-11 02:37:52 +0000
@@ -1726,7 +1726,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') as $module) {
         $router_items = call_user_func($module . '_menu');
         if (isset($router_items) && is_array($router_items)) {
           foreach (array_keys($router_items) as $path) {
@@ -1884,7 +1884,7 @@ function _menu_delete_item($item, $force
  *   - plid        The mlid of the parent.
  *   - router_path The path of the relevant router item.
  * @return
- *   The mlid of the saved menu link, or FALSE if the menu link could not be 
+ *   The mlid of the saved menu link, or FALSE if the menu link could not be
  *   saved.
  */
 function menu_link_save(&$item) {

=== modified file 'includes/module.inc'
--- includes/module.inc	2008-08-21 19:36:35 +0000
+++ includes/module.inc	2008-09-11 02:37:21 +0000
@@ -384,9 +384,6 @@ function module_hook($module, $hook) {
  *
  * @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.
  * @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,
@@ -396,32 +393,63 @@ function module_hook($module, $hook) {
  *   An array with the names of the modules which are implementing this hook.
  *   If $hook is NULL then it will return the implementation cache.
  */
-function module_implements($hook = NULL, $sort = FALSE, $refresh = FALSE) {
-  static $implementations = array();
+function module_implements($hook = NULL, $refresh = FALSE) {
+  static $implementations = array(), $loaded = array(), $cache;
 
-  if (!isset($hook)) {
+  if (defined('MAINTENANCE_MODE')) {
+    $implementations = array();
+    foreach (module_list() as $module) {
+      if (module_hook($module, $hook)) {
+        $implementations[] = $module;
+      }
+    }
     return $implementations;
   }
   if ($refresh) {
     $implementations = array();
+    $loaded = array();
+    cache_clear_all('hooks', 'cache_registry');
   }
-  if (!defined('MAINTENANCE_MODE') && empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) {
+  if (!$hook) {
+    // 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 (!$refresh && $cache && $implementations != $cache->data) {
+      cache_set('hooks', $implementations, 'cache_registry');
+    }
+    return;
+  }
+
+  if (empty($implementations) && ($cache = cache_get('hooks', 'cache_registry'))) {
     $implementations = $cache->data;
   }
 
-  if ($hook) {
+  if (empty($loaded[$hook])) {
+    if (isset($implementations[$hook])) {
+      $cached = TRUE;
+      // The implementations may not be in memory yet.
+      foreach ($implementations[$hook] as $module) {
+        $function = $module .'_'. $hook;
+        // If the implementations are already cached but there are functions
+        // to be looked up, then we discard the cache. The per router path
+        // caching will make this rare.
+        if (!function_exists($function)) {
+          unset($implementations[$hook]);
+          break;
+        }
+      }
+    }
     if (!isset($implementations[$hook])) {
       $implementations[$hook] = array();
-      foreach (module_list() as $module) {
-        if (module_hook($module, $hook)) {
-          $implementations[$hook][] = $module;
-        }
+      $result = db_query("SELECT name, filename, module FROM {registry} WHERE type = 'function' AND hook = '%s'", $hook);
+      while ($function = db_fetch_object($result)) {
+        $implementations[$hook][] = $function->module;
+        drupal_function_exists($function->name);
       }
     }
-    registry_cache_hook_implementations(array('hook' => $hook, 'modules' => $implementations[$hook]));
-
-    return $implementations[$hook];
+    $loaded[$hook] = TRUE;
   }
+
+  return $implementations[$hook];
 }
 
 /**

=== modified file 'includes/registry.inc'
--- includes/registry.inc	2008-08-21 19:36:35 +0000
+++ includes/registry.inc	2008-09-11 02:37:21 +0000
@@ -45,7 +45,7 @@ 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);
       }
     }
   }
@@ -67,6 +67,7 @@ function _registry_rebuild() {
   }
   _registry_parse_files($files);
 
+  module_implements('', FALSE, TRUE);
   cache_clear_all('*', 'cache_registry', TRUE);
 }
 
@@ -84,7 +85,7 @@ function registry_get_parsed_files() {
  * Parse all files that have changed since the registry was last built, and save their function and class listings.
  *
  * @param $files
- *  The list of files to check and parse.
+ *   The list of files to check and parse.
  */
 function _registry_parse_files($files) {
   $changed_files = array();
@@ -95,7 +96,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, $file, $contents);
       $file['md5'] = $md5;
       db_merge('registry_file')
         ->key(array('filename' => $filename))
@@ -109,11 +110,13 @@ 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 $file
+ *   An associative array about the file. Only the module key is used.
  * @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.
  */
-function _registry_parse_file($filename, $contents) {
+function _registry_parse_file($filename, $file, $contents) {
   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')->condition('filename', $filename)->execute();
@@ -123,6 +126,20 @@ 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)) {
+        $hook = '';
+        $module = '';
+        if ($type == 'function' && isset($file['module'])) {
+          $module = $file['module']->name;
+          $n = strlen($module);
+          if (substr($resource_name, 0, $n) == $module) {
+            $hook = substr($resource_name, $n + 1);
+          }
+        }
+        $fields = array(
+          'filename' => $filename,
+          'module' => $module,
+          'hook' => $hook,
+        );
         // 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.
@@ -132,7 +149,7 @@ function _registry_parse_file($filename,
         // filename instead of another.
         // TODO: Convert this back to an insert query after all duplicate
         // function names have been purged from Drupal.
-        db_merge('registry')->key(array('name' => $resource_name, 'type' => $type))->fields(array('filename' => $filename))->execute();
+        db_merge('registry')->key(array('name' => $resource_name, 'type' => $type))->fields($fields)->execute();
 
         // We skip the body because classes may contain functions.
         _registry_skip_body($tokens);

=== modified file 'index.php'
--- index.php	2008-08-21 19:36:35 +0000
+++ index.php	2008-09-11 02:37:21 +0000
@@ -14,6 +14,7 @@
 
 require_once './includes/bootstrap.inc';
 drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
+
 $return = menu_execute_active_handler();
 
 // Menu status constants are integers; page content is a string.

=== modified file 'modules/system/system.install'
--- modules/system/system.install	2008-09-06 08:36:19 +0000
+++ modules/system/system.install	2008-09-11 02:37:21 +0000
@@ -1091,6 +1091,18 @@ 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,
+      ),
+      'hook' => array(
+        'description' => t('Name of the hook this function implements, if any.'),
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
     ),
     'primary key' => array('name', 'type'),
   );

