Skip to content

Commit 3a1e26a

Browse files
committed
Performance improvements of the inherits built-in
1 parent f3a5c70 commit 3a1e26a

File tree

4 files changed

+121
-14
lines changed

4 files changed

+121
-14
lines changed

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public static boolean hasClass(RAttributable value, String className) {
9191
return false;
9292
}
9393

94-
private static final RStringVector truffleObjectClassHeader = RDataFactory.createStringVectorFromScalar("polyglot.value");
94+
private static final RStringVector truffleObjectClassHeader = RDataFactory.getPermanent().createStringVectorFromScalar("polyglot.value");
9595

9696
@Child private GetFixedPropertyNode access;
9797
@Child private S4Class s4Class;

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ImplicitClassHierarchyNode.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
2828
import com.oracle.truffle.api.dsl.Cached;
2929
import com.oracle.truffle.api.dsl.Specialization;
30+
import com.oracle.truffle.api.nodes.ExplodeLoop;
3031
import com.oracle.truffle.api.profiles.ConditionProfile;
3132
import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode;
3233
import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode;
@@ -124,6 +125,19 @@ protected RStringVector get(RTypedValue value,
124125
return getCachedType(value, value.getRType(), isArray, isMatrix, getDim);
125126
}
126127

128+
@ExplodeLoop
129+
public static boolean isImplicitClass(String className) {
130+
if (className.equals("array") || className.equals("matrix") || className.equals("numeric")) {
131+
return true;
132+
}
133+
for (RType type : RType.VALUES) {
134+
if (className.equals(type.getClazz())) {
135+
return true;
136+
}
137+
}
138+
return false;
139+
}
140+
127141
public static RStringVector getImplicitClass(Object value, boolean forDispatch) {
128142
CompilerAsserts.neverPartOfCompilation();
129143
if (value instanceof Integer) {

com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java

Lines changed: 105 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,36 @@
1414
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1515
*
1616
* Copyright (c) 2014, Purdue University
17-
* Copyright (c) 2014, 2018, Oracle and/or its affiliates
17+
* Copyright (c) 2014, 2019, Oracle and/or its affiliates
1818
*
1919
* All rights reserved.
2020
*/
2121

2222
package com.oracle.truffle.r.nodes.unary;
2323

24+
import com.oracle.truffle.api.CompilerDirectives;
2425
import com.oracle.truffle.api.dsl.Cached;
26+
import com.oracle.truffle.api.dsl.ImportStatic;
2527
import com.oracle.truffle.api.dsl.Specialization;
2628
import com.oracle.truffle.api.dsl.TypeSystemReference;
29+
import com.oracle.truffle.api.nodes.Node;
30+
import com.oracle.truffle.api.profiles.BranchProfile;
31+
import com.oracle.truffle.api.profiles.ConditionProfile;
32+
import com.oracle.truffle.api.profiles.ValueProfile;
2733
import com.oracle.truffle.r.nodes.function.ClassHierarchyNode;
2834
import com.oracle.truffle.r.nodes.function.ClassHierarchyNodeGen;
35+
import com.oracle.truffle.r.nodes.function.ImplicitClassHierarchyNode;
36+
import com.oracle.truffle.r.nodes.function.IsNotObject;
37+
import com.oracle.truffle.r.runtime.DSLConfig;
2938
import com.oracle.truffle.r.runtime.RRuntime;
3039
import com.oracle.truffle.r.runtime.data.RDataFactory;
3140
import com.oracle.truffle.r.runtime.data.RIntVector;
3241
import com.oracle.truffle.r.runtime.data.RStringVector;
3342
import com.oracle.truffle.r.runtime.data.RTypes;
3443
import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector;
44+
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
45+
import com.oracle.truffle.r.runtime.data.nodes.VectorAccess;
46+
import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator;
3547
import com.oracle.truffle.r.runtime.nodes.RBaseNode;
3648

3749
/**
@@ -40,31 +52,80 @@
4052
@TypeSystemReference(RTypes.class)
4153
public abstract class InheritsNode extends RBaseNode {
4254

55+
@Child private ClassHierarchyNode classHierarchy;
56+
4357
public abstract Object execute(Object x, RAbstractStringVector what, boolean which);
4458

45-
protected ClassHierarchyNode createClassHierarchy() {
46-
return ClassHierarchyNodeGen.create(true, true);
59+
protected static boolean isNotImplicitClass(String className) {
60+
return !ImplicitClassHierarchyNode.isImplicitClass(className);
61+
}
62+
63+
protected static boolean vectorEquals(VectorAccess access, RAbstractVector vec, String what) {
64+
try (SequentialIterator it = access.access(vec)) {
65+
access.next(it);
66+
return access.getLength(it) == 1 && access.getString(it).equals(what);
67+
}
68+
}
69+
70+
protected static String getSingleOrNull(RAbstractStringVector vec) {
71+
return vec.getLength() == 1 ? vec.getDataAt(0) : null;
72+
}
73+
74+
// Fast path for situation where: "what" is a constant and "x" is not an object
75+
// We need to check that "what" is not implicit class that's why we cannot just simply check
76+
// that "x" is not an object. Note IsNotObject covers S4 classes too.
77+
@Specialization(guards = {
78+
"!which",
79+
"cachedWhat != null",
80+
"isNotObject.execute(x)",
81+
"whatAccess.supports(what)",
82+
"vectorEquals(whatAccess, what, cachedWhat)",
83+
"isNotImplicitClass(cachedWhat)"}, limit = "getVectorAccessCacheSize()")
84+
@SuppressWarnings("unused") // all arguments are used only in the guard
85+
protected byte noObjectFastPath(Object x, RAbstractStringVector what, boolean which,
86+
@Cached IsNotObject isNotObject,
87+
@Cached("what.access()") VectorAccess whatAccess,
88+
@Cached("getSingleOrNull(what)") String cachedWhat) {
89+
return RRuntime.LOGICAL_FALSE;
4790
}
4891

49-
@Specialization(guards = "!which")
92+
@Specialization(guards = {"!which", "whatAccess.supports(what)"}, limit = "getVectorAccessCacheSize()")
5093
protected byte doesInherit(Object x, RAbstractStringVector what, @SuppressWarnings("unused") boolean which,
51-
@Cached("createClassHierarchy()") ClassHierarchyNode classHierarchy) {
52-
RStringVector hierarchy = classHierarchy.execute(x);
53-
for (int i = 0; i < what.getLength(); i++) {
54-
String whatString = what.getDataAt(i);
55-
for (int j = 0; j < hierarchy.getLength(); j++) {
56-
if (whatString.equals(hierarchy.getDataAt(j))) {
94+
@Cached BranchProfile nonEmptyClassHierarchy,
95+
@Cached("createEqualityProfile()") ValueProfile whatValueProfile,
96+
@Cached("createBinaryProfile()") ConditionProfile whatIsSingleElement,
97+
@Cached ContainsCheck containsCheck,
98+
@Cached("what.access()") VectorAccess whatAccess) {
99+
RStringVector hierarchy = getClassHierarchy().execute(x);
100+
if (hierarchy == null) {
101+
return RRuntime.LOGICAL_FALSE;
102+
}
103+
nonEmptyClassHierarchy.enter();
104+
try (SequentialIterator whatIt = whatAccess.access(what)) {
105+
if (whatIsSingleElement.profile(whatAccess.getLength(whatIt) == 1)) {
106+
whatAccess.next(whatIt);
107+
String whatString = whatValueProfile.profile(whatAccess.getString(whatIt));
108+
return RRuntime.asLogical(containsCheck.execute(whatString, hierarchy));
109+
}
110+
while (whatAccess.next(whatIt)) {
111+
String whatString = whatValueProfile.profile(whatAccess.getString(whatIt));
112+
if (containsCheck.execute(whatString, hierarchy)) {
57113
return RRuntime.LOGICAL_TRUE;
58114
}
59115
}
60116
}
61117
return RRuntime.LOGICAL_FALSE;
62118
}
63119

120+
@Specialization(replaces = {"doesInherit", "noObjectFastPath"}, guards = "!which")
121+
protected byte doesInheritGeneric(Object x, RAbstractStringVector what, @SuppressWarnings("unused") boolean which,
122+
@Cached ContainsCheck containsCheck) {
123+
return doesInherit(x, what, which, BranchProfile.getUncached(), ValueProfile.getUncached(), ConditionProfile.getUncached(), containsCheck, what.slowPathAccess());
124+
}
125+
64126
@Specialization(guards = "which")
65-
protected RIntVector doesInheritWhich(Object x, RAbstractStringVector what, @SuppressWarnings("unused") boolean which,
66-
@Cached("createClassHierarchy()") ClassHierarchyNode classHierarchy) {
67-
RStringVector hierarchy = classHierarchy.execute(x);
127+
protected RIntVector doesInheritWhich(Object x, RAbstractStringVector what, @SuppressWarnings("unused") boolean which) {
128+
RStringVector hierarchy = getClassHierarchy().execute(x);
68129
int[] data = new int[what.getLength()];
69130
for (int i = 0; i < what.getLength(); i++) {
70131
String whatString = what.getDataAt(i);
@@ -77,4 +138,35 @@ protected RIntVector doesInheritWhich(Object x, RAbstractStringVector what, @Sup
77138
}
78139
return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
79140
}
141+
142+
public ClassHierarchyNode getClassHierarchy() {
143+
if (classHierarchy == null) {
144+
CompilerDirectives.transferToInterpreterAndInvalidate();
145+
classHierarchy = insert(ClassHierarchyNodeGen.create(true, true));
146+
}
147+
return classHierarchy;
148+
}
149+
150+
@ImportStatic(DSLConfig.class)
151+
protected abstract static class ContainsCheck extends Node {
152+
public abstract boolean execute(String needle, RStringVector haystack);
153+
154+
@Specialization(guards = {"haystackAccess.supports(haystack)"}, limit = "getVectorAccessCacheSize()")
155+
protected boolean doLongHaystack(String needle, RStringVector haystack,
156+
@Cached("haystack.access()") VectorAccess haystackAccess) {
157+
try (SequentialIterator it = haystackAccess.access(haystack)) {
158+
while (haystackAccess.next(it)) {
159+
if (needle.equals(haystackAccess.getString(it))) {
160+
return true;
161+
}
162+
}
163+
}
164+
return false;
165+
}
166+
167+
@Specialization(replaces = "doLongHaystack")
168+
protected boolean doLongHaystackGeneric(String needle, RStringVector haystack) {
169+
return doLongHaystack(needle, haystack, haystack.slowPathAccess());
170+
}
171+
}
80172
}

com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public enum RType {
6868

6969
public static final int NO_PRECEDENCE = -1;
7070
public static final int NUMBER_OF_PRECEDENCES = 9;
71+
public static final RType[] VALUES = values();
7172

7273
private final String name;
7374
private final String clazz;

0 commit comments

Comments
 (0)