Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / corlib / System / Array.cs
index 8231de820386b1f961f767fa033cfa80c7254612..bc22c019faa2219f4c357766d8f2ebecc9a10f28 100644 (file)
@@ -40,7 +40,9 @@ using System.Runtime.InteropServices;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Runtime.ConstrainedExecution;
+#if !FULL_AOT_RUNTIME
 using System.Reflection.Emit;
+#endif
 
 namespace System
 {
@@ -48,7 +50,7 @@ namespace System
        [ComVisible (true)]
        // FIXME: We are doing way to many double/triple exception checks for the overloaded functions"
        public abstract class Array : ICloneable, ICollection, IList, IEnumerable
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                , IStructuralComparable, IStructuralEquatable
 #endif
        {
@@ -103,14 +105,16 @@ namespace System
                                T value;
                                GetGenericValueImpl (i, out value);
                                if (item == null){
-                                       if (value == null)
+                                       if (value == null) {
                                                return true;
+                                       }
 
                                        continue;
                                }
-                               
-                               if (item.Equals (value))
+
+                               if (item.Equals (value)) {
                                        return true;
+                               }
                        }
 
                        return false;
@@ -138,6 +142,23 @@ namespace System
                        Copy (this, this.GetLowerBound (0), array, index, this.GetLength (0));
                }
 
+#if NET_4_5
+               internal T InternalArray__IReadOnlyList_get_Item<T> (int index)
+               {
+                       if (unchecked ((uint) index) >= unchecked ((uint) Length))
+                               throw new ArgumentOutOfRangeException ("index");
+
+                       T value;
+                       GetGenericValueImpl (index, out value);
+                       return value;
+               }
+
+               internal int InternalArray__IReadOnlyCollection_get_Count ()
+               {
+                       return Length;
+               }
+#endif
+
                internal void InternalArray__Insert<T> (int index, T item)
                {
                        throw new NotSupportedException ("Collection is of a fixed size");
@@ -434,7 +455,7 @@ namespace System
                        return new SimpleEnumerator (this);
                }
 
-#if NET_4_0 || MOONLIGHT || MOBILE
+#if NET_4_0
                int IStructuralComparable.CompareTo (object other, IComparer comparer)
                {
                        if (other == null)
@@ -490,7 +511,7 @@ namespace System
 
                        int hash = 0;
                        for (int i = 0; i < Length; i++)
-                               hash = ((hash << 7) + hash) ^ GetValue (i).GetHashCode ();
+                               hash = ((hash << 7) + hash) ^ comparer.GetHashCode (GetValueImpl (i));
                        return hash;
                }
 #endif
@@ -673,8 +694,10 @@ namespace System
                                throw new NotSupportedException ("Array type can not be void");
                        if (elementType.ContainsGenericParameters)
                                throw new NotSupportedException ("Array type can not be an open generic type");
+#if !FULL_AOT_RUNTIME
                        if ((elementType is TypeBuilder) && !(elementType as TypeBuilder).IsCreated ())
                                throw new NotSupportedException ("Can't create an array of the unfinished type '" + elementType + "'.");
+#endif
                        
                        return CreateInstanceImpl (elementType, lengths, bounds);
                }
@@ -758,22 +781,7 @@ namespace System
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static int BinarySearch (Array array, object value)
                {
-                       if (array == null)
-                               throw new ArgumentNullException ("array");
-
-                       if (value == null)
-                               return -1;
-
-                       if (array.Rank > 1)
-                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
-                       if (array.Length == 0)
-                               return -1;
-
-                       if (!(value is IComparable))
-                               throw new ArgumentException (Locale.GetText ("value does not support IComparable."));
-
-                       return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, null);
+                       return BinarySearch (array, value, null);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
@@ -788,41 +796,13 @@ namespace System
                        if (array.Length == 0)
                                return -1;
 
-                       if ((comparer == null) && (value != null) && !(value is IComparable))
-                               throw new ArgumentException (Locale.GetText (
-                                       "comparer is null and value does not support IComparable."));
-
                        return DoBinarySearch (array, array.GetLowerBound (0), array.GetLength (0), value, comparer);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
                public static int BinarySearch (Array array, int index, int length, object value)
                {
-                       if (array == null)
-                               throw new ArgumentNullException ("array");
-
-                       if (array.Rank > 1)
-                               throw new RankException (Locale.GetText ("Only single dimension arrays are supported."));
-
-                       if (index < array.GetLowerBound (0))
-                               throw new ArgumentOutOfRangeException ("index", Locale.GetText (
-                                       "index is less than the lower bound of array."));
-                       if (length < 0)
-                               throw new ArgumentOutOfRangeException ("length", Locale.GetText (
-                                       "Value has to be >= 0."));
-                       // re-ordered to avoid possible integer overflow
-                       if (index > array.GetLowerBound (0) + array.GetLength (0) - length)
-                               throw new ArgumentException (Locale.GetText (
-                                       "index and length do not specify a valid range in array."));
-
-                       if (array.Length == 0)
-                               return -1;
-
-                       if ((value != null) && (!(value is IComparable)))
-                               throw new ArgumentException (Locale.GetText (
-                                       "value does not support IComparable"));
-
-                       return DoBinarySearch (array, index, length, value, null);
+                       return BinarySearch (array, index, length, value, null);
                }
 
                [ReliabilityContractAttribute (Consistency.WillNotCorruptState, Cer.MayFail)]
@@ -848,10 +828,6 @@ namespace System
                        if (array.Length == 0)
                                return -1;
 
-                       if ((comparer == null) && (value != null) && !(value is IComparable))
-                               throw new ArgumentException (Locale.GetText (
-                                       "comparer is null and value does not support IComparable."));
-
                        return DoBinarySearch (array, index, length, value, comparer);
                }
 
@@ -980,12 +956,13 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
@@ -995,17 +972,37 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
                }
 
