diff --git a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java index df0e6390600d1..77773dddac927 100644 --- a/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java +++ b/engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/ordering/SortVectorNode.java @@ -102,6 +102,7 @@ Object sortPrimitives(State state, Object self, long ascending, Object comparato @Cached TypeOfNode typeOfNode, @Cached AnyToTextNode toTextNode, @Cached BranchProfile warningEncounteredProfile, + @Cached(value = "createDefaultComparator(lessThanNode, equalsNode, typeOfNode, toTextNode, ascending)", allowUncached = true) DefaultSortComparator javaComparator, @CachedLibrary(limit = "10") InteropLibrary interop, @CachedLibrary(limit = "5") WarningsLibrary warningsLib) { EnsoContext ctx = EnsoContext.get(this); @@ -116,6 +117,7 @@ Object sortPrimitives(State state, Object self, long ascending, Object comparato interop.readArrayElement(self, i) ); } else { + CompilerDirectives.transferToInterpreter(); throw new PanicException( ctx.getBuiltins().error().makeUnsupportedArgumentsError( new Object[]{self}, @@ -128,16 +130,25 @@ Object sortPrimitives(State state, Object self, long ascending, Object comparato } catch (UnsupportedMessageException | InvalidArrayIndexException e) { throw new IllegalStateException("Should not reach here", e); } - var javaComparator = new DefaultComparator(lessThanNode, equalsNode, typeOfNode, - toTextNode, ascending > 0); try { - return sortPrimitiveVector(elems, javaComparator, warningEncounteredProfile); + return sortPrimitiveVector(elems, javaComparator); } catch (CompareException e) { throw DataflowError.withoutTrace( incomparableValuesError(e.leftOperand, e.rightOperand), this); } } + DefaultSortComparator createDefaultComparator( + LessThanNode lessThanNode, + EqualsNode equalsNode, + TypeOfNode typeOfNode, + AnyToTextNode toTextNode, + long ascending + ) { + return new DefaultSortComparator(lessThanNode, equalsNode, typeOfNode, toTextNode, + ascending > 0); + } + @TruffleBoundary @Specialization(guards = { "interop.hasArrayElements(self)", @@ -157,7 +168,7 @@ Object sortGeneric(State state, Object self, long ascending, Object comparatorsA List compareFuncs = readInteropArray(interop, warningsLib, compareFuncsArray); List groups = splitByComparators(elems, comparators, compareFuncs); - // Prepare input for DefaultComparator and GenericComparator and sort the elements within groups + // Prepare input for DefaultSortComparator and GenericSortComparator and sort the elements within groups var ctx = EnsoContext.get(this); Atom less = ctx.getBuiltins().ordering().newLess(); Atom equal = ctx.getBuiltins().ordering().newEqual(); @@ -166,9 +177,9 @@ Object sortGeneric(State state, Object self, long ascending, Object comparatorsA List resultVec = new ArrayList<>(); try { for (var group : groups) { - Comparator javaComparator; + SortComparator javaComparator; if (isNothing(byFunc) && isNothing(onFunc) && isPrimitiveGroup(group)) { - javaComparator = new DefaultComparator( + javaComparator = new DefaultSortComparator( lessThanNode, equalsNode, typeOfNode, @@ -177,7 +188,7 @@ Object sortGeneric(State state, Object self, long ascending, Object comparatorsA ); } else { Object compareFunc = isNothing(byFunc) ? group.compareFunc : byFunc; - javaComparator = new GenericComparator( + javaComparator = new GenericSortComparator( ascending > 0, compareFunc, onFunc, @@ -206,15 +217,14 @@ Object sortGeneric(State state, Object self, long ascending, Object comparatorsA } } + @TruffleBoundary(allowInlining = true) private Object sortPrimitiveVector(Object[] elems, - DefaultComparator javaComparator, BranchProfile warningEncounteredProfile) + DefaultSortComparator javaComparator) throws CompareException { Arrays.sort(elems, javaComparator); var sortedVector = Vector.fromArray(new Array(elems)); if (javaComparator.hasWarnings()) { - warningEncounteredProfile.enter(); - CompilerDirectives.transferToInterpreter(); return attachWarnings(sortedVector, javaComparator.getEncounteredWarnings()); } else { return sortedVector; @@ -409,9 +419,9 @@ private boolean isNothing(Object object, EnsoContext ctx) { * Group of elements grouped by comparator. * * @param elems Elements of the group. - * @param comparator Comparator for the elems, i.e., it should hold that + * @param comparator SortComparator for the elems, i.e., it should hold that * {@code elems.each it-> (Comparable.from it) == comparator}. - * @param compareFunc `Comparator.compare` function extracted from the comparator. + * @param compareFunc `SortComparator.compare` function extracted from the comparator. */ private record Group( List elems, @@ -426,12 +436,12 @@ private record Group( * incomparable values. The warnings are gathered as pure Strings in a hash set, so that they are * not duplicated. */ - private static abstract class Comparator implements java.util.Comparator { + private static abstract class SortComparator implements java.util.Comparator { private final Set warnings = new HashSet<>(); private final AnyToTextNode toTextNode; - protected Comparator(AnyToTextNode toTextNode) { + protected SortComparator(AnyToTextNode toTextNode) { this.toTextNode = toTextNode; } @@ -447,14 +457,15 @@ public Set getEncounteredWarnings() { return warnings; } + @TruffleBoundary public boolean hasWarnings() { return !warnings.isEmpty(); } } /** - * Comparator for comparing all values that have Default_Comparator. These are either primitive - * types, or the types that do not provide their own comparator. + * SortComparator for comparing all values that have Default_Comparator. These are either + * primitive types, or the types that do not provide their own comparator. *

* Note that it is essential for this class that the {@code by} method parameter to * {@code Vector.sort} is set to the default value, which is {@code Ordering.compare}, because @@ -462,14 +473,14 @@ public boolean hasWarnings() { * handle partial ordering for primitive types specifically, partial ordering for other types is * not implemented yet - that requires topological sorting). */ - private final class DefaultComparator extends Comparator { + final class DefaultSortComparator extends SortComparator { private final LessThanNode lessThanNode; private final EqualsNode equalsNode; private final TypeOfNode typeOfNode; private final boolean ascending; - private DefaultComparator(LessThanNode lessThanNode, EqualsNode equalsNode, + private DefaultSortComparator(LessThanNode lessThanNode, EqualsNode equalsNode, TypeOfNode typeOfNode, AnyToTextNode toTextNode, boolean ascending) { super(toTextNode); @@ -571,9 +582,9 @@ private int getPrimitiveValueCost(Object object) { /** * Comparator for any values. This comparator compares the values by calling back to Enso (by * {@link #compareFunc}), rather than using compare nodes (i.e. {@link LessThanNode}). directly, - * as opposed to {@link DefaultComparator}. + * as opposed to {@link DefaultSortComparator}. */ - private final class GenericComparator extends Comparator { + private final class GenericSortComparator extends SortComparator { private final boolean ascending; /** @@ -591,7 +602,7 @@ private final class GenericComparator extends Comparator { private final Atom greater; - private GenericComparator( + private GenericSortComparator( boolean ascending, Object compareFunc, Object onFunc,