Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.1012
diff -u -p -r1.1012 common.inc
--- includes/common.inc	11 Oct 2009 02:14:43 -0000	1.1012
+++ includes/common.inc	11 Oct 2009 05:27:44 -0000
@@ -2578,6 +2578,93 @@ function drupal_attributes(array $attrib
  *   an HTML string containing a link to the given path.
  */
 function l($text, $path, array $options = array()) {
+  global $theme;
+  static $theme_function;
+  static $processor_functions;
+
+  $variables = array(
+    'text' => $text,
+    'path' => $path,
+    'options' => $options,
+  );
+
+  // Basically, we want to call theme('link', $variables). But we can't do that
+  // until the theme system is fully loaded and operational, and even when it
+  // is, it has too much overhead (l() is called a lot!). So instead, we use
+  // static variables to cache the theme function to call (yes, we're assuming
+  // a function, because a template implementation of 'link' would be needlessly
+  // slow) and its preprocess and process functions. In a sense, we're
+  // duplicating what theme() does in order to shave a few microseconds.
+  if (!isset($theme_function)) {
+    if (isset($theme)) {
+      $hooks = theme_get_registry();
+      if (isset($hooks) && isset($hooks['link']) && isset($hooks['link']['function'])) {
+        $theme_function = $hooks['link']['function'];
+        if (isset($hooks['link']['preprocess functions']) || isset($hooks['link']['process functions'])) {
+          $processor_functions = array();
+          foreach (array('preprocess functions', 'process functions') as $phase) {
+            if (isset($hooks['link'][$phase])) {
+              $processor_functions = array_merge($processor_functions, $hooks['link'][$phase]);
+            }
+          }
+        }
+        // Theme hooks can have include files, but those only need to be loaded
+        // once per page request. No need to duplicate that part of theme().
+        // One more call to theme() per page request is fine. Additional calls
+        // to l() per page request will avoid this overhead.
+        return theme('link', $variables);
+      }
+    }
+  }
+
+  if (isset($theme_function)) {
+    // Here we've already called theme('link') once for the page request and
+    // are on a subsequent call to l(). So we emulate what theme() would do
+    // with respect to preprocess and process functions.
+    if (isset($processor_functions)) {
+      foreach ($processor_functions as $function) {
+        if (function_exists($function)) {
+          $function($variables, 'link');
+        }
+      }
+    }
+    // Now, call the actual function. Chances are, it's not overridden by the
+    // theme, and if so, save the overhead of a function_exists() and calling
+    // a variable function.
+    if ($theme_function == 'theme_link') {
+      return theme_link($variables);
+    }
+    elseif (function_exists($theme_function)) {
+      return $theme_function($variables);
+    }
+  }
+  else {
+    // We should only be here if the theme system hasn't initialized yet, or
+    // something is weird and the 'link' hook isn't in the registry.
+    return theme_link($variables);
+  }
+}
+
+/**
+ * Format an internal Drupal link.
+ *
+ * @param $variables
+ *   A keyed array with 'text', 'path', and 'options'.
+ *   @see l() for documentation about these.
+ * 
+ * @return
+ *   an HTML string containing a link to the given path.
+ * 
+ * @ingroup themeable
+ * 
+ * @todo
+ *   If it's never possible for l() to be called without theme.inc loaded,
+ *   then move this function to theme.inc.
+ */
+function theme_link($variables) {
+  $text = $variables['text'];
+  $path = $variables['path'];
+  $options = $variables['options'];
   global $language_url;
 
   // Merge in defaults.
@@ -4857,6 +4944,9 @@ function drupal_common_theme() {
     'status_messages' => array(
       'arguments' => array('display' => NULL),
     ),
+    'link' => array(
+      'arguments' => array('text' => NULL, 'path' => NULL, 'options' => array()),
+    ),
     'links' => array(
       'arguments' => array('links' => NULL, 'attributes' => array('class' => array('links')), 'heading' => array()),
     ),
