Index: lucene/core/src/java/org/apache/lucene/util/SorterTemplate.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/SorterTemplate.java	(révision 1459301)
+++ lucene/core/src/java/org/apache/lucene/util/SorterTemplate.java	(copie de travail)
@@ -343,8 +343,10 @@
     merge(lo, mid, hi, mid - lo, hi - mid);
   }
 
-  // pkg-protected for access from TimSort class
-  void merge(int lo, int pivot, int hi, int len1, int len2) {
+  /** Merge the slices [lo-pivot[ (of length len1) and [pivot-hi[ (of length
+   *  len2) which are already sorted. This method merges in-place but can be
+   *  extended to provide a faster implementation using extra memory. */
+  protected void merge(int lo, int pivot, int hi, int len1, int len2) {
     if (len1 == 0 || len2 == 0) {
       return;
     }
Index: lucene/core/src/java/org/apache/lucene/util/ArrayUtil.java
===================================================================
--- lucene/core/src/java/org/apache/lucene/util/ArrayUtil.java	(révision 1459301)
+++ lucene/core/src/java/org/apache/lucene/util/ArrayUtil.java	(copie de travail)
@@ -28,6 +28,11 @@
 
 public final class ArrayUtil {
 
+  // affordable memory overhead to merge sorted arrays
+  private static final float MERGE_OVERHEAD_RATIO = 0.01f;
+  // arrays below this size will always be sorted in-place
+  private static final int MERGE_EXTRA_MEMORY_THRESHOLD = (int) (5 / MERGE_OVERHEAD_RATIO);
+
   private ArrayUtil() {} // no instance
 
   /*
@@ -604,65 +609,145 @@
 
     return result;
   }
-  
-  /** SorterTemplate with custom {@link Comparator} */
-  private static <T> SorterTemplate getSorter(final T[] a, final Comparator<? super T> comp) {
-    return new SorterTemplate() {
-      @Override
-      protected void swap(int i, int j) {
-        final T o = a[i];
-        a[i] = a[j];
-        a[j] = o;
+
+  private static abstract class ArraySorterTemplate<T> extends SorterTemplate {
+
+    protected final T[] a;
+
+    ArraySorterTemplate(T[] a) {
+      this.a = a;
+    }
+
+    protected abstract int compare(T a, T b);
+
+    @Override
+    protected void swap(int i, int j) {
+      final T o = a[i];
+      a[i] = a[j];
+      a[j] = o;
+    }
+
+    @Override
+    protected int compare(int i, int j) {
+      return compare(a[i], a[j]);
+    }
+
+    @Override
+    protected void setPivot(int i) {
+      pivot = a[i];
+    }
+
+    @Override
+    protected int comparePivot(int j) {
+      return compare(pivot, a[j]);
+    }
+
+    private T pivot;
+
+  }
+
+  // a template for merge-based sorts which uses extra memory to speed up merging
+  private static abstract class ArrayMergeSorterTemplate<T> extends ArraySorterTemplate<T> {
+
+    final int threshold; // maximum length of a merge that can be made using extra memory
+    private final T[] tmp;
+
+    ArrayMergeSorterTemplate(T[] a, float overheadRatio) {
+      super(a);
+      this.threshold = (int) (a.length * overheadRatio);
+      @SuppressWarnings("unchecked")
+      final T[] tmpBuf = (T[]) new Object[threshold];
+      this.tmp = tmpBuf;
+    }
+
+    private void mergeWithExtraMemory(int lo, int pivot, int hi, int len1, int len2) {
+      System.arraycopy(a, lo, tmp, 0, len1);
+      int i = 0, j = pivot, dest = lo;
+      while (i < len1 && j < hi) {
+        if (compare(tmp[i], a[j]) <= 0) {
+          a[dest++] = tmp[i++];
+        } else {
+          a[dest++] = a[j++];
+        }
       }
-      
-      @Override
-      protected int compare(int i, int j) {
-        return comp.compare(a[i], a[j]);
+      while (i < len1) {
+        a[dest++] = tmp[i++];
       }
+      while (j < hi) {
+        a[dest++] = a[j++];
+      }
+      assert dest == hi;
+    }
 
-      @Override
-      protected void setPivot(int i) {
-        pivot = a[i];
+    @Override
+    protected void merge(int lo, int pivot, int hi, int len1, int len2) {
+      if (len1 <= threshold) {
+        mergeWithExtraMemory(lo, pivot, hi, len1, len2);
+      } else {
+        // since this method recurses to run merge on smaller arrays, it will
+        // end up using mergeWithExtraMemory
+        super.merge(lo, pivot, hi, len1, len2);
       }
-  
+    }
+
+  }
+
+  /** SorterTemplate with custom {@link Comparator} */
+  private static <T> SorterTemplate getSorter(final T[] a, final Comparator<? super T> comp) {
+    return new ArraySorterTemplate<T>(a) {
+
       @Override
-      protected int comparePivot(int j) {
-        return comp.compare(pivot, a[j]);
+      protected int compare(T a, T b) {
+        return comp.compare(a, b);
       }
-      
-      private T pivot;
+
     };
   }
-  
+
   /** Natural SorterTemplate */
   private static <T extends Comparable<? super T>> SorterTemplate getSorter(final T[] a) {
-    return new SorterTemplate() {
+    return new ArraySorterTemplate<T>(a) {
+
       @Override
-      protected void swap(int i, int j) {
-        final T o = a[i];
-        a[i] = a[j];
-        a[j] = o;
+      protected int compare(T a, T b) {
+        return a.compareTo(b);
       }
-      
-      @Override
-      protected int compare(int i, int j) {
-        return a[i].compareTo(a[j]);
-      }
 
-      @Override
-      protected void setPivot(int i) {
-        pivot = a[i];
-      }
-  
-      @Override
-      protected int comparePivot(int j) {
-        return pivot.compareTo(a[j]);
-      }
-      
-      private T pivot;
     };
   }
 
+  /** SorterTemplate with custom {@link Comparator} for merge-based sorts. */
+  private static <T> SorterTemplate getMergeSorter(final T[] a, final Comparator<? super T> comp) {
+    if (a.length < MERGE_EXTRA_MEMORY_THRESHOLD) {
+      return getSorter(a, comp);
+    } else {
+      return new ArrayMergeSorterTemplate<T>(a, MERGE_OVERHEAD_RATIO) {
+
+        @Override
+        protected int compare(T a, T b) {
+          return comp.compare(a, b);
+        }
+
+      };
+    }
+  }
+
+  /** Natural SorterTemplate for merge-based sorts. */
+  private static <T extends Comparable<? super T>> SorterTemplate getMergeSorter(final T[] a) {
+    if (a.length < MERGE_EXTRA_MEMORY_THRESHOLD) {
+      return getSorter(a);
+    } else {
+      return new ArrayMergeSorterTemplate<T>(a, MERGE_OVERHEAD_RATIO) {
+
+        @Override
+        protected int compare(T a, T b) {
+          return a.compareTo(b);
+        }
+
+      };
+    }
+  }
+
   // quickSorts (endindex is exclusive!):
   
   /**
@@ -714,7 +799,7 @@
   public static <T> void mergeSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> comp) {
     if (toIndex-fromIndex <= 1) return;
     //System.out.println("SORT: " + (toIndex-fromIndex));
-    getSorter(a, comp).mergeSort(fromIndex, toIndex-1);
+    getMergeSorter(a, comp).mergeSort(fromIndex, toIndex-1);
   }
   
   /**
@@ -733,7 +818,7 @@
    */
   public static <T extends Comparable<? super T>> void mergeSort(T[] a, int fromIndex, int toIndex) {
     if (toIndex-fromIndex <= 1) return;
-    getSorter(a).mergeSort(fromIndex, toIndex-1);
+    getMergeSorter(a).mergeSort(fromIndex, toIndex-1);
   }
   
   /**
@@ -754,7 +839,7 @@
    */
   public static <T> void timSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> comp) {
     if (toIndex-fromIndex <= 1) return;
-    getSorter(a, comp).timSort(fromIndex, toIndex-1);
+    getMergeSorter(a, comp).timSort(fromIndex, toIndex-1);
   }
   
   /**
@@ -773,7 +858,7 @@
    */
   public static <T extends Comparable<? super T>> void timSort(T[] a, int fromIndex, int toIndex) {
     if (toIndex-fromIndex <= 1) return;
-    getSorter(a).timSort(fromIndex, toIndex-1);
+    getMergeSorter(a).timSort(fromIndex, toIndex-1);
   }
   
   /**
