diff --git a/modules/field/field.info.inc b/modules/field/field.info.inc
index cc8dac5..5e0ffdc 100644
--- a/modules/field/field.info.inc
+++ b/modules/field/field.info.inc
@@ -6,6 +6,251 @@
  */
 
 /**
+ * Extends DrupalCacheArray to allow dynamic building of the field info cache.
+ */
+class FieldInfoFieldCache {
+  protected $fields;
+  protected $field_ids;
+  protected $bundles;
+  protected $bin;
+
+  public function __construct() {
+    $this->fields = array();
+    $this->field_ids = array();
+    $this->bundles = array();
+    $this->bin = 'field';
+  }
+
+  // @todo : rename $offset
+  public function bundleGet($offset) {
+    if (isset($this->bundles[$offset])) {
+      $value = $this->bundles[$offset];
+    }
+    elseif ($cached = cache($this->bin)->get('info_fields:' . $offset)) {
+      $value = $cached->data;
+      // Extract the 'fields' part and store them globally.
+      $this->fields += $value['fields'];
+      // @todo : kind of absurd, we're re-adding it below.
+      unset($value['fields']);
+      $this->bundles[$offset] = $value;
+    }
+    else {
+      $value = $this->bundleResolve($offset);
+    }
+
+    // Additionally, populate actual fields from ids.
+    foreach ($value['field_ids'] as $field_id) {
+      $value['fields'][$field_id] = $this->fields[$field_id];
+    }
+
+    return $value;
+  }
+
+  public function fieldGet($field_name) {
+    $field = NULL;
+
+    if (isset($this->field_ids[$field_name])) {
+      $field = $this->fields[$this->field_ids[$field_name]];
+    }
+    elseif ($field = field_read_field(array('field_name' => $field_name))) {
+      $field = _field_info_prepare_field($field);
+
+      // Persist for the rest of the request.
+      $this->fields[$field['id']] = $field;
+      $this->field_ids[$field_name] = $field['id'];
+    }
+
+    return $field;
+  }
+
+  public function fieldIdGet($field_id) {
+    $field = NULL;
+
+    if (isset($this->fields[$field_id])) {
+      $field = $this->fields[$field_id];
+    }
+    elseif ($field = field_read_field(array('id' => $field_id, array('include_deleted' => TRUE)))) {
+      $field = _field_info_prepare_field($field);
+
+      // Persist for the rest of the request.
+      $this->fields[$field['id']] = $field;
+      if (!$field['deleted']) {
+        $this->field_ids[$field_name] = $field['id'];
+      }
+    }
+
+    return $field;
+  }
+
+  protected function bundleResolve($offset) {
+    list ($entity_type, $bundle) = explode(':', $offset);
+    $value = array(
+      'instances' => array(),
+      'field_ids' => array(),
+    );
+
+    $fields = field_read_fields(array(), array('include_deleted' => 1));
+    $field_bundles = array();
+
+    // Note: we need to read instances on all bundles in order to populate
+    // $field['bundles'] in the global list of fields.
+    foreach (field_read_instances() as $instance) {
+      $field_id = $instance['field_id'];
+      $field_name = $instance['field_name'];
+
+      if ($instance['entity_type'] == $entity_type && $instance['bundle'] == $bundle) {
+
+        // Populate the global array of fields and field ids.
+        if (!isset($this->fields[$field_id])) {
+          $field = _field_info_prepare_field($fields[$field_id]);
+          $this->fields[$field_id] = $field;
+          if (!$field['deleted']) {
+            $this->field_ids[$field_name] = $field_id;
+          }
+        }
+        else {
+          $field = $this->fields[$field_id];
+        }
+
+        $instance = _field_info_prepare_instance($instance, $field);
+        $value['instances'][$field_name] = $instance;
+        // @todo : key by field name ?
+        $value['field_ids'][] = $field_id;
+      }
+
+      // Collect the list of bundles for all fields.
+      $field_bundles[$field_id][$instance['entity_type']][] = $instance['bundle'];
+    }
+
+    // Enrich field definitions with the list of bundles where they have
+    // instances. Note: Deleted fields are not enriched because all of their
+    // instances are deleted, too, and are thus not iterated here.
+    foreach ($value['field_ids'] as $field_id) {
+      $this->fields[$field_id]['bundles'] = $field_bundles[$field_id];
+    }
+
+    // Populate 'extra_fields'.
+    $extra = module_invoke_all('field_extra_fields');
+    drupal_alter('field_extra_fields', $extra);
+    // Merge in saved settings.
+    foreach ($extra as $entity_type => $bundles) {
+      foreach ($bundles as $bundle => $extra_fields) {
+        $extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
+        $value['extra_fields'][$entity_type][$bundle] = $extra_fields;
+      }
+    }
+
+    $this->bundles["$entity_type:$bundle"] = $value;
+//    $this->persist("$entity_type:$bundle");
+    
+    return $value;
+  }
+
+  public function __destruct() {
+    // @todo : this will persist any calls with non-existent entity types or bundles.
+    foreach ($this->bundles as $offset => $value) {;
+      // Add field definitions from the global list of fields.
+      foreach ($value['field_ids'] as $field_id) {
+        $value['fields'][$field_id] = $this->fields[$field_id];
+        // @todo : persist $this->field_ids ?
+      }
+      cache($this->bin)->set('info_fields:' . $offset, $value);
+    }
+  }
+
+  /**
+   * Don't look at that, this is the code from current _field_info_collate_fields().
+   */
+  function dummy_old_code() {
+    $definitions = array(
+      'field_ids' => field_read_fields(array(), array('include_deleted' => 1)),
+      'instances' => field_read_instances(),
+    );
+
+    // Populate 'fields' with all fields, keyed by ID.
+    $info['fields'] = array();
+    foreach ($definitions['field_ids'] as $key => $field) {
+      $info['fields'][$key] = $definitions['field_ids'][$key] = _field_info_prepare_field($field);
+    }
+
+    // Build an array of field IDs for non-deleted fields, keyed by name.
+    $info['field_ids'] = array();
+    foreach ($info['fields'] as $key => $field) {
+      if (!$field['deleted']) {
+        $info['field_ids'][$field['field_name']] = $key;
+      }
+    }
+
+    // Populate 'instances'. Only non-deleted instances are considered.
+    $info['instances'] = array();
+    foreach (field_info_bundles() as $entity_type => $bundles) {
+      foreach ($bundles as $bundle => $bundle_info) {
+        $info['instances'][$entity_type][$bundle] = array();
+      }
+    }
+    foreach ($definitions['instances'] as $instance) {
+      $field = $info['fields'][$instance['field_id']];
+      $instance = _field_info_prepare_instance($instance, $field);
+      $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
+      // Enrich field definitions with the list of bundles where they have
+      // instances. NOTE: Deleted fields in $info['field_ids'] are not
+      // enriched because all of their instances are deleted, too, and
+      // are thus not in $definitions['instances'].
+      $info['fields'][$instance['field_id']]['bundles'][$instance['entity_type']][] = $instance['bundle'];
+    }
+
+    // Populate 'extra_fields'.
+    $extra = module_invoke_all('field_extra_fields');
+    drupal_alter('field_extra_fields', $extra);
+    // Merge in saved settings.
+    foreach ($extra as $entity_type => $bundles) {
+      foreach ($bundles as $bundle => $extra_fields) {
+        $extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
+        $info['extra_fields'][$entity_type][$bundle] = $extra_fields;
+      }
+    }
+  }
+}
+
+function _field_info_field_cache() {
+  // Use the advanced drupal_static() pattern, since this is called very often.
+  static $drupal_static_fast;
+
+  if (!isset($drupal_static_fast)) {
+    $drupal_static_fast['field_info_field_cache'] = &drupal_static(__FUNCTION__);
+  }
+  $info = &$drupal_static_fast['field_info_field_cache'];
+
+  if (!isset($info)) {
+    $info = new FieldInfoFieldCache();
+  }
+  
+  return $info;
+}
+
+function _field_info_field_cache_reset() {
+  // @todo this will trigger _destruct() and perform a cache write ?
+  drupal_static_reset('_field_info_field_cache');
+  cache('field')->deletePrefix('info_fields');
+}
+
+function dummy_test() {
+  $cache = _field_info_field_cache();
+  dsm($cache->bundleGet('node:article'), '$cache[node:article]');
+  dsm(cache('field')->get('info_fields:node:article')->data, 'cache node:article');
+  dsm($info, '$cache');
+  dsm($cache->bundleGet('node:page'), '$cache[node:page]');
+  dsm(cache('field')->get('info_fields:node:page'), 'cache node:page');
+  dsm($info, '$info');
+
+  dsm(cache('field')->get('info_fields:node:article')->data, 'cache node:article');
+  drupal_flush_all_caches();
+  dsm(field_info_instance('node', 'body', 'article'), 'instance : body (article)');
+  dsm(field_info_instance('node', 'body', 'foo'), 'instance : body (foo)');
+  dsm(field_info_instances('node', 'article'), 'instances (article)');
+}
+
+/**
  * @defgroup field_info Field Info API
  * @{
  * Obtain information about Field API configuration.
@@ -30,7 +275,10 @@ function field_info_cache_clear() {
   entity_info_cache_clear();
 
   _field_info_collate_types(TRUE);
+  // @todo remove
   _field_info_collate_fields(TRUE);
+  _field_info_field_cache_reset();
+
 }
 
 /**
@@ -177,72 +425,73 @@ function _field_info_collate_types($reset = FALSE) {
  *     whose field is active.
  */
 function _field_info_collate_fields($reset = FALSE) {
-  static $info;
-
-  if ($reset) {
-    $info = NULL;
-    cache('field')->delete('field_info_fields');
-    return;
-  }
-
-  if (!isset($info)) {
-    if ($cached = cache('field')->get('field_info_fields')) {
-      $info = $cached->data;
-    }
-    else {
-      $definitions = array(
-        'field_ids' => field_read_fields(array(), array('include_deleted' => 1)),
-        'instances' => field_read_instances(),
-      );
-
-      // Populate 'fields' with all fields, keyed by ID.
-      $info['fields'] = array();
-      foreach ($definitions['field_ids'] as $key => $field) {
-        $info['fields'][$key] = $definitions['field_ids'][$key] = _field_info_prepare_field($field);
-      }
-
-      // Build an array of field IDs for non-deleted fields, keyed by name.
-      $info['field_ids'] = array();
-      foreach ($info['fields'] as $key => $field) {
-        if (!$field['deleted']) {
-          $info['field_ids'][$field['field_name']] = $key;
-        }
-      }
-
-      // Populate 'instances'. Only non-deleted instances are considered.
-      $info['instances'] = array();
-      foreach (field_info_bundles() as $entity_type => $bundles) {
-        foreach ($bundles as $bundle => $bundle_info) {
-          $info['instances'][$entity_type][$bundle] = array();
-        }
-      }
-      foreach ($definitions['instances'] as $instance) {
-        $field = $info['fields'][$instance['field_id']];
-        $instance = _field_info_prepare_instance($instance, $field);
-        $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
-        // Enrich field definitions with the list of bundles where they have
-        // instances. NOTE: Deleted fields in $info['field_ids'] are not
-        // enriched because all of their instances are deleted, too, and
-        // are thus not in $definitions['instances'].
-        $info['fields'][$instance['field_id']]['bundles'][$instance['entity_type']][] = $instance['bundle'];
-      }
-
-      // Populate 'extra_fields'.
-      $extra = module_invoke_all('field_extra_fields');
-      drupal_alter('field_extra_fields', $extra);
-      // Merge in saved settings.
-      foreach ($extra as $entity_type => $bundles) {
-        foreach ($bundles as $bundle => $extra_fields) {
-          $extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
-          $info['extra_fields'][$entity_type][$bundle] = $extra_fields;
-        }
-      }
-
-      cache('field')->set('field_info_fields', $info);
-    }
-  }
-
-  return $info;
+//  static $info;
+//  static $schema;
+//
+//  if ($reset) {
+//    $info = NULL;
+//    cache('field')->delete('field_info_fields');
+//    return;
+//  }
+//
+//  if (!isset($info)) {
+//    if ($cached = cache('field')->get('field_info_fields')) {
+//      $info = $cached->data;
+//    }
+//    else {
+//      $definitions = array(
+//        'field_ids' => field_read_fields(array(), array('include_deleted' => 1)),
+//        'instances' => field_read_instances(),
+//      );
+//
+//      // Populate 'fields' with all fields, keyed by ID.
+//      $info['fields'] = array();
+//      foreach ($definitions['field_ids'] as $key => $field) {
+//        $info['fields'][$key] = $definitions['field_ids'][$key] = _field_info_prepare_field($field);
+//      }
+//
+//      // Build an array of field IDs for non-deleted fields, keyed by name.
+//      $info['field_ids'] = array();
+//      foreach ($info['fields'] as $key => $field) {
+//        if (!$field['deleted']) {
+//          $info['field_ids'][$field['field_name']] = $key;
+//        }
+//      }
+//
+//      // Populate 'instances'. Only non-deleted instances are considered.
+//      $info['instances'] = array();
+//      foreach (field_info_bundles() as $entity_type => $bundles) {
+//        foreach ($bundles as $bundle => $bundle_info) {
+//          $info['instances'][$entity_type][$bundle] = array();
+//        }
+//      }
+//      foreach ($definitions['instances'] as $instance) {
+//        $field = $info['fields'][$instance['field_id']];
+//        $instance = _field_info_prepare_instance($instance, $field);
+//        $info['instances'][$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
+//        // Enrich field definitions with the list of bundles where they have
+//        // instances. NOTE: Deleted fields in $info['field_ids'] are not
+//        // enriched because all of their instances are deleted, too, and
+//        // are thus not in $definitions['instances'].
+//        $info['fields'][$instance['field_id']]['bundles'][$instance['entity_type']][] = $instance['bundle'];
+//      }
+//
+//      // Populate 'extra_fields'.
+//      $extra = module_invoke_all('field_extra_fields');
+//      drupal_alter('field_extra_fields', $extra);
+//      // Merge in saved settings.
+//      foreach ($extra as $entity_type => $bundles) {
+//        foreach ($bundles as $bundle => $extra_fields) {
+//          $extra_fields = _field_info_prepare_extra_fields($extra_fields, $entity_type, $bundle);
+//          $info['extra_fields'][$entity_type][$bundle] = $extra_fields;
+//        }
+//      }
+//
+//      cache('field')->set('field_info_fields', $info);
+//    }
+//  }
+//
+//  return $info;
 }
 
 /**
@@ -588,10 +837,9 @@ function field_info_bundles($entity_type = NULL) {
  */
 function field_info_fields() {
   $fields = array();
-  $info = _field_info_collate_fields();
-  foreach ($info['fields'] as $key => $field) {
+  foreach (field_read_fields() as $key => $field) {
     if (!$field['deleted']) {
-      $fields[$field['field_name']] = $field;
+      $fields[$field['field_name']] = _field_info_prepare_field($field);
     }
   }
   return $fields;
@@ -613,10 +861,8 @@ function field_info_fields() {
  * @see field_info_field_by_id()
  */
 function field_info_field($field_name) {
-  $info = _field_info_collate_fields();
-  if (isset($info['field_ids'][$field_name])) {
-    return $info['fields'][$info['field_ids'][$field_name]];
-  }
+  $cache = _field_info_field_cache();
+  return $cache->fieldGet($field_name);
 }
 
 /**
@@ -634,10 +880,8 @@ function field_info_field($field_name) {
  * @see field_info_field()
  */
 function field_info_field_by_id($field_id) {
-  $info = _field_info_collate_fields();
-  if (isset($info['fields'][$field_id])) {
-    return $info['fields'][$field_id];
-  }
+  $cache = _field_info_field_cache();
+  return $cache->fieldIdGet($field_id);
 }
 
 /**
@@ -655,8 +899,11 @@ function field_info_field_by_id($field_id) {
  * @see field_info_field_by_id()
  */
 function field_info_field_by_ids() {
-  $info = _field_info_collate_fields();
-  return $info['fields'];
+  $fields = array();
+  foreach (field_read_fields(array(), array('include_deleted' => TRUE)) as $key => $field) {
+    $fields[$field['field_name']] = _field_info_prepare_field($field);
+  }
+  return $fields;
 }
 
 /**
@@ -674,17 +921,30 @@ function field_info_field_by_ids() {
  *   all instances for that bundle.
  */
 function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
-  $info = _field_info_collate_fields();
-  if (!isset($entity_type)) {
+  // If entity type + bundle : persist in the cache.
+  if (isset($entity_type) && isset($bundle_name)) {
+    $cache = _field_info_field_cache();
+    $info = $cache->bundleGet("$entity_type:$bundle_name");
     return $info['instances'];
   }
-  if (!isset($bundle_name)) {
-    return $info['instances'][$entity_type];
+
+  $instances = array();
+  $params = array();
+  if (isset($entity_type)) {
+    $params['entity_type'] = $entity_type;
+  }
+  $fields = field_read_fields();
+  foreach (field_read_instances($params) as $instance) {
+    $field = $fields[$instance['field_name']];
+    $instance = _field_info_prepare_instance($instance, $field);
+    $instances[$instance['entity_type']][$instance['bundle']][$instance['field_name']] = $instance;
   }
-  if (isset($info['instances'][$entity_type][$bundle_name])) {
-    return $info['instances'][$entity_type][$bundle_name];
+  if (isset($entity_type)) {
+    return isset($instances[$entity_type]) ? $instances[$entity_type] : array();
+  }
+  else {
+    return $instances;
   }
-  return array();
 }
 
 /**
@@ -698,9 +958,11 @@ function field_info_instances($entity_type = NULL, $bundle_name = NULL) {
  *   The bundle name for the instance.
  */
 function field_info_instance($entity_type, $field_name, $bundle_name) {
-  $info = _field_info_collate_fields();
-  if (isset($info['instances'][$entity_type][$bundle_name][$field_name])) {
-    return $info['instances'][$entity_type][$bundle_name][$field_name];
+  // Persist the instance and field definition.
+  $cache = _field_info_field_cache();
+  $info = $cache->bundleGet("$entity_type:$bundle_name");
+  if (isset($info['instances'][$field_name])) {
+    return $info['instances'][$field_name];
   }
 }
 
@@ -758,11 +1020,9 @@ function field_info_instance($entity_type, $field_name, $bundle_name) {
  *   The array of pseudo-field elements in the bundle.
  */
 function field_info_extra_fields($entity_type, $bundle, $context) {
-  $info = _field_info_collate_fields();
-  if (isset($info['extra_fields'][$entity_type][$bundle][$context])) {
-    return $info['extra_fields'][$entity_type][$bundle][$context];
-  }
-  return array();
+  $cache = _field_info_field_cache();
+  $info = $cache->bundleGet("$entity_type:$bundle_name");
+  return $info['extra_fields'];
 }
 
 /**
diff --git a/modules/field_ui/field_ui.admin.inc b/modules/field_ui/field_ui.admin.inc
index 47129d0..7fc562c 100644
--- a/modules/field_ui/field_ui.admin.inc
+++ b/modules/field_ui/field_ui.admin.inc
@@ -612,6 +612,8 @@ function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle
   // Add settings for the update selects behavior.
   $js_fields = array();
   foreach ($existing_field_options as $field_name => $fields) {
+    // @todo : we probably want to avoid filling the field / instance caches here
+    // -> use field_info_fields() / field_info_instances() ?
     $field = field_info_field($field_name);
     $instance = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']);
     $js_fields[$field_name] = array('label' => $instance['label'], 'type' => $field['type'], 'widget' => $instance['widget']['type']);
@@ -1503,6 +1505,7 @@ function field_ui_existing_field_options($entity_type, $bundle) {
           // - fields that that shoud not be added via user interface.
 
           if (empty($field['locked'])
+            // @todo watch this.
             && !field_info_instance($entity_type, $field['field_name'], $bundle)
             && (empty($field['entity_types']) || in_array($entity_type, $field['entity_types']))
             && empty($field_types[$field['type']]['no_ui'])) {
diff --git a/modules/field_ui/field_ui.module b/modules/field_ui/field_ui.module
index 90559cf..b34c61e 100644
--- a/modules/field_ui/field_ui.module
+++ b/modules/field_ui/field_ui.module
@@ -331,7 +331,10 @@ function field_ui_inactive_instances($entity_type, $bundle_name = NULL) {
   }
   $params['entity_type'] = $entity_type;
 
-  $active_instances = field_info_instances($entity_type);
+  $active_instances = field_info_instances($entity_type, $bundle_name);
+  if (!empty($bundle_name)) {
+    $active_instances = array($bundle_name => $active_instances);
+  }
   $all_instances = field_read_instances($params, array('include_inactive' => TRUE));
   foreach ($all_instances as $instance) {
     if (!isset($active_instances[$instance['bundle']][$instance['field_name']])) {
diff --git a/modules/field_ui/field_ui.test b/modules/field_ui/field_ui.test
index e7c5e18..d9eb912 100644
--- a/modules/field_ui/field_ui.test
+++ b/modules/field_ui/field_ui.test
@@ -269,7 +269,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
    */
   function assertFieldSettings($bundle, $field_name, $string = 'dummy test string', $entity_type = 'node') {
     // Reset the fields info.
-    _field_info_collate_fields(TRUE);
+    _field_info_field_cache_reset();
     // Assert field settings.
     $field = field_info_field($field_name);
     $this->assertTrue($field['settings']['test_field_setting'] == $string, t('Field settings were found.'));
@@ -360,7 +360,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
     $this->fieldUIDeleteField($bundle_path1, $this->field_name, $this->field_label, $this->type);
 
     // Reset the fields info.
-    _field_info_collate_fields(TRUE);
+    _field_info_field_cache_reset();
     // Check that the field instance was deleted.
     $this->assertNull(field_info_instance('node', $this->field_name, $this->type), t('Field instance was deleted.'));
     // Check that the field was not deleted
@@ -370,7 +370,7 @@ class FieldUIManageFieldsTestCase extends FieldUITestCase {
     $this->fieldUIDeleteField($bundle_path2, $this->field_name, $this->field_label, $type_name2);
 
     // Reset the fields info.
-    _field_info_collate_fields(TRUE);
+    _field_info_field_cache_reset();
     // Check that the field instance was deleted.
     $this->assertNull(field_info_instance('node', $this->field_name, $type_name2), t('Field instance was deleted.'));
     // Check that the field was deleted too.