+               static Exception CreateArrayTypeMismatchException ()
+               {
+                       return new ArrayTypeMismatchException ();
+               }
+
+               static bool CanAssignArrayElement (Type source, Type target)
+               {
+                       if (source.IsValueType)
+                               return source.IsAssignableFrom (target);
+
+                       if (source.IsInterface)
+                               return !target.IsValueType;
+
+                       if (target.IsInterface)
+                               return !source.IsValueType;
+
+                       return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
+               }
+
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
                                         long destinationIndex, long length)
@@ -1134,28 +1131,13 @@ namespace System
                        return lb - 1;
                }
 
-               /* delegate used to swap array elements */
-               delegate void Swapper (int i, int j);
-
-               static Swapper get_swapper (Array array)
-               {
-                       if (array is int[])
-                               return new Swapper (array.int_swapper);
-                       if (array is double[])
-                               return new Swapper (array.double_swapper);
-                       if (array is object[]) {
-                               return new Swapper (array.obj_swapper);
-                       }
-                       return new Swapper (array.slow_swapper);
-               }
-
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Reverse (Array array)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       Reverse (array, array.GetLowerBound (0), array.GetLength (0));
+                       Reverse (array, array.GetLowerBound (0), array.Length);
                }
 
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -1175,45 +1157,119 @@ namespace System
                                throw new ArgumentException ();
 
                        int end = index + length - 1;
-                       object[] oarray = array as object[];
-                       if (oarray != null) {
+                       var et = array.GetType ().GetElementType ();
+                       switch (Type.GetTypeCode (et)) {
+                       case TypeCode.Boolean:
                                while (index < end) {
-                                       object tmp = oarray [index];
-                                       oarray [index] = oarray [end];
-                                       oarray [end] = tmp;
+                                       bool a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       int[] iarray = array as int[];
-                       if (iarray != null) {
+
+                       case TypeCode.Byte:
+                       case TypeCode.SByte:
+                               while (index < end) {
+                                       byte a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.Int16:
+                       case TypeCode.UInt16:
+                       case TypeCode.Char:
                                while (index < end) {
-                                       int tmp = iarray [index];
-                                       iarray [index] = iarray [end];
-                                       iarray [end] = tmp;
+                                       short a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       double[] darray = array as double[];
-                       if (darray != null) {
+
+                       case TypeCode.Int32:
+                       case TypeCode.UInt32:
+                       case TypeCode.Single:
                                while (index < end) {
-                                       double tmp = darray [index];
-                                       darray [index] = darray [end];
-                                       darray [end] = tmp;
+                                       int a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
                                        ++index;
                                        --end;
                                }
                                return;
-                       }
-                       // fallback
-                       Swapper swapper = get_swapper (array);
-                       while (index < end) {
-                               swapper (index, end);
-                               ++index;
-                               --end;
+
+                       case TypeCode.Int64:
+                       case TypeCode.UInt64:
+                       case TypeCode.Double:
+                               while (index < end) {
+                                       long a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.Decimal:
+                               while (index < end) {
+                                       decimal a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+
+                       case TypeCode.String:
+                               while (index < end) {
+                                       object a, b;
+
+                                       array.GetGenericValueImpl (index, out a);
+                                       array.GetGenericValueImpl (end, out b);
+                                       array.SetGenericValueImpl (index, ref b);
+                                       array.SetGenericValueImpl (end, ref a);
+                                       ++index;
+                                       --end;
+                               }
+                               return;
+                       default:
+                               if (array is object[])
+                                       goto case TypeCode.String;
+
+                               // Very slow fallback
+                               while (index < end) {
+                                       object val = array.GetValueImpl (index);
+                                       array.SetValueImpl (array.GetValueImpl (end), index);
+                                       array.SetValueImpl (val, end);
+                                       ++index;
+                                       --end;
+                               }
+
+                               return;
                        }
                }
 
@@ -1388,33 +1444,10 @@ namespace System
                                throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
                        }
                }
-
-               /* note, these are instance methods */
-               void int_swapper (int i, int j) {
-                       int[] array = this as int[];
-                       int val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
-               }
-
-               void obj_swapper (int i, int j) {
-                       object[] array = this as object[];
-                       object val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
-               }
-
-               void slow_swapper (int i, int j) {
-                       object val = GetValueImpl (i);
-                       SetValueImpl (GetValue (j), i);
-                       SetValueImpl (val, j);
-               }
-
-               void double_swapper (int i, int j) {
-                       double[] array = this as double[];
-                       double val = array [i];
-                       array [i] = array [j];
-                       array [j] = val;
+               
+               struct QSortStack {
+                       public int high;
+                       public int low;
                }
                
                static bool QSortArrange (Array keys, Array items, int lo, ref object v0, int hi, ref object v1, IComparer comparer)
@@ -1447,84 +1480,137 @@ namespace System
                        return false;
                }
                
-               private static void qsort (Array keys, Array items, int low, int high, IComparer comparer)
+               private static void qsort (Array keys, Array items, int low0, int high0, IComparer comparer)
                {
-                       //const int QSORT_THRESHOLD = 7;
+                       QSortStack[] stack = new QSortStack[32];
+                       const int QSORT_THRESHOLD = 7;
+                       int high, low, mid, i, k;
                        object key, hi, lo;
                        IComparable cmp;
-                       int mid, i, k;
-                       
-                       // TODO: implement InsertionSort when QSORT_THRESHOLD reached
-                       
-                       // calculate the middle element
-                       mid = low + ((high - low) / 2);
-                       
-                       // get the 3 keys
-                       key = keys.GetValueImpl (mid);
-                       hi = keys.GetValueImpl (high);
-                       lo = keys.GetValueImpl (low);
-                       
-                       // once we re-order the low, mid, and high elements to be in
-                       // ascending order, we'll use mid as our pivot.
-                       QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
-                       if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
-                               QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
+                       int sp = 1;
                        
-                       cmp = key as IComparable;
-                       
-                       // since we've already guaranteed that lo <= mid and mid <= hi,
-                       // we can skip comparing them again.
-                       k = high - 1;
-                       i = low + 1;
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
                        
                        do {
-                               // Move the walls in
-                               if (comparer != null) {
-                                       while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) >= 0)
-                                               i++;
-                                       
-                                       while (k >= i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
-                                               k--;
-                               } else if (cmp != null) {
-                                       while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) >= 0)
-                                               i++;
-                                       
-                                       while (k >= i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
-                                               k--;
-                               } else {
-                                       // This has the effect of moving the null values to the front if comparer is null
-                                       while (i < k && keys.GetValueImpl (i) == null)
-                                               i++;
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
+                               
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       lo = keys.GetValueImpl (k - 1);
+                                                       hi = keys.GetValueImpl (k);
+                                                       if (comparer != null) {
+                                                               if (comparer.Compare (hi, lo) >= 0)
+                                                                       break;
+                                                       } else {
+                                                               if (lo == null)
+                                                                       break;
+                                                               
+                                                               if (hi != null) {
+                                                                       cmp = hi as IComparable;
+                                                                       if (cmp.CompareTo (lo) >= 0)
+                                                                               break;
+                                                               }
+                                                       }
+                                                       
+                                                       swap (keys, items, k - 1, k);
+                                               }
+                                       }
                                        
-                                       while (k >= i && keys.GetValueImpl (k) != null)
-                                               k--;
+                                       continue;
                                }
                                
-                               if (k <= i)
-                                       break;
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
                                
-                               swap (keys, items, i, k);
+                               // get the 3 keys
+                               key = keys.GetValueImpl (mid);
+                               hi = keys.GetValueImpl (high);
+                               lo = keys.GetValueImpl (low);
                                
-                               // make sure we keep track of our pivot element
-                               if (mid == i)
-                                       mid = k;
-                               else if (mid == k)
-                                       mid = i;
+                               // once we re-order the low, mid, and high elements to be in
+                               // ascending order, we'll use mid as our pivot.
+                               QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
+                               if (QSortArrange (keys, items, mid, ref key, high, ref hi, comparer))
+                                       QSortArrange (keys, items, low, ref lo, mid, ref key, comparer);
                                
-                               i++;
-                               k--;
-                       } while (true);
-                       
-                       if (k != mid) {
-                               // swap the pivot with the last element in the first partition
-                               swap (keys, items, mid, k);
-                       }
-                       
-                       // recursively sort each partition
-                       if ((k + 1) < high)
-                               qsort (keys, items, k + 1, high, comparer);
-                       if ((k - 1) > low)
-                               qsort (keys, items, low, k - 1, comparer);
+                               cmp = key as IComparable;
+                               
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again.
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       // Move the walls in
+                                       if (comparer != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && comparer.Compare (key, keys.GetValueImpl (i)) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && comparer.Compare (key, keys.GetValueImpl (k)) < 0)
+                                                       k--;
+                                       } else if (cmp != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && cmp.CompareTo (keys.GetValueImpl (i)) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && cmp.CompareTo (keys.GetValueImpl (k)) < 0)
+                                                       k--;
+                                       } else {
+                                               // This has the effect of moving the null values to the front if comparer is null
+                                               while (i < k && keys.GetValueImpl (i) == null)
+                                                       i++;
+                                               
+                                               while (k > i && keys.GetValueImpl (k) != null)
+                                                       k--;
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap (keys, items, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                               }
+                       } while (sp > 0);
                }
 
                private static void CheckComparerAvailable (Array keys, int low, int high)
