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
2222package com .oracle .truffle .r .nodes .unary ;
2323
24+ import com .oracle .truffle .api .CompilerDirectives ;
2425import com .oracle .truffle .api .dsl .Cached ;
26+ import com .oracle .truffle .api .dsl .ImportStatic ;
2527import com .oracle .truffle .api .dsl .Specialization ;
2628import 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 ;
2733import com .oracle .truffle .r .nodes .function .ClassHierarchyNode ;
2834import 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 ;
2938import com .oracle .truffle .r .runtime .RRuntime ;
3039import com .oracle .truffle .r .runtime .data .RDataFactory ;
3140import com .oracle .truffle .r .runtime .data .RIntVector ;
3241import com .oracle .truffle .r .runtime .data .RStringVector ;
3342import com .oracle .truffle .r .runtime .data .RTypes ;
3443import 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 ;
3547import com .oracle .truffle .r .runtime .nodes .RBaseNode ;
3648
3749/**
4052@ TypeSystemReference (RTypes .class )
4153public 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}
0 commit comments