Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splitting Gigantic EqualsNode into few Smaller Ones #6280

Merged
merged 23 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
80fd070
Always try to resolve conversion for Any type
JaroslavTulach Apr 3, 2023
40cc46b
Make sure conversions fallback to Any for foreign objects and types
JaroslavTulach Apr 4, 2023
65e933e
Splitting the EqualsNode to two speeds the sieve benchmark
JaroslavTulach Apr 4, 2023
2e847e6
EqualsComplexNode shall in general delegate to simple EqualsNode
JaroslavTulach Apr 14, 2023
ca4d7b6
Comparing interop strings needs to be handled in EqualsNode
JaroslavTulach Apr 14, 2023
f6b43f7
Only when isPrimitive-ness differs we can conclude they aren't the same
JaroslavTulach Apr 14, 2023
e8a0c97
Dedicated node to compare atoms
JaroslavTulach Apr 14, 2023
6a9358a
Let HasCustomComparatorNode return the comparator to use
JaroslavTulach Apr 14, 2023
e45fc47
Merging with current develop branch
JaroslavTulach Apr 14, 2023
adb78d7
Delegate to custom comparators when they are provided
JaroslavTulach Apr 14, 2023
0195e6c
Treat InteropLibrary.isString as a primitive object
JaroslavTulach Apr 14, 2023
0d21a46
No need for InvokeAnyEqualsNode, EqualsNode handles all the cases
JaroslavTulach Apr 14, 2023
a30ab04
There should be no need for int, byte & co. specializations - such ty…
JaroslavTulach Apr 14, 2023
904055d
Implementing from conversion via Truffle nodes
JaroslavTulach Apr 14, 2023
1c69c34
Update engine/runtime/src/main/java/org/enso/interpreter/node/express…
JaroslavTulach Apr 14, 2023
dcd484b
Renaming to isNotPrimitive
JaroslavTulach Apr 14, 2023
a9787c6
Dropping Has and making CustomComparatorNode
JaroslavTulach Apr 15, 2023
1c7ac56
Define Any.== as a builtin
JaroslavTulach Apr 15, 2023
38ce191
test micro distribution has to use Any.== builtin
JaroslavTulach Apr 15, 2023
6a78062
Merging with changes on the develop branch
JaroslavTulach Apr 16, 2023
7c8730b
Convert interop values on the Enso boundary
JaroslavTulach Apr 16, 2023
04bdbff
Reverting no longer needed 2bf5256 as is builtin again
JaroslavTulach Apr 16, 2023
80eb323
Resolving conflicts with develop branch
JaroslavTulach Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 1 addition & 16 deletions distribution/lib/Standard/Base/0.0.0-dev/src/Any.enso
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,7 @@ type Any
a = 7 * 21
a == 147
== : Any -> Boolean
== self that =
# If there is No_Such_Conversion, then `self` and `that` are probably
# host or polyglot values, so we just compare them with the default comparator.
eq_self = Comparable.from self
eq_that = Comparable.from that
similar_type = Meta.is_same_object eq_self eq_that
case similar_type of
False -> False
True ->
case Meta.is_same_object eq_self Default_Comparator of
# Shortcut for objects with Default_Comparator, because of the performance.
True -> Comparable.equals_builtin self that
False ->
case eq_self.compare self that of
Ordering.Equal -> True
_ -> False
== self that = Comparable.equals_builtin self that
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved

## ALIAS Inequality

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ type Comparable
A custom comparator is any comparator that is different than the
default ones.
has_custom_comparator : Atom -> Boolean
has_custom_comparator atom =
comp = Comparable.from atom
(comp.is_a Default_Comparator).not
has_custom_comparator atom = case Comparable.from atom of
JaroslavTulach marked this conversation as resolved.
Show resolved Hide resolved
_ : Default_Comparator -> Nothing
c -> c

## PRIVATE
Default implementation of a _comparator_.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package org.enso.interpreter.node.expression.builtin.meta;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.GenerateUncached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.library.CachedLibrary;
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.profiles.ConditionProfile;
import java.util.Arrays;
import org.enso.interpreter.node.callable.InvokeCallableNode.ArgumentsExecutionMode;
import org.enso.interpreter.node.callable.InvokeCallableNode.DefaultsExecutionMode;
import org.enso.interpreter.node.callable.dispatch.InvokeFunctionNode;
import org.enso.interpreter.node.expression.builtin.ordering.HasCustomComparatorNode;
import org.enso.interpreter.runtime.EnsoContext;
import org.enso.interpreter.runtime.callable.argument.CallArgumentInfo;
import org.enso.interpreter.runtime.callable.atom.Atom;
import org.enso.interpreter.runtime.callable.atom.AtomConstructor;
import org.enso.interpreter.runtime.callable.atom.StructsLibrary;
import org.enso.interpreter.runtime.callable.function.Function;
import org.enso.interpreter.runtime.data.Type;
import org.enso.interpreter.runtime.state.State;