@@ -1573,7 +1659,7 @@ namespace System
                        if (array == null)
                                throw new ArgumentNullException ("array");
 
-                       SortImpl<T, T> (array, null, 0, array.Length, comparer);
+                       SortImpl<T> (array, 0, array.Length, comparer);
                }
 
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -1621,7 +1707,7 @@ namespace System
                        if (index + length > array.Length)
                                throw new ArgumentException ();
                                
-                       SortImpl<T, T> (array, null, index, length, comparer);
+                       SortImpl<T> (array, index, length, comparer);
                }
 
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
@@ -1659,7 +1745,9 @@ namespace System
                        // Check for value types which can be sorted without Compare () method
                        //
                        if (comparer == null) {
-#if !BOOTSTRAP_BASIC                           
+                               /* Avoid this when using full-aot to prevent the generation of many unused qsort<K,T> instantiations */
+#if FULL_AOT_RUNTIME
+#if !BOOTSTRAP_BASIC
                                switch (Type.GetTypeCode (typeof (TKey))) {
                                case TypeCode.Int32:
                                        qsort (keys as Int32[], items, low, high);
@@ -1701,6 +1789,7 @@ namespace System
                                        qsort (keys as UInt64[], items, low, high);
                                        return;
                                }
+#endif
 #endif
                                // Using Comparer<TKey> adds a small overload, but with value types it
                                // helps us to not box them.
@@ -1718,6 +1807,79 @@ namespace System
                                //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
                                //}
                }
