8026701: Array.prototype.splice is slow on dense arrays

Thu, 17 Oct 2013 17:33:16 +0200

author
hannesw
date
Thu, 17 Oct 2013 17:33:16 +0200
changeset 633
a2065f67857c
parent 632
b01a10c7c7c2
child 634
66d27c77b455

8026701: Array.prototype.splice is slow on dense arrays
Reviewed-by: lagergren, sundar, jlaskey

src/jdk/nashorn/internal/objects/NativeArray.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/ScriptObject.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ArrayData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java file | annotate | diff | comparison | revisions
test/examples/array-micro.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8026701.js file | annotate | diff | comparison | revisions
test/script/basic/JDK-8026701.js.EXPECTED file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/objects/NativeArray.java	Thu Oct 17 12:38:50 2013 +0200
     1.2 +++ b/src/jdk/nashorn/internal/objects/NativeArray.java	Thu Oct 17 17:33:16 2013 +0200
     1.3 @@ -1007,19 +1007,42 @@
     1.4          final long actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);
     1.5          final long actualDeleteCount = Math.min(Math.max(JSType.toLong(deleteCount), 0), len - actualStart);
     1.6  
     1.7 -        final NativeArray array = new NativeArray(actualDeleteCount);
     1.8 +        NativeArray returnValue;
     1.9  
    1.10 -        for (long k = 0; k < actualDeleteCount; k++) {
    1.11 -            final long from = actualStart + k;
    1.12 +        if (actualStart <= Integer.MAX_VALUE && actualDeleteCount <= Integer.MAX_VALUE && bulkable(sobj)) {
    1.13 +            try {
    1.14 +                returnValue =  new NativeArray(sobj.getArray().fastSplice((int)actualStart, (int)actualDeleteCount, items.length));
    1.15 +
    1.16 +                // Since this is a dense bulkable array we can use faster defineOwnProperty to copy new elements
    1.17 +                int k = (int) actualStart;
    1.18 +                for (int i = 0; i < items.length; i++, k++) {
    1.19 +                    sobj.defineOwnProperty(k, items[i]);
    1.20 +                }
    1.21 +            } catch (UnsupportedOperationException uoe) {
    1.22 +                returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len);
    1.23 +            }
    1.24 +        } else {
    1.25 +            returnValue = slowSplice(sobj, actualStart, actualDeleteCount, items, len);
    1.26 +        }
    1.27 +
    1.28 +        return returnValue;
    1.29 +    }
    1.30 +
    1.31 +    private static NativeArray slowSplice(final ScriptObject sobj, final long start, final long deleteCount, final Object[] items, final long len) {
    1.32 +
    1.33 +        final NativeArray array = new NativeArray(deleteCount);
    1.34 +
    1.35 +        for (long k = 0; k < deleteCount; k++) {
    1.36 +            final long from = start + k;
    1.37  
    1.38              if (sobj.has(from)) {
    1.39                  array.defineOwnProperty(ArrayIndex.getArrayIndex(k), sobj.get(from));
    1.40              }
    1.41          }
    1.42  
    1.43 -        if (items.length < actualDeleteCount) {
    1.44 -            for (long k = actualStart; k < (len - actualDeleteCount); k++) {
    1.45 -                final long from = k + actualDeleteCount;
    1.46 +        if (items.length < deleteCount) {
    1.47 +            for (long k = start; k < (len - deleteCount); k++) {
    1.48 +                final long from = k + deleteCount;
    1.49                  final long to   = k + items.length;
    1.50  
    1.51                  if (sobj.has(from)) {
    1.52 @@ -1029,12 +1052,12 @@
    1.53                  }
    1.54              }
    1.55  
    1.56 -            for (long k = len; k > (len - actualDeleteCount + items.length); k--) {
    1.57 +            for (long k = len; k > (len - deleteCount + items.length); k--) {
    1.58                  sobj.delete(k - 1, true);
    1.59              }
    1.60 -        } else if (items.length > actualDeleteCount) {
    1.61 -            for (long k = len - actualDeleteCount; k > actualStart; k--) {
    1.62 -                final long from = k + actualDeleteCount - 1;
    1.63 +        } else if (items.length > deleteCount) {
    1.64 +            for (long k = len - deleteCount; k > start; k--) {
    1.65 +                final long from = k + deleteCount - 1;
    1.66                  final long to   = k + items.length - 1;
    1.67  
    1.68                  if (sobj.has(from)) {
    1.69 @@ -1046,12 +1069,12 @@
    1.70              }
    1.71          }
    1.72  
    1.73 -        long k = actualStart;
    1.74 +        long k = start;
    1.75          for (int i = 0; i < items.length; i++, k++) {
    1.76              sobj.set(k, items[i], true);
    1.77          }
    1.78  
    1.79 -        final long newLength = len - actualDeleteCount + items.length;
    1.80 +        final long newLength = len - deleteCount + items.length;
    1.81          sobj.set("length", newLength, true);
    1.82  
    1.83          return array;
     2.1 --- a/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Oct 17 12:38:50 2013 +0200
     2.2 +++ b/src/jdk/nashorn/internal/runtime/ScriptObject.java	Thu Oct 17 17:33:16 2013 +0200
     2.3 @@ -594,7 +594,7 @@
     2.4       * @param index key for property
     2.5       * @param value value to define
     2.6       */
     2.7 -    protected final void defineOwnProperty(final int index, final Object value) {
     2.8 +    public final void defineOwnProperty(final int index, final Object value) {
     2.9          assert isValidArrayIndex(index) : "invalid array index";
    2.10          final long longIndex = ArrayIndex.toLongIndex(index);
    2.11          if (longIndex >= getArray().length()) {
     3.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Oct 17 12:38:50 2013 +0200
     3.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ArrayData.java	Thu Oct 17 17:33:16 2013 +0200
     3.3 @@ -461,7 +461,23 @@
     3.4       */
     3.5      public abstract ArrayData slice(long from, long to);
     3.6  
     3.7 -    private static Class<?> widestType(final Object... items) {
     3.8 +    /**
     3.9 +     * Fast splice operation. This just modifies the array according to the number of
    3.10 +     * elements added and deleted but does not insert the added elements. Throws
    3.11 +     * {@code UnsupportedOperationException} if fast splice operation is not supported
    3.12 +     * for this class or arguments.
    3.13 +     *
    3.14 +     * @param start start index of splice operation
    3.15 +     * @param removed number of removed elements
    3.16 +     * @param added number of added elements
    3.17 +     * @throws UnsupportedOperationException if fast splice is not supported for the class or arguments.
    3.18 +     */
    3.19 +    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
    3.20 +        throw new UnsupportedOperationException();
    3.21 +    }
    3.22 +
    3.23 +
    3.24 +    static Class<?> widestType(final Object... items) {
    3.25          assert items.length > 0;
    3.26  
    3.27          Class<?> widest = Integer.class;
     4.1 --- a/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Thu Oct 17 12:38:50 2013 +0200
     4.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/IntArrayData.java	Thu Oct 17 17:33:16 2013 +0200
     4.3 @@ -269,4 +269,32 @@
     4.4  
     4.5          return new IntArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     4.6      }
     4.7 +
     4.8 +    @Override
     4.9 +    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
    4.10 +        final long oldLength = length();
    4.11 +        final long newLength = oldLength - removed + added;
    4.12 +        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
    4.13 +            throw new UnsupportedOperationException();
    4.14 +        }
    4.15 +        final ArrayData returnValue = (removed == 0) ?
    4.16 +                EMPTY_ARRAY : new IntArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
    4.17 +
    4.18 +        if (newLength != oldLength) {
    4.19 +            final int[] newArray;
    4.20 +
    4.21 +            if (newLength > array.length) {
    4.22 +                newArray = new int[ArrayData.nextSize((int)newLength)];
    4.23 +                System.arraycopy(array, 0, newArray, 0, start);
    4.24 +            } else {
    4.25 +                newArray = array;
    4.26 +            }
    4.27 +
    4.28 +            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
    4.29 +            array = newArray;
    4.30 +            setLength(newLength);
    4.31 +        }
    4.32 +
    4.33 +        return returnValue;
    4.34 +    }
    4.35  }
     5.1 --- a/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Thu Oct 17 12:38:50 2013 +0200
     5.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/LongArrayData.java	Thu Oct 17 17:33:16 2013 +0200
     5.3 @@ -92,7 +92,7 @@
     5.4  
     5.5      @Override
     5.6      public ArrayData convert(final Class<?> type) {
     5.7 -        if (type == Long.class) {
     5.8 +        if (type == Integer.class || type == Long.class) {
     5.9              return this;
    5.10          }
    5.11          final int length = (int) length();
    5.12 @@ -238,4 +238,32 @@
    5.13          final long newLength = to - start;
    5.14          return new LongArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
    5.15      }
    5.16 +
    5.17 +    @Override
    5.18 +    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
    5.19 +        final long oldLength = length();
    5.20 +        final long newLength = oldLength - removed + added;
    5.21 +        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
    5.22 +            throw new UnsupportedOperationException();
    5.23 +        }
    5.24 +        final ArrayData returnValue = (removed == 0) ?
    5.25 +                EMPTY_ARRAY : new LongArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
    5.26 +
    5.27 +        if (newLength != oldLength) {
    5.28 +            final long[] newArray;
    5.29 +
    5.30 +            if (newLength > array.length) {
    5.31 +                newArray = new long[ArrayData.nextSize((int)newLength)];
    5.32 +                System.arraycopy(array, 0, newArray, 0, start);
    5.33 +            } else {
    5.34 +                newArray = array;
    5.35 +            }
    5.36 +
    5.37 +            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
    5.38 +            array = newArray;
    5.39 +            setLength(newLength);
    5.40 +        }
    5.41 +
    5.42 +        return returnValue;
    5.43 +    }
    5.44  }
     6.1 --- a/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Thu Oct 17 12:38:50 2013 +0200
     6.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/NumberArrayData.java	Thu Oct 17 17:33:16 2013 +0200
     6.3 @@ -218,4 +218,32 @@
     6.4          final long newLength = to - start;
     6.5          return new NumberArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     6.6      }
     6.7 +
     6.8 +    @Override
     6.9 +    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
    6.10 +        final long oldLength = length();
    6.11 +        final long newLength = oldLength - removed + added;
    6.12 +        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
    6.13 +            throw new UnsupportedOperationException();
    6.14 +        }
    6.15 +        final ArrayData returnValue = (removed == 0) ?
    6.16 +                EMPTY_ARRAY : new NumberArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
    6.17 +
    6.18 +        if (newLength != oldLength) {
    6.19 +            final double[] newArray;
    6.20 +
    6.21 +            if (newLength > array.length) {
    6.22 +                newArray = new double[ArrayData.nextSize((int)newLength)];
    6.23 +                System.arraycopy(array, 0, newArray, 0, start);
    6.24 +            } else {
    6.25 +                newArray = array;
    6.26 +            }
    6.27 +
    6.28 +            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
    6.29 +            array = newArray;
    6.30 +            setLength(newLength);
    6.31 +        }
    6.32 +
    6.33 +        return returnValue;
    6.34 +    }
    6.35  }
     7.1 --- a/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Thu Oct 17 12:38:50 2013 +0200
     7.2 +++ b/src/jdk/nashorn/internal/runtime/arrays/ObjectArrayData.java	Thu Oct 17 17:33:16 2013 +0200
     7.3 @@ -206,4 +206,32 @@
     7.4          final long newLength = to - start;
     7.5          return new ObjectArrayData(Arrays.copyOfRange(array, (int)from, (int)to), (int)newLength);
     7.6      }
     7.7 +
     7.8 +    @Override
     7.9 +    public ArrayData fastSplice(final int start, final int removed, final int added) throws UnsupportedOperationException {
    7.10 +        final long oldLength = length();
    7.11 +        final long newLength = oldLength - removed + added;
    7.12 +        if (newLength > SparseArrayData.MAX_DENSE_LENGTH && newLength > array.length) {
    7.13 +            throw new UnsupportedOperationException();
    7.14 +        }
    7.15 +        final ArrayData returnValue = (removed == 0) ?
    7.16 +                EMPTY_ARRAY : new ObjectArrayData(Arrays.copyOfRange(array, start, start + removed), removed);
    7.17 +
    7.18 +        if (newLength != oldLength) {
    7.19 +            final Object[] newArray;
    7.20 +
    7.21 +            if (newLength > array.length) {
    7.22 +                newArray = new Object[ArrayData.nextSize((int)newLength)];
    7.23 +                System.arraycopy(array, 0, newArray, 0, start);
    7.24 +            } else {
    7.25 +                newArray = array;
    7.26 +            }
    7.27 +
    7.28 +            System.arraycopy(array, start + removed, newArray, start + added, (int)(oldLength - start - removed));
    7.29 +            array = newArray;
    7.30 +            setLength(newLength);
    7.31 +        }
    7.32 +
    7.33 +        return returnValue;
    7.34 +    }
    7.35  }
     8.1 --- a/test/examples/array-micro.js	Thu Oct 17 12:38:50 2013 +0200
     8.2 +++ b/test/examples/array-micro.js	Thu Oct 17 17:33:16 2013 +0200
     8.3 @@ -90,6 +90,24 @@
     8.4      array[6] = 6;
     8.5  });
     8.6  
     8.7 +bench("push", function() {
     8.8 +    var arr = [1, 2, 3];
     8.9 +    arr.push(4);
    8.10 +    arr.push(5);
    8.11 +    arr.push(6);
    8.12 +});
    8.13 +
    8.14 +bench("pop", function() {
    8.15 +    var arr = [1, 2, 3];
    8.16 +    arr.pop();
    8.17 +    arr.pop();
    8.18 +    arr.pop();
    8.19 +});
    8.20 +
    8.21 +bench("splice", function() {
    8.22 +    [1, 2, 3].splice(0, 2, 5, 6, 7);
    8.23 +});
    8.24 +
    8.25  var all = function(e) { return true; };
    8.26  var none = function(e) { return false; };
    8.27  
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/script/basic/JDK-8026701.js	Thu Oct 17 17:33:16 2013 +0200
     9.3 @@ -0,0 +1,72 @@
     9.4 +/*
     9.5 + * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + * 
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.
    9.11 + * 
    9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.15 + * version 2 for more details (a copy is included in the LICENSE file that
    9.16 + * accompanied this code).
    9.17 + * 
    9.18 + * You should have received a copy of the GNU General Public License version
    9.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.21 + * 
    9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.23 + * or visit www.oracle.com if you need additional information or have any
    9.24 + * questions.
    9.25 + */
    9.26 +
    9.27 +/**
    9.28 + * JDK-8026701: Array.prototype.splice is slow on dense arrays
    9.29 + *
    9.30 + * @test
    9.31 + * @run
    9.32 + */
    9.33 +
    9.34 +function testSplice(arr, e1, e2, e3) {
    9.35 +    try {
    9.36 +        print(arr);
    9.37 +        print(arr.splice(3, 0, e1, e2, e3));
    9.38 +        print(arr);
    9.39 +        print(arr.splice(2, 3));
    9.40 +        print(arr);
    9.41 +        print(arr.splice(2, 3, arr[2], arr[3], arr[4]));
    9.42 +        print(arr);
    9.43 +        print(arr.splice(20, 10));
    9.44 +        print(arr);
    9.45 +        print(arr.splice(arr.length, 0, e1, e2, e3));
    9.46 +        print(arr);
    9.47 +        print(arr.splice(0, 2, arr[0], arr[1], arr[2], arr[3]));
    9.48 +        print(arr);
    9.49 +    } catch (error) {
    9.50 +        print(error);
    9.51 +    }
    9.52 +}
    9.53 +
    9.54 +function convert(array, type) {
    9.55 +    return (typeof Java === "undefined") ? array : Java.from(Java.to(array, type));
    9.56 +}
    9.57 +
    9.58 +// run some splice tests on all dense array implementations
    9.59 +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2, -3);
    9.60 +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2, -3);
    9.61 +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, -2, -3);
    9.62 +testSplice(["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], -1, -2, -3);
    9.63 +
    9.64 +// test array conversion during splice
    9.65 +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, "-2", "-3");
    9.66 +testSplice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], -1, -2.5, -3.5);
    9.67 +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, "-2", "-3");
    9.68 +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "long[]"), -1, -2.5, -3.5);
    9.69 +testSplice(convert([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "double[]"), -1, "-2", "-3");
    9.70 +
    9.71 +// test combination with defined elements
    9.72 +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13}), -1, -2, -3);
    9.73 +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false}), -1, -2, -3);
    9.74 +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, configurable: false}), -1, -2, -3);
    9.75 +testSplice(Object.defineProperty([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5, {value: 13, writable: false, configurable: false}), -1, -2, -3);
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/script/basic/JDK-8026701.js.EXPECTED	Thu Oct 17 17:33:16 2013 +0200
    10.3 @@ -0,0 +1,147 @@
    10.4 +1,2,3,4,5,6,7,8,9,10
    10.5 +
    10.6 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
    10.7 +3,-1,-2
    10.8 +1,2,-3,4,5,6,7,8,9,10
    10.9 +-3,4,5
   10.10 +1,2,-3,4,5,6,7,8,9,10
   10.11 +
   10.12 +1,2,-3,4,5,6,7,8,9,10
   10.13 +
   10.14 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.15 +1,2
   10.16 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.17 +1,2,3,4,5,6,7,8,9,10
   10.18 +
   10.19 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
   10.20 +3,-1,-2
   10.21 +1,2,-3,4,5,6,7,8,9,10
   10.22 +-3,4,5
   10.23 +1,2,-3,4,5,6,7,8,9,10
   10.24 +
   10.25 +1,2,-3,4,5,6,7,8,9,10
   10.26 +
   10.27 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.28 +1,2
   10.29 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.30 +1,2,3,4,5,6,7,8,9,10
   10.31 +
   10.32 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
   10.33 +3,-1,-2
   10.34 +1,2,-3,4,5,6,7,8,9,10
   10.35 +-3,4,5
   10.36 +1,2,-3,4,5,6,7,8,9,10
   10.37 +
   10.38 +1,2,-3,4,5,6,7,8,9,10
   10.39 +
   10.40 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.41 +1,2
   10.42 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.43 +1,2,3,4,5,6,7,8,9,10
   10.44 +
   10.45 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
   10.46 +3,-1,-2
   10.47 +1,2,-3,4,5,6,7,8,9,10
   10.48 +-3,4,5
   10.49 +1,2,-3,4,5,6,7,8,9,10
   10.50 +
   10.51 +1,2,-3,4,5,6,7,8,9,10
   10.52 +
   10.53 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.54 +1,2
   10.55 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.56 +1,2,3,4,5,6,7,8,9,10
   10.57 +
   10.58 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
   10.59 +3,-1,-2
   10.60 +1,2,-3,4,5,6,7,8,9,10
   10.61 +-3,4,5
   10.62 +1,2,-3,4,5,6,7,8,9,10
   10.63 +
   10.64 +1,2,-3,4,5,6,7,8,9,10
   10.65 +
   10.66 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.67 +1,2
   10.68 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.69 +1,2,3,4,5,6,7,8,9,10
   10.70 +
   10.71 +1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10
   10.72 +3,-1,-2.5
   10.73 +1,2,-3.5,4,5,6,7,8,9,10
   10.74 +-3.5,4,5
   10.75 +1,2,-3.5,4,5,6,7,8,9,10
   10.76 +
   10.77 +1,2,-3.5,4,5,6,7,8,9,10
   10.78 +
   10.79 +1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
   10.80 +1,2
   10.81 +1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
   10.82 +1,2,3,4,5,6,7,8,9,10
   10.83 +
   10.84 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
   10.85 +3,-1,-2
   10.86 +1,2,-3,4,5,6,7,8,9,10
   10.87 +-3,4,5
   10.88 +1,2,-3,4,5,6,7,8,9,10
   10.89 +
   10.90 +1,2,-3,4,5,6,7,8,9,10
   10.91 +
   10.92 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.93 +1,2
   10.94 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
   10.95 +1,2,3,4,5,6,7,8,9,10
   10.96 +
   10.97 +1,2,3,-1,-2.5,-3.5,4,5,6,7,8,9,10
   10.98 +3,-1,-2.5
   10.99 +1,2,-3.5,4,5,6,7,8,9,10
  10.100 +-3.5,4,5
  10.101 +1,2,-3.5,4,5,6,7,8,9,10
  10.102 +
  10.103 +1,2,-3.5,4,5,6,7,8,9,10
  10.104 +
  10.105 +1,2,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
  10.106 +1,2
  10.107 +1,2,-3.5,4,-3.5,4,5,6,7,8,9,10,-1,-2.5,-3.5
  10.108 +1,2,3,4,5,6,7,8,9,10
  10.109 +
  10.110 +1,2,3,-1,-2,-3,4,5,6,7,8,9,10
  10.111 +3,-1,-2
  10.112 +1,2,-3,4,5,6,7,8,9,10
  10.113 +-3,4,5
  10.114 +1,2,-3,4,5,6,7,8,9,10
  10.115 +
  10.116 +1,2,-3,4,5,6,7,8,9,10
  10.117 +
  10.118 +1,2,-3,4,5,6,7,8,9,10,-1,-2,-3
  10.119 +1,2
  10.120 +1,2,-3,4,-3,4,5,6,7,8,9,10,-1,-2,-3
  10.121 +1,2,3,4,5,13,7,8,9,10
  10.122 +
  10.123 +1,2,3,-1,-2,-3,4,5,13,7,8,9,10
  10.124 +3,-1,-2
  10.125 +1,2,-3,4,5,13,7,8,9,10
  10.126 +-3,4,5
  10.127 +1,2,-3,4,5,13,7,8,9,10
  10.128 +
  10.129 +1,2,-3,4,5,13,7,8,9,10
  10.130 +
  10.131 +1,2,-3,4,5,13,7,8,9,10,-1,-2,-3
  10.132 +1,2
  10.133 +1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3
  10.134 +1,2,3,4,5,13,7,8,9,10
  10.135 +TypeError: "5" is not a writable property of [object Array]
  10.136 +1,2,3,4,5,13,7,8,9,10
  10.137 +
  10.138 +1,2,3,-1,-2,-3,4,5,13,7,8,9,10
  10.139 +3,-1,-2
  10.140 +1,2,-3,4,5,13,7,8,9,10
  10.141 +-3,4,5
  10.142 +1,2,-3,4,5,13,7,8,9,10
  10.143 +
  10.144 +1,2,-3,4,5,13,7,8,9,10
  10.145 +
  10.146 +1,2,-3,4,5,13,7,8,9,10,-1,-2,-3
  10.147 +1,2
  10.148 +1,2,-3,4,-3,4,5,13,7,8,9,10,-1,-2,-3
  10.149 +1,2,3,4,5,13,7,8,9,10
  10.150 +TypeError: "5" is not a writable property of [object Array]

mercurial