< prev index next >

src/jdk/nashorn/internal/objects/NativeArray.java

Print this page
rev 1337 : 8080182: Array.prototype.sort throws IAE on inconsistent comparison
Reviewed-by: lagergren, hannesw


1216     }
1217 
1218     private static ScriptFunction compareFunction(final Object comparefn) {
1219         if (comparefn == ScriptRuntime.UNDEFINED) {
1220             return null;
1221         }
1222 
1223         if (! (comparefn instanceof ScriptFunction)) {
1224             throw typeError("not.a.function", ScriptRuntime.safeToString(comparefn));
1225         }
1226 
1227         return (ScriptFunction)comparefn;
1228     }
1229 
1230     private static Object[] sort(final Object[] array, final Object comparefn) {
1231         final ScriptFunction cmp = compareFunction(comparefn);
1232 
1233         final List<Object> list = Arrays.asList(array);
1234         final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance();
1235 

1236         Collections.sort(list, new Comparator<Object>() {
1237             private final MethodHandle call_cmp = getCALL_CMP();
1238             @Override
1239             public int compare(final Object x, final Object y) {
1240                 if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) {
1241                     return 0;
1242                 } else if (x == ScriptRuntime.UNDEFINED) {
1243                     return 1;
1244                 } else if (y == ScriptRuntime.UNDEFINED) {
1245                     return -1;
1246                 }
1247 
1248                 if (cmp != null) {
1249                     try {
1250                         return (int)Math.signum((double)call_cmp.invokeExact(cmp, cmpThis, x, y));
1251                     } catch (final RuntimeException | Error e) {
1252                         throw e;
1253                     } catch (final Throwable t) {
1254                         throw new RuntimeException(t);
1255                     }
1256                 }
1257 
1258                 return JSType.toString(x).compareTo(JSType.toString(y));
1259             }
1260         });









1261 
1262         return list.toArray(new Object[array.length]);
1263     }
1264 
1265     /**
1266      * ECMA 15.4.4.11 Array.prototype.sort ( comparefn )
1267      *
1268      * @param self       self reference
1269      * @param comparefn  element comparison function
1270      * @return sorted array
1271      */
1272     @Function(attributes = Attribute.NOT_ENUMERABLE)
1273     public static ScriptObject sort(final Object self, final Object comparefn) {
1274         try {
1275             final ScriptObject sobj    = (ScriptObject) self;
1276             final long         len     = JSType.toUint32(sobj.getLength());
1277             ArrayData          array   = sobj.getArray();
1278 
1279             if (len > 1) {
1280                 // Get only non-missing elements. Missing elements go at the end




1216     }
1217 
1218     private static ScriptFunction compareFunction(final Object comparefn) {
1219         if (comparefn == ScriptRuntime.UNDEFINED) {
1220             return null;
1221         }
1222 
1223         if (! (comparefn instanceof ScriptFunction)) {
1224             throw typeError("not.a.function", ScriptRuntime.safeToString(comparefn));
1225         }
1226 
1227         return (ScriptFunction)comparefn;
1228     }
1229 
1230     private static Object[] sort(final Object[] array, final Object comparefn) {
1231         final ScriptFunction cmp = compareFunction(comparefn);
1232 
1233         final List<Object> list = Arrays.asList(array);
1234         final Object cmpThis = cmp == null || cmp.isStrict() ? ScriptRuntime.UNDEFINED : Global.instance();
1235 
1236         try {
1237             Collections.sort(list, new Comparator<Object>() {
1238                 private final MethodHandle call_cmp = getCALL_CMP();
1239                 @Override
1240                 public int compare(final Object x, final Object y) {
1241                     if (x == ScriptRuntime.UNDEFINED && y == ScriptRuntime.UNDEFINED) {
1242                         return 0;
1243                     } else if (x == ScriptRuntime.UNDEFINED) {
1244                         return 1;
1245                     } else if (y == ScriptRuntime.UNDEFINED) {
1246                         return -1;
1247                     }
1248 
1249                     if (cmp != null) {
1250                         try {
1251                             return (int)Math.signum((double)call_cmp.invokeExact(cmp, cmpThis, x, y));
1252                         } catch (final RuntimeException | Error e) {
1253                             throw e;
1254                         } catch (final Throwable t) {
1255                             throw new RuntimeException(t);
1256                         }
1257                     }
1258 
1259                     return JSType.toString(x).compareTo(JSType.toString(y));
1260                 }
1261             });
1262         } catch (final IllegalArgumentException iae) {
1263             // Collections.sort throws IllegalArgumentException when
1264             // Comparison method violates its general contract
1265 
1266             // See ECMA spec 15.4.4.11 Array.prototype.sort (comparefn).
1267             // If "comparefn" is not undefined and is not a consistent
1268             // comparison function for the elements of this array, the
1269             // behaviour of sort is implementation-defined.
1270         }
1271 
1272         return list.toArray(new Object[array.length]);
1273     }
1274 
1275     /**
1276      * ECMA 15.4.4.11 Array.prototype.sort ( comparefn )
1277      *
1278      * @param self       self reference
1279      * @param comparefn  element comparison function
1280      * @return sorted array
1281      */
1282     @Function(attributes = Attribute.NOT_ENUMERABLE)
1283     public static ScriptObject sort(final Object self, final Object comparefn) {
1284         try {
1285             final ScriptObject sobj    = (ScriptObject) self;
1286             final long         len     = JSType.toUint32(sobj.getLength());
1287             ArrayData          array   = sobj.getArray();
1288 
1289             if (len > 1) {
1290                 // Get only non-missing elements. Missing elements go at the end


< prev index next >