+
+               // Specialized version for items==null
+               private static void SortImpl<TKey> (TKey [] keys, int index, int length, IComparer<TKey> comparer)
+               {
+                       if (keys.Length <= 1)
+                               return;
+
+                       int low = index;
+                       int high = index + length - 1;
+                       
+                       //
+                       // Check for value types which can be sorted without Compare () method
+                       //
+                       if (comparer == null) {
+#if !BOOTSTRAP_BASIC                           
+                               switch (Type.GetTypeCode (typeof (TKey))) {
+                               case TypeCode.Int32:
+                                       qsort (keys as Int32[], low, high);
+                                       return;
+                               case TypeCode.Int64:
+                                       qsort (keys as Int64[], low, high);
+                                       return;
+                               case TypeCode.Byte:
+                                       qsort (keys as byte[], low, high);
+                                       return;
+                               case TypeCode.Char:
+                                       qsort (keys as char[], low, high);
+                                       return;
+                               case TypeCode.DateTime:
+                                       qsort (keys as DateTime[], low, high);
+                                       return;
+                               case TypeCode.Decimal:
+                                       qsort (keys as decimal[], low, high);
+                                       return;
+                               case TypeCode.Double:
+                                       qsort (keys as double[], low, high);
+                                       return;
+                               case TypeCode.Int16:
+                                       qsort (keys as Int16[], low, high);
+                                       return;
+                               case TypeCode.SByte:
+                                       qsort (keys as SByte[], low, high);
+                                       return;
+                               case TypeCode.Single:
+                                       qsort (keys as Single[], low, high);
+                                       return;
+                               case TypeCode.UInt16:
+                                       qsort (keys as UInt16[], low, high);
+                                       return; 
+                               case TypeCode.UInt32:
+                                       qsort (keys as UInt32[], low, high);
+                                       return;
+                               case TypeCode.UInt64:
+                                       qsort (keys as UInt64[], low, high);
+                                       return;
+                               }
+#endif
+                               // Using Comparer<TKey> adds a small overload, but with value types it
+                               // helps us to not box them.
+                               if (typeof (IComparable<TKey>).IsAssignableFrom (typeof (TKey)) &&
+                                               typeof (TKey).IsValueType)
+                                       comparer = Comparer<TKey>.Default;
+                       }
+
+                       if (comparer == null)
+                               CheckComparerAvailable<TKey> (keys, low, high);
+                       //try {
+                               qsort<TKey> (keys, low, high, comparer);
+                               //} catch (Exception e) {
+                               //throw new InvalidOperationException (Locale.GetText ("The comparer threw an exception."), e);
+                               //}
+               }
                
                public static void Sort<T> (T [] array, Comparison<T> comparison)
                {
@@ -1758,91 +1920,236 @@ namespace System
                        
                        return false;
                }
+
+               // Specialized version for items==null
+               static bool QSortArrange<T> (T [] keys, int lo, int hi) where T : IComparable<T>
+               {
+                       if (keys[lo] != null) {
+                               if (keys[hi] == null || keys[hi].CompareTo (keys[lo]) < 0) {
+                                       swap (keys, lo, hi);
+                                       return true;
+                               }
+                       }
+                       
+                       return false;
+               }
                
-               private static void qsort<T, U> (T[] keys, U[] items, int low, int high) where T : IComparable<T>
+               private static void qsort<T, U> (T[] keys, U[] items, int low0, int high0) where T : IComparable<T>
                {
+                       QSortStack[] stack = new QSortStack[32];
                        const int QSORT_THRESHOLD = 7;
-                       int mid, i, k;
+                       int high, low, mid, i, k;
+                       int sp = 1;
                        T key;
                        
-                       if ((low + QSORT_THRESHOLD) > high) {
-                               // switch to insertion sort
-                               for (i = low + 1; i <= high; i++) {
-                                       for (k = i; k > low; k--) {
-                                               // if keys[k] >= keys[k-1], break
-                                               if (keys[k-1] == null)
-                                                       break;
-                                               
-                                               if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
-                                                       break;
-                                               
-                                               swap (keys, items, k - 1, k);
-                                       }
-                               }
-                               
-                               return;
-                       }
-                       
-                       // calculate the middle element
-                       mid = low + ((high - low) / 2);
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
                        
-                       // once we re-order the lo, mid, and hi elements to be in
-                       // ascending order, we'll use mid as our pivot.
-                       QSortArrange<T, U> (keys, items, low, mid);
-                       if (QSortArrange<T, U> (keys, items, mid, high))
+                       do {
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
+                               
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       // if keys[k] >= keys[k-1], break
+                                                       if (keys[k-1] == null)
+                                                               break;
+                                                       
+                                                       if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
+                                                               break;
+                                                       
+                                                       swap (keys, items, k - 1, k);
+                                               }
+                                       }
+                                       
+                                       continue;
+                               }
+                               
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
+                               
+                               // once we re-order the lo, mid, and hi elements to be in
+                               // ascending order, we'll use mid as our pivot.
                                QSortArrange<T, U> (keys, items, low, mid);
+                               if (QSortArrange<T, U> (keys, items, mid, high))
+                                       QSortArrange<T, U> (keys, items, low, mid);
+                               
+                               key = keys[mid];
+                               
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       if (key != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && key.CompareTo (keys[i]) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && key.CompareTo (keys[k]) < 0)
+                                                       k--;
+                                       } else {
+                                               while (i < k && keys[i] == null)
+                                                       i++;
+                                               
+                                               while (k > i && keys[k] != null)
+                                                       k--;
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap (keys, items, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                               }
+                       } while (sp > 0);
+               }               
+
+               // Specialized version for items==null
+               private static void qsort<T> (T[] keys, int low0, int high0) where T : IComparable<T>
+               {
+                       QSortStack[] stack = new QSortStack[32];
+                       const int QSORT_THRESHOLD = 7;
+                       int high, low, mid, i, k;
+                       int sp = 1;
+                       T key;
                        
-                       key = keys[mid];
-                       
-                       // since we've already guaranteed that lo <= mid and mid <= hi,
-                       // we can skip comparing them again
-                       k = high - 1;
-                       i = low + 1;
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
                        
                        do {
-                               if (key != null) {
-                                       // find the first element with a value > pivot value
-                                       while (i < k && key.CompareTo (keys[i]) >= 0)
-                                               i++;
-                                       
-                                       // find the last element with a value <= pivot value
-                                       while (k >= i && key.CompareTo (keys[k]) < 0)
-                                               k--;
-                               } else {
-                                       while (i < k && keys[i] == null)
-                                               i++;
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
+                               
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       // if keys[k] >= keys[k-1], break
+                                                       if (keys[k-1] == null)
+                                                               break;
+                                                       
+                                                       if (keys[k] != null && keys[k].CompareTo (keys[k-1]) >= 0)
+                                                               break;
+                                                       
+                                                       swap (keys, k - 1, k);
+                                               }
+                                       }
                                        
-                                       while (k >= i && keys[k] != null)
-                                               k--;
+                                       continue;
                                }
                                
