Skip to content

Commit b90a06e

Browse files
committed
[GR-16266] Performance improvements in inherits and unclass.
PullRequest: fastr/2054
2 parents c066385 + d461bf9 commit b90a06e

File tree

6 files changed

+166
-50
lines changed

6 files changed

+166
-50
lines changed

com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UnClass.java

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,77 +24,86 @@
2424
import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE;
2525
import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
2626

27-
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
27+
import com.oracle.truffle.api.CompilerDirectives;
2828
import com.oracle.truffle.api.dsl.Cached;
2929
import com.oracle.truffle.api.dsl.Specialization;
3030
import com.oracle.truffle.api.profiles.BranchProfile;
3131
import com.oracle.truffle.r.nodes.attributes.RemoveFixedAttributeNode;
3232
import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode;
3333
import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
34+
import com.oracle.truffle.r.nodes.builtin.base.UnClassNodeGen.RemoveClassAttrNodeGen;
3435
import com.oracle.truffle.r.runtime.builtins.RBuiltin;
3536
import com.oracle.truffle.r.runtime.data.RAttributable;
3637
import com.oracle.truffle.r.runtime.data.RNull;
3738
import com.oracle.truffle.r.runtime.data.RShareable;
38-
import com.oracle.truffle.r.runtime.data.RVector;
3939
import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
40+
import com.oracle.truffle.r.runtime.data.nodes.VectorReuse;
41+
import com.oracle.truffle.r.runtime.nodes.RBaseNode;
4042

4143
@RBuiltin(name = "unclass", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE)
4244
public abstract class UnClass extends RBuiltinNode.Arg1 {
43-
private final BranchProfile objectProfile = BranchProfile.create();
44-
private final BranchProfile shareableProfile = BranchProfile.create();
45-
4645
static {
4746
Casts casts = new Casts(UnClass.class);
4847
casts.arg("x").mustNotBeMissing().asAttributable(true, true, true);
4948
}
5049

50+
@Child private RemoveClassAttrNode removeClassAttrNode;
51+
5152
@Specialization
5253
protected RNull unClass(RNull rnull) {
5354
return rnull;
5455
}
5556

56-
@TruffleBoundary
57-
private static Object unClassVector(RAbstractVector arg) {
58-
RVector<?> resultVector = arg.materialize();
59-
if (!resultVector.isTemporary()) {
60-
resultVector = resultVector.copy();
61-
resultVector.incRefCount();
62-
}
63-
return RVector.setVectorClassAttr(resultVector, null);
64-
}
65-
66-
// TODO: this specialization could go away if connections were simple vectors (we wouldn't need
67-
// special method for setting class attributes then)
6857
@Specialization
69-
protected Object unClass(RAbstractVector arg,
58+
protected Object unClass(RAttributable arg,
7059
@Cached("create()") GetClassAttributeNode getClassNode) {
7160
if (getClassNode.isObject(arg)) {
72-
objectProfile.enter();
73-
return unClassVector(arg);
61+
if (removeClassAttrNode == null) {
62+
CompilerDirectives.transferToInterpreterAndInvalidate();
63+
removeClassAttrNode = insert(RemoveClassAttrNodeGen.create());
64+
}
65+
return removeClassAttrNode.execute(arg);
7466
}
7567
return arg;
7668
}
7769

78-
@Specialization(guards = "notAbstractVector(arg)")
79-
protected Object unClass(RAttributable arg,
80-
@Cached("createClass()") RemoveFixedAttributeNode removeClassNode,
81-
@Cached("create()") GetClassAttributeNode getClassNode) {
82-
if (getClassNode.getClassAttr(arg) != null) {
83-
objectProfile.enter();
84-
if (arg instanceof RShareable) {
70+
protected abstract static class RemoveClassAttrNode extends RBaseNode {
71+
public abstract Object execute(RAttributable attributable);
72+
73+
@Specialization(guards = "reuse.supports(x)")
74+
protected Object doVector(RAbstractVector x,
75+
@Cached("createClass()") RemoveFixedAttributeNode removeClassNode,
76+
@Cached("createTemporary(x)") VectorReuse reuse) {
77+
RAbstractVector result = reuse.getMaterializedResult(x);
78+
removeClassNode.execute(result);
79+
return result;
80+
}
81+
82+
@Specialization(replaces = "doVector")
83+
protected Object doVectorGeneric(RAbstractVector x,
84+
@Cached("createClass()") RemoveFixedAttributeNode removeClassNode,
85+
@Cached("createTemporaryGeneric()") VectorReuse reuse) {
86+
return doVector(x, removeClassNode, reuse);
87+
}
88+
89+
@Specialization(guards = "notAbstractVector(x)")
90+
protected Object unClass(RAttributable x,
91+
@Cached BranchProfile shareableProfile,
92+
@Cached("createClass()") RemoveFixedAttributeNode removeClassNode) {
93+
RAttributable result = x;
94+
if (x instanceof RShareable) {
8595
shareableProfile.enter();
86-
RShareable shareable = (RShareable) arg;
96+
RShareable shareable = (RShareable) x;
8797
if (!shareable.isTemporary()) {
88-
shareable = shareable.copy();
89-
shareable.incRefCount();
98+
result = (RAttributable) shareable.copy();
9099
}
91100
}
92-
removeClassNode.execute(arg);
101+
removeClassNode.execute(result);
102+
return result;
93103
}
94-
return arg;
95-
}
96104

97-
protected boolean notAbstractVector(Object arg) {
98-
return !(arg instanceof RAbstractVector);
105+
protected static boolean notAbstractVector(Object arg) {
106+
return !(arg instanceof RAbstractVector);
107+
}
99108
}
100109
}

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/LazyResourceHandlerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public Map<String, String> getRFiles(Class<?> accessor, String pkgName) {
7575
while ((line = r.readLine()) != null) {
7676
if (line.endsWith(".r") || line.endsWith(".R")) {
7777
final String rResource = pkgName + "/R/" + line.trim();
78-
result.put(sourcePath.toString(), Utils.getResourceAsString(accessor, rResource, true));
78+
result.put(rResource, Utils.getResourceAsString(accessor, rResource, true));
7979
}
8080
}
8181
}

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)