Index: includes/module.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/module.inc,v
retrieving revision 1.191
diff -u -p -r1.191 module.inc
--- includes/module.inc	28 Apr 2010 12:36:26 -0000	1.191
+++ includes/module.inc	28 Apr 2010 22:57:19 -0000
@@ -852,10 +852,22 @@ function drupal_alter($type, &$data, &$c
       }
       // If any modules implement one of the extra hooks that do not implement
       // the primary hook, we need to add them to the $modules array in their
-      // appropriate order.
+      // appropriate order. module_implements() can only return ordered
+      // implementations of a single hook. To get the ordered implementations
+      // of multiple hooks, we mimic the module_implements() logic of first
+      // ordering by module_list(), and then calling
+      // drupal_alter('module_implements').
       if (array_diff($extra_modules, $modules)) {
-        // Order the modules by the order returned by module_list().
+        // Merge the arrays and order by module_list().
         $modules = array_intersect(module_list(), array_merge($modules, $extra_modules));
+        // Since module_implements() already took care of loading the necessary
+        // include files, we can safely pass FALSE for the array values.
+        $implementations = array_fill_keys($modules, FALSE);
+        // Let modules adjust the order solely based on the primary hook. This
+        // ensures the same module order regardless of whether this if block
+        // runs.
+        drupal_alter('module_implements', $implementations, $hook);
+        $modules = array_keys($implementations);
       }
       foreach ($modules as $module) {
         // Since $modules is a merged array, for any given module, we do not
Index: modules/simpletest/tests/common.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v
retrieving revision 1.110
diff -u -p -r1.110 common.test
--- modules/simpletest/tests/common.test	22 Apr 2010 21:41:09 -0000	1.110
+++ modules/simpletest/tests/common.test	28 Apr 2010 22:57:20 -0000
@@ -57,6 +57,14 @@ class DrupalAlterTestCase extends Drupal
     $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.'));
     $this->assertEqual($entity_copy, $entity_expected, t('Second argument to drupal_alter() was altered.'));
     $this->assertEqual($array2_copy, $array2_expected, t('Third argument to drupal_alter() was altered.'));
+
+    // Verify alteration order when passing an array of types to drupal_alter().
+    // common_test_module_implements_alter() places 'block' implementation after
+    // other modules.
+    $array_copy = $array;
+    $array_expected = array('foo' => 'Drupal block theme');
+    drupal_alter(array('drupal_alter', 'drupal_alter_foo'), $array_copy);
+    $this->assertEqual($array_copy, $array_expected, t('hook_TYPE_alter() implementations ran in correct order.'));
   }
 }
 
Index: modules/simpletest/tests/common_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common_test.module,v
retrieving revision 1.10
diff -u -p -r1.10 common_test.module
--- modules/simpletest/tests/common_test.module	2 Mar 2010 08:47:41 -0000	1.10
+++ modules/simpletest/tests/common_test.module	28 Apr 2010 22:57:20 -0000
@@ -141,6 +141,34 @@ function garland_drupal_alter_alter(&$da
 }
 
 /**
+ * Implements hook_TYPE_alter() on behalf of block module.
+ *
+ * This is for verifying that drupal_alter(array(TYPE1, TYPE2), ...) allows
+ * hook_module_implements_alter() to affect the order in which module
+ * implementations are executed.
+ */
+function block_drupal_alter_foo_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) {
+  $data['foo'] .= ' block';
+}
+
+/**
+ * Implements hook_module_implements_alter().
+ *
+ * @see block_drupal_alter_foo_alter()
+ */
+function common_test_module_implements_alter(&$implementations, $hook) {
+  // For drupal_alter(array('drupal_alter', 'drupal_alter_foo'), ...), make the
+  // block module implementations run after all the other modules. Note that
+  // when drupal_alter() is called with an array of types, the first type is
+  // considered primary and controls the module order.
+  if ($hook == 'drupal_alter_alter' && isset($implementations['block'])) {
+    $group = $implementations['block'];
+    unset($implementations['block']);
+    $implementations['block'] = $group;
+  }
+}
+
+/**
  * Implements hook_theme().
  */
 function common_test_theme() {
