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
|