-                               if (k <= i)
-                                       break;
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
                                
-                               swap (keys, items, i, k);
+                               // once we re-order the lo, mid, and hi elements to be in
+                               // ascending order, we'll use mid as our pivot.
+                               QSortArrange<T> (keys, low, mid);
+                               if (QSortArrange<T> (keys, mid, high))
+                                       QSortArrange<T> (keys, low, mid);
                                
-                               // make sure we keep track of our pivot element
-                               if (mid == i)
-                                       mid = k;
-                               else if (mid == k)
-                                       mid = i;
+                               key = keys[mid];
                                
-                               i++;
-                               k--;
-                       } while (true);
-                       
-                       if (k != mid) {
-                               // swap the pivot with the last element in the first partition
-                               swap (keys, items, mid, k);
-                       }
-                       
-                       // recursively sort each partition
-                       if ((k + 1) < high)
-                               qsort (keys, items, k + 1, high);
-                       
-                       if ((k - 1) > low)
-                               qsort (keys, items, low, k - 1);
-               }               
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       if (key != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && key.CompareTo (keys[i]) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k >= i && key.CompareTo (keys[k]) < 0)
+                                                       k--;
+                                       } else {
+                                               while (i < k && keys[i] == null)
+                                                       i++;
+                                               
+                                               while (k >= i && keys[k] != null)
+                                                       k--;
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap (keys, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                               }
+                       } while (sp > 0);
+               }
                
                static bool QSortArrange<K, V> (K [] keys, V [] items, int lo, int hi, IComparer<K> comparer)
                {
@@ -1883,120 +2190,337 @@ namespace System
                        
                        return false;
                }
+
+               // Specialized version for items==null
+               static bool QSortArrange<K> (K [] keys, int lo, int hi, IComparer<K> comparer)
+               {
+                       IComparable<K> gcmp;
+                       IComparable cmp;
+                       
+                       if (comparer != null) {
+                               if (comparer.Compare (keys[hi], keys[lo]) < 0) {
+                                       swap<K> (keys, lo, hi);
+                                       return true;
+                               }
+                       } else if (keys[lo] != null) {
+                               if (keys[hi] == null) {
+                                       swap<K> (keys, lo, hi);
+                                       return true;
+                               }
+                               
+                               gcmp = keys[hi] as IComparable<K>;
+                               if (gcmp != null) {
+                                       if (gcmp.CompareTo (keys[lo]) < 0) {
+                                               swap<K> (keys, lo, hi);
+                                               return true;
+                                       }
+                                       
+                                       return false;
+                               }
+                               
+                               cmp = keys[hi] as IComparable;
+                               if (cmp != null) {
+                                       if (cmp.CompareTo (keys[lo]) < 0) {
+                                               swap<K> (keys, lo, hi);
+                                               return true;
+                                       }
+                                       
+                                       return false;
+                               }
+                       }
+                       
+                       return false;
+               }
                