@GenerateUncached
public abstract class EqualsAtomNode extends Node {

public static EqualsAtomNode build() {
return EqualsAtomNodeGen.create();
}

public abstract boolean execute(Atom left, Atom right);

static EqualsNode[] createEqualsNodes(int size) {
EqualsNode[] nodes = new EqualsNode[size];
Arrays.fill(nodes, EqualsNode.build());
return nodes;
}

@Specialization(
guards = {
"selfCtorCached == self.getConstructor()",
"customComparatorNode.execute(self) == null"
},
limit = "10")
@ExplodeLoop
boolean equalsAtoms(
Atom self,
Atom other,
@Cached("self.getConstructor()") AtomConstructor selfCtorCached,
@Cached(value = "selfCtorCached.getFields().length", allowUncached = true)
int fieldsLenCached,
@Cached(value = "createEqualsNodes(fieldsLenCached)", allowUncached = true)
EqualsNode[] fieldEqualsNodes,
@Cached HasCustomComparatorNode customComparatorNode,
@Cached ConditionProfile constructorsNotEqualProfile,
@CachedLibrary(limit = "5") StructsLibrary structsLib) {
if (constructorsNotEqualProfile.profile(self.getConstructor() != other.getConstructor())) {
return false;
}
var selfFields = structsLib.getFields(self);
var otherFields = structsLib.getFields(other);
assert selfFields.length == otherFields.length
: "Constructors are same, atoms should have the same number of fields";

CompilerAsserts.partialEvaluationConstant(fieldsLenCached);
for (int i = 0; i < fieldsLenCached; i++) {
boolean fieldsAreEqual = fieldEqualsNodes[i].execute(selfFields[i], otherFields[i]);
if (!fieldsAreEqual) {
return false;
}
}
return true;
}

@Specialization(
guards = {
"selfCtorCached == self.getConstructor()",
"cachedComparator != null",
},
limit = "10")
boolean equalsAtoms(
Atom self,
Atom other,
@Cached("self.getConstructor()") AtomConstructor selfCtorCached,
@Cached HasCustomComparatorNode customComparatorNode,
@Cached(value = "customComparatorNode.execute(self)") Type cachedComparator,
@Cached(value = "findCompareMethod(cachedComparator)", allowUncached = true)
Function compareFn,
@Cached(value = "invokeCompareNode(compareFn)") InvokeFunctionNode invokeNode) {
var otherComparator = customComparatorNode.execute(other);
if (cachedComparator != otherComparator) {
return false;
}
var ctx = EnsoContext.get(this);
var args = new Object[] {cachedComparator, self, other};
var result = invokeNode.execute(compareFn, null, State.create(ctx), args);
return ctx.getBuiltins().ordering().newEqual() == result;
}

@CompilerDirectives.TruffleBoundary
@Specialization(replaces = "equalsAtoms")
boolean equalsAtomsUncached(Atom self, Atom other) {
if (self.getConstructor() != other.getConstructor()) {
return false;
}
Object[] selfFields = StructsLibrary.getUncached().getFields(self);
Object[] otherFields = StructsLibrary.getUncached().getFields(other);
if (selfFields.length != otherFields.length) {
return false;
}
for (int i = 0; i < selfFields.length; i++) {
boolean areFieldsSame = EqualsNodeGen.getUncached().execute(selfFields[i], otherFields[i]);
if (!areFieldsSame) {
return false;
}
}
return true;
}

@TruffleBoundary
static Function findCompareMethod(Type comparator) {
var fn = comparator.getDefinitionScope().getMethods().get(comparator).get("compare");
if (fn == null) {
throw new AssertionError("No compare function for " + comparator);
}
return fn;
}

static InvokeFunctionNode invokeCompareNode(Function compareFn) {
CallArgumentInfo[] argsInfo = new CallArgumentInfo[compareFn.getSchema().getArgumentsCount()];
for (int i = 0; i < argsInfo.length; i++) {
var argDef = compareFn.getSchema().getArgumentInfos()[i];
argsInfo[i] = new CallArgumentInfo(argDef.getName());
}
return InvokeFunctionNode.build(
argsInfo, DefaultsExecutionMode.EXECUTE, ArgumentsExecutionMode.EXECUTE);
}
}
Loading