Index: modules/field/modules/options/options.api.php
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/options/options.api.php,v
retrieving revision 1.1
diff -u -p -r1.1 options.api.php
--- modules/field/modules/options/options.api.php	14 Dec 2009 20:18:55 -0000	1.1
+++ modules/field/modules/options/options.api.php	3 Sep 2010 15:03:37 -0000
@@ -53,7 +53,7 @@ function hook_options_list($field) {
   // on properties of the field. Example from taxonomy.module:
   $options = array();
   foreach ($field['settings']['allowed_values'] as $tree) {
-    $terms = taxonomy_get_tree($tree['vid'], $tree['parent']);
+    $terms = taxonomy_get_entries($tree['vid'], $tree['parent']);
     if ($terms) {
       foreach ($terms as $term) {
         $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
Index: modules/forum/forum.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.admin.inc,v
retrieving revision 1.36
diff -u -p -r1.36 forum.admin.inc
--- modules/forum/forum.admin.inc	8 Aug 2010 19:21:25 -0000	1.36
+++ modules/forum/forum.admin.inc	3 Sep 2010 15:03:38 -0000
@@ -286,7 +286,7 @@ function _forum_parent_select($tid, $tit
   }
 
   $vid = variable_get('forum_nav_vocabulary', '');
-  $children = taxonomy_get_tree($vid, $tid);
+  $children = taxonomy_get_entries($vid, $tid);
 
   // A term can't be the child of itself, nor of its children.
   foreach ($children as $child) {
@@ -294,7 +294,7 @@ function _forum_parent_select($tid, $tit
   }
   $exclude[] = $tid;
 
-  $tree = taxonomy_get_tree($vid);
+  $tree = taxonomy_get_entries($vid);
   $options[0] = '<' . t('root') . '>';
   if ($tree) {
     foreach ($tree as $term) {
Index: modules/forum/forum.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/forum/forum.module,v
retrieving revision 1.573
diff -u -p -r1.573 forum.module
--- modules/forum/forum.module	17 Aug 2010 16:20:07 -0000	1.573
+++ modules/forum/forum.module	3 Sep 2010 15:03:40 -0000
@@ -777,7 +777,7 @@ function forum_forum_load($tid = NULL) {
 
   // Load the tree below.
   $forums = array();
-  $_forums = taxonomy_get_tree($vid, $tid);
+  $_forums = taxonomy_get_entries($vid, $tid);
 
   if (count($_forums)) {
     $query = db_select('node', 'n');
Index: modules/taxonomy/taxonomy.admin.inc
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.admin.inc,v
retrieving revision 1.107
diff -u -p -r1.107 taxonomy.admin.inc
--- modules/taxonomy/taxonomy.admin.inc	31 Jul 2010 13:01:50 -0000	1.107
+++ modules/taxonomy/taxonomy.admin.inc	3 Sep 2010 15:03:41 -0000
@@ -286,7 +286,7 @@ function taxonomy_overview_terms($form, 
 
   $delta = 0;
   $term_deltas = array();
-  $tree = taxonomy_get_tree($vocabulary->vid);
+  $tree = taxonomy_get_entries($vocabulary->vid);
   $term = current($tree);
   do {
     // In case this tree is completely empty.
@@ -462,7 +462,7 @@ function taxonomy_overview_terms_submit(
   $hierarchy = 0; // Update the current hierarchy type as we go.
 
   $changed_terms = array();
-  $tree = taxonomy_get_tree($vocabulary->vid);
+  $tree = taxonomy_get_entries($vocabulary->vid);
 
   if (empty($tree)) {
     return;
@@ -721,13 +721,13 @@ function taxonomy_form_term($form, &$for
     '#weight' => 10,
   );
 
-  // taxonomy_get_tree and taxonomy_get_parents may contain large numbers of
+  // taxonomy_get_entries and taxonomy_get_parents may contain large numbers of
   // items so we check for taxonomy_override_selector before loading the
   // full vocabulary. Contrib modules can then intercept before
   // hook_form_alter to provide scalable alternatives.
   if (!variable_get('taxonomy_override_selector', FALSE)) {
     $parent = array_keys(taxonomy_get_parents($term->tid));
-    $children = taxonomy_get_tree($vocabulary->vid, $term->tid);
+    $children = taxonomy_get_entries($vocabulary->vid, $term->tid);
 
     // A term can't be the child of itself, nor of its children.
     foreach ($children as $child) {
@@ -735,7 +735,7 @@ function taxonomy_form_term($form, &$for
     }
     $exclude[] = $term->tid;
 
-    $tree = taxonomy_get_tree($vocabulary->vid);
+    $tree = taxonomy_get_entries($vocabulary->vid);
     $options = array('<' . t('root') . '>');
     if (empty($parent)) {
       $parent = array(0);
Index: modules/taxonomy/taxonomy.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/taxonomy/taxonomy.module,v
retrieving revision 1.603
diff -u -p -r1.603 taxonomy.module
--- modules/taxonomy/taxonomy.module	22 Aug 2010 15:45:03 -0000	1.603
+++ modules/taxonomy/taxonomy.module	3 Sep 2010 15:03:44 -0000
@@ -448,7 +448,7 @@ function taxonomy_vocabulary_delete($vid
  *   An array of the term structure that was updated.
  */
 function taxonomy_check_vocabulary_hierarchy($vocabulary, $changed_term) {
-  $tree = taxonomy_get_tree($vocabulary->vid);
+  $tree = taxonomy_get_entries($vocabulary->vid);
   $hierarchy = 0;
   foreach ($tree as $term) {
     // Update the changed term with the new parent value before comparison.
@@ -680,6 +680,8 @@ function taxonomy_terms_static_reset() {
   drupal_static_reset('taxonomy_get_tree');
   drupal_static_reset('taxonomy_get_tree:parents');
   drupal_static_reset('taxonomy_get_tree:terms');
+  drupal_static_reset('taxonomy_get_entries');
+  drupal_static_reset('taxonomy_get_entries:parents');
   drupal_static_reset('taxonomy_get_parents');
   drupal_static_reset('taxonomy_get_parents_all');
   drupal_static_reset('taxonomy_get_children');
@@ -858,6 +860,99 @@ function taxonomy_get_tree($vid, $parent
 }
 
 /**
+ * Creates a flat list of term entries, usually used for generating forms or
+ * overviews of terms.
+ *
+ * Note that the entries do not represent full term objects. If full term objects
+ * are required, use taxonomy_get_tree (needs more processing time).
+ *
+ * @param $vid
+ *   Which vocabulary to generate the list for.
+ * @param $parent
+ *   The term ID under which to load the terms. If 0, return the entire vocabulary.
+ * @param $max_depth
+ *   The number of hierarchy levels to return. Leave NULL to return all levels.
+ *
+ * @return
+ *   An array of all term entries in the vocabulary. Each term entry contains
+ *   the "depth" and "parents" attributes in addition to the data from the
+ *   taxonomy_term_data table.
+ *   Results are statically cached.
+ */
+function taxonomy_get_entries($vid, $parent = 0, $max_depth = NULL) {
+  $children = &drupal_static(__FUNCTION__, array());
+  $parents = &drupal_static(__FUNCTION__ . ':parents', array());
+  $terms = array();
+
+  // We cache terms, so it's not CPU-intensive to call get_entries() on a term
+  // and its children, too.
+  if (!isset($children[$vid])) {
+    $children[$vid] = array();
+    $parents[$vid] = array();
+
+    $query = db_select('taxonomy_term_data', 't');
+    $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
+    $result = $query
+      ->addTag('translatable')
+      ->addTag('term_access')
+      ->fields('t')
+      ->fields('h', array('parent'))
+      ->condition('t.vid', $vid)
+      ->orderBy('weight')
+      ->orderBy('name')
+      ->execute();
+
+    foreach ($result as $term) {
+      $children[$vid][$term->parent][] = $term;
+      $parents[$vid][$term->tid][] = $term->parent;
+     }
+  }
+
+  $max_depth = (is_null($max_depth)) ? count($children[$vid]) : $max_depth;
+  $process_parents = array();
+  $process_parents[] = $parent;
+  while (count($process_parents)) {
+    $parent = array_pop($process_parents);
+    $depth = count($process_parents);
+    if ($max_depth > $depth && !empty($children[$vid][$parent])) {
+      $has_children = FALSE;
+      $child = current($children[$vid][$parent]);
+      do {
+        if (empty($child)) {
+          break;
+        }
+        $child->depth = $depth;
+        unset($child->parent);
+        $child->parents = $parents[$vid][$child->tid];
+        $terms[] = $child;
+        if (!empty($children[$vid][$child->tid])) {
+          $has_children = TRUE;
+
+          // We have to continue with the current parent later
+          // and use $child for the next iteration.
+          $process_parents[] = $parent;
+          $process_parents[] = $child->tid;
+
+          // Reset pointers for child lists because we step in there more often with multi parents.
+          reset($children[$vid][$child->tid]);
+          // Move pointer so that we get the correct term the next time.
+          next($children[$vid][$parent]);
+          break;
+        }
+      } while ($child = next($children[$vid][$parent]));
+
+      if (!$has_children) {
+        // We processed all terms in this hierarchy-level
+        // reset pointer so that this function works the next time it gets called.
+        reset($children[$vid][$parent]);
+      }
+    }
+  }
+
+  return $terms;
+}
+
+/**
  * Try to map a string to an existing term, as for glossary use.
  *
  * Provides a case-insensitive and trimmed mapping, to maximize the
@@ -1275,7 +1370,7 @@ function taxonomy_field_formatter_view($
 function taxonomy_allowed_values($field) {
   $options = array();
   foreach ($field['settings']['allowed_values'] as $tree) {
-    $terms = taxonomy_get_tree($tree['vid'], $tree['parent']);
+    $terms = taxonomy_get_entries($tree['vid'], $tree['parent']);
     if ($terms) {
       foreach ($terms as $term) {
         $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