-               private static void qsort<K, V> (K [] keys, V [] items, int low, int high, IComparer<K> comparer)
+               private static void qsort<K, V> (K [] keys, V [] items, int low0, int high0, IComparer<K> comparer)
                {
+                       QSortStack[] stack = new QSortStack[32];
                        const int QSORT_THRESHOLD = 7;
+                       int high, low, mid, i, k;
                        IComparable<K> gcmp;
                        IComparable cmp;
-                       int mid, i, k;
+                       int sp = 1;
                        K key;
                        
-                       if ((low + QSORT_THRESHOLD) > high) {
-                               // switch to insertion sort
-                               for (i = low + 1; i <= high; i++) {
-                                       for (k = i; k > low; k--) {
-                                               // if keys[k] >= keys[k-1], break
-                                               if (comparer != null) {
-                                                       if (comparer.Compare (keys[k], keys[k-1]) >= 0)
-                                                               break;
-                                               } else {
-                                                       if (keys[k-1] == null)
-                                                               break;
-                                                       
-                                                       if (keys[k] != null) {
-                                                               gcmp = keys[k] as IComparable<K>;
-                                                               cmp = keys[k] as IComparable;
-                                                               if (gcmp != null) {
-                                                                       if (gcmp.CompareTo (keys[k-1]) >= 0)
-                                                                               break;
-                                                               } else {
-                                                                       if (cmp.CompareTo (keys[k-1]) >= 0)
-                                                                               break;
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
+                       
+                       do {
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
+                               
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       // if keys[k] >= keys[k-1], break
+                                                       if (comparer != null) {
+                                                               if (comparer.Compare (keys[k], keys[k-1]) >= 0)
+                                                                       break;
+                                                       } else {
+                                                               if (keys[k-1] == null)
+                                                                       break;
+                                                               
+                                                               if (keys[k] != null) {
+                                                                       gcmp = keys[k] as IComparable<K>;
+                                                                       cmp = keys[k] as IComparable;
+                                                                       if (gcmp != null) {
+                                                                               if (gcmp.CompareTo (keys[k-1]) >= 0)
+                                                                                       break;
+                                                                       } else {
+                                                                               if (cmp.CompareTo (keys[k-1]) >= 0)
+                                                                                       break;
+                                                                       }
                                                                }
                                                        }
+                                                       
+                                                       swap<K, V> (keys, items, k - 1, k);
                                                }
-                                               
-                                               swap<K, V> (keys, items, k - 1, k);
                                        }
+                                       
+                                       continue;
                                }
                                
-                               return;
-                       }
-                       
-                       // calculate the middle element
-                       mid = low + ((high - low) / 2);
-                       
-                       // once we re-order the low, mid, and high elements to be in
-                       // ascending order, we'll use mid as our pivot.
-                       QSortArrange<K, V> (keys, items, low, mid, comparer);
-                       if (QSortArrange<K, V> (keys, items, mid, high, comparer))
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
+                               
+                               // once we re-order the low, mid, and high elements to be in
+                               // ascending order, we'll use mid as our pivot.
                                QSortArrange<K, V> (keys, items, low, mid, comparer);
-                       
-                       key = keys[mid];
-                       gcmp = key as IComparable<K>;
-                       cmp = key as IComparable;
-                       
-                       // since we've already guaranteed that lo <= mid and mid <= hi,
-                       // we can skip comparing them again.
-                       k = high - 1;
-                       i = low + 1;
-                       
-                       do {
-                               // Move the walls in
-                               if (comparer != null) {
-                                       while (i < k && comparer.Compare (key, keys[i]) >= 0)
-                                               i++;
-                                       
-                                       while (k >= i && comparer.Compare (key, keys[k]) < 0)
-                                               k--;
-                               } else {
-                                       if (gcmp != null) {
-                                               while (i < k && gcmp.CompareTo (keys[i]) >= 0)
-                                                       i++;
-                                               
-                                               while (k >= i && gcmp.CompareTo (keys[k]) < 0)
-                                                       k--;
-                                       } else if (cmp != null) {
-                                               while (i < k && cmp.CompareTo (keys[i]) >= 0)
+                               if (QSortArrange<K, V> (keys, items, mid, high, comparer))
+                                       QSortArrange<K, V> (keys, items, low, mid, comparer);
+                               
+                               key = keys[mid];
+                               gcmp = key as IComparable<K>;
+                               cmp = key as IComparable;
+                               
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again.
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       // Move the walls in
+                                       if (comparer != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && comparer.Compare (key, keys[i]) > 0)
                                                        i++;
                                                
-                                               while (k >= i && cmp.CompareTo (keys[k]) < 0)
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && comparer.Compare (key, keys[k]) < 0)
                                                        k--;
                                        } else {
-                                               while (i < k && keys[i] == null)
-                                                       i++;
-                                               
-                                               while (k >= i && keys[k] != null)
-                                                       k--;
+                                               if (gcmp != null) {
+                                                       // find the first element with a value >= pivot value
+                                                       while (i < k && gcmp.CompareTo (keys[i]) > 0)
+                                                               i++;
+                                                       
+                                                       // find the last element with a value <= pivot value
+                                                       while (k > i && gcmp.CompareTo (keys[k]) < 0)
+                                                               k--;
+                                               } else if (cmp != null) {
+                                                       // find the first element with a value >= pivot value
+                                                       while (i < k && cmp.CompareTo (keys[i]) > 0)
+                                                               i++;
+                                                       
+                                                       // find the last element with a value <= pivot value
+                                                       while (k > i && cmp.CompareTo (keys[k]) < 0)
+                                                               k--;
+                                               } else {
+                                                       while (i < k && keys[i] == null)
+                                                               i++;
+                                                       
+                                                       while (k > i && keys[k] != null)
+                                                               k--;
+                                               }
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap<K, V> (keys, items, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
                                        }
                                }
+                       } while (sp > 0);
+               }
+
+               // Specialized version for items==null
+               private static void qsort<K> (K [] keys, int low0, int high0, IComparer<K> comparer)
+               {
+                       QSortStack[] stack = new QSortStack[32];
+                       const int QSORT_THRESHOLD = 7;
+                       int high, low, mid, i, k;
+                       IComparable<K> gcmp;
+                       IComparable cmp;
+                       int sp = 1;
+                       K key;
+                       
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
+                       
+                       do {
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
                                
-                               if (k <= i)
-                                       break;
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       // if keys[k] >= keys[k-1], break
+                                                       if (comparer != null) {
+                                                               if (comparer.Compare (keys[k], keys[k-1]) >= 0)
+                                                                       break;
+                                                       } else {
+                                                               if (keys[k-1] == null)
+                                                                       break;
+                                                               
+                                                               if (keys[k] != null) {
+                                                                       gcmp = keys[k] as IComparable<K>;
+                                                                       cmp = keys[k] as IComparable;
+                                                                       if (gcmp != null) {
+                                                                               if (gcmp.CompareTo (keys[k-1]) >= 0)
+                                                                                       break;
+                                                                       } else {
+                                                                               if (cmp.CompareTo (keys[k-1]) >= 0)
+                                                                                       break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       
+                                                       swap<K> (keys, k - 1, k);
+                                               }
+                                       }
+                                       
+                                       continue;
+                               }
                                
-                               swap<K, V> (keys, items, i, k);
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
                                
-                               // make sure we keep track of our pivot element
-                               if (mid == i)
-                                       mid = k;
-                               else if (mid == k)
-                                       mid = i;
+                               // once we re-order the low, mid, and high elements to be in
+                               // ascending order, we'll use mid as our pivot.
+                               QSortArrange<K> (keys, low, mid, comparer);
+                               if (QSortArrange<K> (keys, mid, high, comparer))
+                                       QSortArrange<K> (keys, low, mid, comparer);
                                
-                               i++;
-                               k--;
-                       } while (true);
-                       
-                       if (k != mid) {
-                               // swap the pivot with the last element in the first partition
-                               swap<K, V> (keys, items, mid, k);
-                       }
-                       
-                       // recursively sort each partition
-                       if ((k + 1) < high)
-                               qsort<K, V> (keys, items, k + 1, high, comparer);
-                       if ((k - 1) > low)
-                               qsort<K, V> (keys, items, low, k - 1, comparer);
+                               key = keys[mid];
+                               gcmp = key as IComparable<K>;
+                               cmp = key as IComparable;
+                               
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again.
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       // Move the walls in
+                                       if (comparer != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && comparer.Compare (key, keys[i]) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && comparer.Compare (key, keys[k]) < 0)
+                                                       k--;
+                                       } else {
+                                               if (gcmp != null) {
+                                                       // find the first element with a value >= pivot value
+                                                       while (i < k && gcmp.CompareTo (keys[i]) > 0)
+                                                               i++;
+                                                       
+                                                       // find the last element with a value <= pivot value
+                                                       while (k > i && gcmp.CompareTo (keys[k]) < 0)
+                                                               k--;
+                                               } else if (cmp != null) {
+                                                       // find the first element with a value >= pivot value
+                                                       while (i < k && cmp.CompareTo (keys[i]) > 0)
+                                                               i++;
+                                                       
+                                                       // find the last element with a value <= pivot value
+                                                       while (k > i && cmp.CompareTo (keys[k]) < 0)
+                                                               k--;
+                                               } else {
+                                                       while (i < k && keys[i] == null)
+                                                               i++;
+                                                       
+                                                       while (k > i && keys[k] != null)
+                                                               k--;
+                                               }
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap<K> (keys, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                               }
+                       } while (sp > 0);
                }
                
                static bool QSortArrange<T> (T [] array, int lo, int hi, Comparison<T> compare)
@@ -2011,90 +2535,109 @@ namespace System
                        return false;
                }
                
-               private static void qsort<T> (T [] array, int low, int high, Comparison<T> compare)
+               private static void qsort<T> (T [] array, int low0, int high0, Comparison<T> compare)
                {
+                       QSortStack[] stack = new QSortStack[32];
                        const int QSORT_THRESHOLD = 7;
-                       int mid, i, k;
+                       int high, low, mid, i, k;
+                       int sp = 1;
                        T key;
                        
-                       if ((low + QSORT_THRESHOLD) > high) {
-                               // switch to insertion sort
-                               for (i = low + 1; i <= high; i++) {
-                                       for (k = i; k > low; k--) {
-                                               // if keys[k] >= keys[k-1], break
-                                               if (array[k-1] == null)
-                                                       break;
-                                               
-                                               if (array[k] != null && compare (array[k], array[k-1]) >= 0)
-                                                       break;
-                                               
-                                               swap<T> (array, k - 1, k);
-                                       }
-                               }
-                               
-                               return;
-                       }
-                       
-                       // calculate the middle element
-                       mid = low + ((high - low) / 2);
-                       
-                       // once we re-order the lo, mid, and hi elements to be in
-                       // ascending order, we'll use mid as our pivot.
-                       QSortArrange<T> (array, low, mid, compare);
-                       if (QSortArrange<T> (array, mid, high, compare))
-                               QSortArrange<T> (array, low, mid, compare);
-                       
-                       key = array[mid];
-                       
-                       // since we've already guaranteed that lo <= mid and mid <= hi,
-                       // we can skip comparing them again
-                       k = high - 1;
-                       i = low + 1;
+                       // initialize our stack
+                       stack[0].high = high0;
+                       stack[0].low = low0;
                        
                        do {
-                               // Move the walls in
-                               if (key != null) {
-                                       // find the first element with a value > pivot value
-                                       while (i < k && compare (key, array[i]) >= 0)
-                                               i++;
-                                       
-                                       // find the last element with a value <= pivot value
-                                       while (k >= i && compare (key, array[k]) < 0)
-                                               k--;
-                               } else {
-                                       while (i < k && array[i] == null)
-                                               i++;
+                               // pop the stack
+                               sp--;
+                               high = stack[sp].high;
+                               low = stack[sp].low;
+                               
+                               if ((low + QSORT_THRESHOLD) > high) {
+                                       // switch to insertion sort
+                                       for (i = low + 1; i <= high; i++) {
+                                               for (k = i; k > low; k--) {
+                                                       if (compare (array[k], array[k-1]) >= 0)
+                                                               break;
+                                                       
+                                                       swap<T> (array, k - 1, k);
+                                               }
+                                       }
                                        
-                                       while (k >= i && array[k] != null)
-                                               k--;
+                                       continue;
                                }
                                
-                               if (k <= i)
-                                       break;
+                               // calculate the middle element
+                               mid = low + ((high - low) / 2);
                                
-                               swap<T> (array, i, k);
+                               // once we re-order the lo, mid, and hi elements to be in
+                               // ascending order, we'll use mid as our pivot.
+                               QSortArrange<T> (array, low, mid, compare);
+                               if (QSortArrange<T> (array, mid, high, compare))
+                                       QSortArrange<T> (array, low, mid, compare);
                                
-                               // make sure we keep track of our pivot element
-                               if (mid == i)
-                                       mid = k;
-                               else if (mid == k)
-                                       mid = i;
+                               key = array[mid];
                                
-                               i++;
-                               k--;
-                       } while (true);
-                       
-                       if (k != mid) {
-                               // swap the pivot with the last element in the first partition
-                               swap<T> (array, mid, k);
-                       }
-                       
-                       // recursively sort each partition
-                       if ((k + 1) < high)
-                               qsort<T> (array, k + 1, high, compare);
-                       
-                       if ((k - 1) > low)
-                               qsort<T> (array, low, k - 1, compare);
+                               // since we've already guaranteed that lo <= mid and mid <= hi,
+                               // we can skip comparing them again
+                               k = high - 1;
+                               i = low + 1;
+                               
+                               do {
+                                       // Move the walls in
+                                       if (key != null) {
+                                               // find the first element with a value >= pivot value
+                                               while (i < k && compare (key, array[i]) > 0)
+                                                       i++;
+                                               
+                                               // find the last element with a value <= pivot value
+                                               while (k > i && compare (key, array[k]) < 0)
+                                                       k--;
+                                       } else {
+                                               while (i < k && array[i] == null)
+                                                       i++;
+                                               
+                                               while (k > i && array[k] != null)
+                                                       k--;
+                                       }
+                                       
+                                       if (k <= i)
+                                               break;
+                                       
+                                       swap<T> (array, i, k);
+                                       
+                                       i++;
+                                       k--;
+                               } while (true);
+                               
+                               // push our partitions onto the stack, largest first
+                               // (to make sure we don't run out of stack space)
+                               if ((high - k) >= (k - low)) {
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                               } else {
+                                       if ((k - 1) > low) {
+                                               stack[sp].high = k;
+                                               stack[sp].low = low;
+                                               sp++;
+                                       }
+                                       
+                                       if ((k + 1) < high) {
+                                               stack[sp].high = high;
+                                               stack[sp].low = k;
+                                               sp++;
+                                       }
+                               }
+                       } while (sp > 0);
                }
 
                private static void CheckComparerAvailable<K> (K [] keys, int low, int high)
@@ -2112,6 +2655,7 @@ namespace System
                        }
                }
 
