24
24
*/
25
25
package com .oracle .svm .core .graal .snippets ;
26
26
27
+ import static com .oracle .svm .core .hub .DynamicHubTypeCheckUtil .HASHING_INTERFACE_MASK ;
28
+ import static com .oracle .svm .core .hub .DynamicHubTypeCheckUtil .HASHING_ITABLE_SHIFT ;
29
+ import static com .oracle .svm .core .hub .DynamicHubTypeCheckUtil .HASHING_SHIFT_OFFSET ;
30
+ import static jdk .graal .compiler .nodes .extended .BranchProbabilityNode .probability ;
27
31
import static jdk .graal .compiler .nodes .extended .BranchProbabilityNode .unknownProbability ;
28
32
29
33
import java .util .Map ;
30
34
31
35
import org .graalvm .nativeimage .ImageSingletons ;
32
36
import org .graalvm .word .LocationIdentity ;
33
37
38
+ import com .oracle .svm .core .SubstrateOptions ;
34
39
import com .oracle .svm .core .config .ObjectLayout ;
35
40
import com .oracle .svm .core .graal .meta .KnownOffsets ;
36
41
import com .oracle .svm .core .graal .nodes .LoadOpenTypeWorldDispatchTableStartingOffset ;
37
42
import com .oracle .svm .core .hub .DynamicHub ;
43
+ import com .oracle .svm .core .hub .DynamicHubTypeCheckUtil ;
38
44
import com .oracle .svm .core .meta .SharedMethod ;
39
45
import com .oracle .svm .core .meta .SharedType ;
40
46
41
47
import jdk .graal .compiler .api .replacements .Snippet ;
48
+ import jdk .graal .compiler .core .common .NumUtil ;
42
49
import jdk .graal .compiler .graph .Node ;
43
50
import jdk .graal .compiler .nodes .ConstantNode ;
44
51
import jdk .graal .compiler .nodes .NamedLocationIdentity ;
45
52
import jdk .graal .compiler .nodes .UnreachableNode ;
53
+ import jdk .graal .compiler .nodes .extended .BranchProbabilityNode ;
46
54
import jdk .graal .compiler .nodes .spi .LoweringTool ;
47
55
import jdk .graal .compiler .options .OptionValues ;
48
56
import jdk .graal .compiler .phases .util .Providers ;
57
+ import jdk .graal .compiler .replacements .ReplacementsUtil ;
49
58
import jdk .graal .compiler .replacements .SnippetTemplate ;
50
59
import jdk .graal .compiler .replacements .Snippets ;
51
60
import jdk .graal .compiler .word .ObjectAccess ;
@@ -56,28 +65,40 @@ public final class OpenTypeWorldDispatchTableSnippets extends SubstrateTemplates
56
65
@ Snippet
57
66
private static long loadITableStartingOffset (
58
67
@ Snippet .NonNullParameter DynamicHub hub ,
59
- int interfaceTypeID ) {
60
- return determineITableStartingOffset (hub , interfaceTypeID );
68
+ int interfaceID ,
69
+ @ Snippet .ConstantParameter boolean useInterfaceHashing ) {
70
+ if (useInterfaceHashing && probability (BranchProbabilityNode .FAST_PATH_PROBABILITY , interfaceID <= SubstrateOptions .interfaceHashingMaxId ())) {
71
+ return determineITableStartingOffsetHashed (hub , interfaceID );
72
+ }
73
+ return determineITableStartingOffsetIterative (hub , interfaceID );
61
74
}
62
75
63
76
@ Snippet
64
77
private static long loadDispatchTableStartingOffset (
65
78
@ Snippet .NonNullParameter DynamicHub hub ,
66
- int interfaceTypeID , @ Snippet .ConstantParameter int vtableStartingOffset ) {
67
- if (unknownProbability (interfaceTypeID >= 0 )) {
68
- return determineITableStartingOffset (hub , interfaceTypeID );
79
+ int interfaceID , @ Snippet .ConstantParameter int vtableStartingOffset ,
80
+ @ Snippet .ConstantParameter boolean useInterfaceHashing ) {
81
+ if (unknownProbability (interfaceID >= 0 )) {
82
+ if (useInterfaceHashing && probability (BranchProbabilityNode .FAST_PATH_PROBABILITY , interfaceID <= SubstrateOptions .interfaceHashingMaxId ())) {
83
+ return determineITableStartingOffsetHashed (hub , interfaceID );
84
+ }
85
+ return determineITableStartingOffsetIterative (hub , interfaceID );
69
86
} else {
70
87
// the class dispatch table is always first
71
88
return vtableStartingOffset ;
72
89
}
73
90
}
74
91
75
- public static long determineITableStartingOffset (
92
+ /**
93
+ * Iterative lookup of itable starting offsets used if
94
+ * {@link SubstrateOptions#useInterfaceHashing()} is disabled or if the interfaceID exceeds
95
+ * {@link SubstrateOptions#interfaceHashingMaxId()}.
96
+ */
97
+ private static long determineITableStartingOffsetIterative (
76
98
DynamicHub checkedHub ,
77
99
int interfaceID ) {
78
-
79
100
int numClassTypes = checkedHub .getNumClassTypes ();
80
- int numInterfaceTypes = checkedHub .getNumInterfaceTypes ();
101
+ int numInterfaceTypes = checkedHub .getNumIterableInterfaceTypes ();
81
102
int [] checkedTypeIds = checkedHub .getOpenTypeWorldTypeCheckSlots ();
82
103
for (int i = 0 ; i < numInterfaceTypes * 2 ; i += 2 ) {
83
104
// int checkedInterfaceId = checkedTypeIds[numClassTypes + i];
@@ -94,6 +115,76 @@ public static long determineITableStartingOffset(
94
115
throw UnreachableNode .unreachable ();
95
116
}
96
117
118
+ /**
119
+ * If {@link SubstrateOptions#useInterfaceHashing()} is enabled, interfaceIDs and itable
120
+ * starting offsets are stored in a hash table (see TypeCheckBuilder for a general
121
+ * documentation). This snippet handles the lookup in the hash table and returns the itable
122
+ * starting offset for the given interfaceID. See
123
+ * {@link DynamicHubTypeCheckUtil#hashParam(int[])} for details on the hashing function and
124
+ * hashing parameter.
125
+ */
126
+ private static int determineITableStartingOffsetHashed (
127
+ DynamicHub checkedHub ,
128
+ int interfaceID ) {
129
+ ReplacementsUtil .dynamicAssert (NumUtil .isUShort (interfaceID ), "InterfaceIDs must fit in a short to be used for hashing." );
130
+
131
+ // The upper byte of the hashParam holds the shift value, the lower three bytes hold p
132
+ // which is used for bitwise "and": hashParam = shift << HASHING_SHIFT_OFFSET | p.
133
+ int hashParam = checkedHub .getOpenTypeWorldInterfaceHashParam ();
134
+ int shift = hashParam >>> HASHING_SHIFT_OFFSET ;
135
+ int [] hashTable = checkedHub .getOpenTypeWorldInterfaceHashTable ();
136
+
137
+ // No need to mask hashParam to get "p". interfaceID fits in a short -> the two upper
138
+ // bytes are 0.
139
+ int hash = (interfaceID >>> shift ) & hashParam ;
140
+ int offset = (int ) ImageSingletons .lookup (ObjectLayout .class ).getArrayElementOffset (JavaKind .Int , hash );
141
+ int hashTableEntry = ObjectAccess .readInt (hashTable , offset , NamedLocationIdentity .FINAL_LOCATION );
142
+
143
+ // Hashtable entries contain integers which hold the iTableOffset and the interfaceID:
144
+ // hashTableEntry = iTableOffset << HASHING_ITABLE_SHIFT | interfaceID
145
+ ReplacementsUtil .dynamicAssert (interfaceID == (hashTableEntry & HASHING_INTERFACE_MASK ), "InterfaceIDs do not match." );
146
+ return (hashTableEntry >>> HASHING_ITABLE_SHIFT );
147
+ }
148
+
149
+ public static long determineITableStartingOffset (
150
+ DynamicHub checkedHub ,
151
+ int interfaceID ) {
152
+ if (SubstrateOptions .useInterfaceHashing ()) {
153
+ // Use the non-snippet version which contains no snippet asserts.
154
+ return determineITableStartingOffsetHashedNonSnippet (checkedHub , interfaceID );
155
+ } else {
156
+ return determineITableStartingOffsetIterative (checkedHub , interfaceID );
157
+ }
158
+ }
159
+
160
+ /**
161
+ * IMPORTANT: Has to be identical to {@link #determineITableStartingOffsetHashed} but with
162
+ * "real" {@code assert}s instead of {@link ReplacementsUtil#dynamicAssert}. Required for being
163
+ * called outside of snippets.
164
+ */
165
+ private static int determineITableStartingOffsetHashedNonSnippet (
166
+ DynamicHub checkedHub ,
167
+ int interfaceID ) {
168
+ assert NumUtil .isUShort (interfaceID ) : "InterfaceIDs must fit in a short to be used for hashing." ;
169
+
170
+ // The upper byte of the hashParam holds the shift value, the lower three bytes hold p
171
+ // which is used for bitwise "and": hashParam = shift << HASHING_SHIFT_OFFSET | p.
172
+ int hashParam = checkedHub .getOpenTypeWorldInterfaceHashParam ();
173
+ int shift = hashParam >>> HASHING_SHIFT_OFFSET ;
174
+ int [] hashTable = checkedHub .getOpenTypeWorldInterfaceHashTable ();
175
+
176
+ // No need to mask hashParam to get "p". interfaceID fits in a short -> the two upper
177
+ // bytes are 0.
178
+ int hash = (interfaceID >>> shift ) & hashParam ;
179
+ int offset = (int ) ImageSingletons .lookup (ObjectLayout .class ).getArrayElementOffset (JavaKind .Int , hash );
180
+ int hashTableEntry = ObjectAccess .readInt (hashTable , offset , NamedLocationIdentity .FINAL_LOCATION );
181
+
182
+ // Hashtable entries contain integers which hold the iTableOffset and the interfaceID:
183
+ // hashTableEntry = iTableOffset << HASHING_ITABLE_SHIFT | interfaceID
184
+ assert interfaceID == (hashTableEntry & HASHING_INTERFACE_MASK ) : "InterfaceIDs do not match." ;
185
+ return (hashTableEntry >>> HASHING_ITABLE_SHIFT );
186
+ }
187
+
97
188
private final SnippetTemplate .SnippetInfo loadITableStartingOffset ;
98
189
private final SnippetTemplate .SnippetInfo loadDispatchTableStartingOffset ;
99
190
@@ -136,7 +227,8 @@ public void lower(LoadOpenTypeWorldDispatchTableStartingOffset node, LoweringToo
136
227
if (target .getDeclaringClass ().isInterface ()) {
137
228
SnippetTemplate .Arguments args = new SnippetTemplate .Arguments (loadITableStartingOffset , node .graph (), tool .getLoweringStage ());
138
229
args .add ("hub" , node .getHub ());
139
- args .add ("interfaceTypeID" , ((SharedType ) target .getDeclaringClass ()).getTypeID ());
230
+ args .add ("interfaceID" , ((SharedType ) target .getDeclaringClass ()).getInterfaceID ());
231
+ args .add ("useInterfaceHashing" , SubstrateOptions .useInterfaceHashing ());
140
232
template (tool , node , args ).instantiate (tool .getMetaAccess (), node , SnippetTemplate .DEFAULT_REPLACER , args );
141
233
142
234
} else {
@@ -150,8 +242,9 @@ public void lower(LoadOpenTypeWorldDispatchTableStartingOffset node, LoweringToo
150
242
*/
151
243
SnippetTemplate .Arguments args = new SnippetTemplate .Arguments (loadDispatchTableStartingOffset , node .graph (), tool .getLoweringStage ());
152
244
args .add ("hub" , node .getHub ());
153
- args .add ("interfaceTypeID " , node .getInterfaceTypeID ());
245
+ args .add ("interfaceID " , node .getInterfaceID ());
154
246
args .add ("vtableStartingOffset" , vtableStartingOffset );
247
+ args .add ("useInterfaceHashing" , SubstrateOptions .useInterfaceHashing ());
155
248
template (tool , node , args ).instantiate (tool .getMetaAccess (), node , SnippetTemplate .DEFAULT_REPLACER , args );
156
249
}
157
250
}
0 commit comments