+               [MethodImpl ((MethodImplOptions)256)]
                private static void swap<K, V> (K [] keys, V [] items, int i, int j)
                {
                        K tmp;
@@ -2128,6 +2672,7 @@ namespace System
                        }
                }
 
+               [MethodImpl ((MethodImplOptions)256)]
                private static void swap<T> (T [] array, int i, int j)
                {
                        T tmp = array [i];
@@ -2222,20 +2767,27 @@ namespace System
                public static void Resize<T> (ref T [] array, int newSize)
                {
                        if (newSize < 0)
-                               throw new ArgumentOutOfRangeException ();
+                               throw new ArgumentOutOfRangeException ("newSize");
                        
                        if (array == null) {
                                array = new T [newSize];
                                return;
                        }
 
-                       int length = array.Length;
+                       var arr = array;
+                       int length = arr.Length;
                        if (length == newSize)
                                return;
                        
                        T [] a = new T [newSize];
-                       if (length != 0)
-                               FastCopy (array, 0, a, 0, Math.Min (newSize, length));
+                       int tocopy = Math.Min (newSize, length);
+
+                       if (tocopy < 9) {
+                               for (int i = 0; i < tocopy; ++i)
+                                       UnsafeStore (a, i, UnsafeLoad (arr, i));
+                       } else {
+                               FastCopy (arr, 0, a, 0, tocopy);
+                       }
                        array = a;
                }
                
@@ -2282,32 +2834,54 @@ namespace System
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindLastIndex<T> (array, 0, array.Length, match);
+                       return GetLastIndex (array, 0, array.Length, match);
                }
                
                public static int FindLastIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ();
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindLastIndex<T> (array, startIndex, array.Length - startIndex, match);
+                       return GetLastIndex (array, 0, startIndex + 1, match);
                }
                
                public static int FindLastIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
                        if (match == null)
                                throw new ArgumentNullException ("match");
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
                        
-                       if (startIndex > array.Length || startIndex + count > array.Length)
-                               throw new ArgumentOutOfRangeException ();
-                       
-                       for (int i = startIndex + count - 1; i >= startIndex; i--)
-                               if (match (array [i]))
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if (startIndex - count + 1 < 0)
+                               throw new ArgumentOutOfRangeException ("count must refer to a location within the array");
+
+                       return GetLastIndex (array, startIndex - count + 1, count, match);
+               }
+
+               internal static int GetLastIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+               {
+                       // unlike FindLastIndex, takes regular params for search range
+                       for (int i = startIndex + count; i != startIndex;)
+                               if (match (array [--i]))
                                        return i;
-                               
+
                        return -1;
                }
                
@@ -2315,16 +2889,25 @@ namespace System
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
                        
-                       return FindIndex<T> (array, 0, array.Length, match);
+                       return GetIndex (array, 0, array.Length, match);
                }
                
                public static int FindIndex<T> (T [] array, int startIndex, Predicate<T> match)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
-                       
-                       return FindIndex<T> (array, startIndex, array.Length - startIndex, match);
+
+                       if (startIndex < 0 || (uint) startIndex > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("startIndex");
+
+                       if (match == null)
+                               throw new ArgumentNullException ("match");
+
+                       return GetIndex (array, startIndex, array.Length - startIndex, match);
                }
                
                public static int FindIndex<T> (T [] array, int startIndex, int count, Predicate<T> match)
@@ -2332,13 +2915,22 @@ namespace System
                        if (array == null)
                                throw new ArgumentNullException ("array");
                        
-                       if (match == null)
-                               throw new ArgumentNullException ("match");
+                       if (startIndex < 0)
+                               throw new ArgumentOutOfRangeException ("startIndex");
                        
-                       if (startIndex > array.Length || startIndex + count > array.Length)
-                               throw new ArgumentOutOfRangeException ();
-                       
-                       for (int i = startIndex; i < startIndex + count; i ++)
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count");
+
+                       if ((uint) startIndex + (uint) count > (uint) array.Length)
+                               throw new ArgumentOutOfRangeException ("index and count exceed length of list");
+
+                       return GetIndex (array, startIndex, count, match);
+               }
+
+               internal static int GetIndex<T> (T[] array, int startIndex, int count, Predicate<T> match)
+               {
+                       int end = startIndex + count;
+                       for (int i = startIndex; i < end; i ++)
                                if (match (array [i]))
                                        return i;
                                
@@ -2394,11 +2986,12 @@ namespace System
                                while (iMin <= iMax) {
                                        // Be careful with overflows
                                        int iMid = iMin + ((iMax - iMin) / 2);
-                                       iCmp = comparer.Compare (value, array [iMid]);
+                                       iCmp = comparer.Compare (array [iMid], value);
 
                                        if (iCmp == 0)
                                                return iMid;
-                                       else if (iCmp < 0)
+
+                                       if (iCmp > 0)
                                                iMax = iMid - 1;
                                        else
                                                iMin = iMid + 1; // compensate for the rounding down
@@ -2560,5 +3153,13 @@ namespace System
                {
                        Copy (sourceArray, sourceIndex, destinationArray, destinationIndex, length);
                }
+
+               internal static T UnsafeLoad<T> (T[] array, int index) {
+                       return array [index];
+               }
+
+               internal static void UnsafeStore<T> (T[] array, int index, T value) {
+                       array [index] = value;
+               }
        }
 }