33
33
34
34
import com .oracle .svm .core .heap .UnknownObjectField ;
35
35
import com .oracle .svm .core .util .VMError ;
36
+ import com .oracle .svm .espresso .classfile .ConstantPool ;
36
37
import com .oracle .svm .espresso .classfile .ParserConstantPool ;
37
- import com .oracle .svm .espresso .classfile .descriptors .Symbol ;
38
38
import com .oracle .svm .interpreter .metadata .serialization .VisibleForSerialization ;
39
39
40
- import jdk .vm .ci .meta .ConstantPool ;
41
40
import jdk .vm .ci .meta .JavaConstant ;
42
41
import jdk .vm .ci .meta .JavaField ;
43
42
import jdk .vm .ci .meta .JavaMethod ;
44
43
import jdk .vm .ci .meta .JavaType ;
45
44
import jdk .vm .ci .meta .ResolvedJavaMethod ;
46
45
import jdk .vm .ci .meta .Signature ;
46
+ import jdk .vm .ci .meta .UnresolvedJavaField ;
47
+ import jdk .vm .ci .meta .UnresolvedJavaMethod ;
48
+ import jdk .vm .ci .meta .UnresolvedJavaType ;
47
49
48
- public final class InterpreterConstantPool extends com .oracle .svm .espresso .classfile .ConstantPool implements ConstantPool {
50
+ /**
51
+ * JVMCI's {@link jdk.vm.ci.meta.ConstantPool} is not designed to be used in a performance-sensitive
52
+ * bytecode interpreter, so a Espresso-like CP implementation is used instead for performance.
53
+ * <p>
54
+ * This class doesn't support runtime resolution on purpose, but supports pre-resolved entries
55
+ * instead for AOT types.
56
+ */
57
+ public class InterpreterConstantPool extends ConstantPool implements jdk .vm .ci .meta .ConstantPool {
58
+
59
+ final InterpreterResolvedObjectType holder ;
60
+ final ParserConstantPool parserConstantPool ;
49
61
50
- private final InterpreterResolvedObjectType holder ;
51
62
// Assigned after analysis.
52
- @ UnknownObjectField (types = Object [].class ) private Object [] entries ;
63
+ @ UnknownObjectField (types = Object [].class ) protected Object [] cachedEntries ;
53
64
54
65
Object objAt (int cpi ) {
55
66
if (cpi == 0 ) {
@@ -60,23 +71,28 @@ Object objAt(int cpi) {
60
71
// where an appropriate error should be thrown.
61
72
throw VMError .shouldNotReachHere ("Cannot resolve CP entry 0" );
62
73
}
63
- return entries [cpi ];
74
+ return cachedEntries [cpi ];
64
75
}
65
76
66
- private InterpreterConstantPool (InterpreterResolvedObjectType holder , Object [] entries ) {
67
- super (new byte []{}, new int []{}, Symbol . EMPTY_ARRAY , 0 , 0 );
77
+ protected InterpreterConstantPool (InterpreterResolvedObjectType holder , ParserConstantPool parserConstantPool , Object [] cachedEntries ) {
78
+ super (parserConstantPool );
68
79
this .holder = MetadataUtil .requireNonNull (holder );
69
- this .entries = MetadataUtil .requireNonNull (entries );
80
+ this .parserConstantPool = parserConstantPool ;
81
+ this .cachedEntries = MetadataUtil .requireNonNull (cachedEntries );
82
+ }
83
+
84
+ protected InterpreterConstantPool (InterpreterResolvedObjectType holder , ParserConstantPool parserConstantPool ) {
85
+ this (holder , parserConstantPool , new Object [parserConstantPool .length ()]);
70
86
}
71
87
72
88
@ VisibleForSerialization
73
- public static InterpreterConstantPool create (InterpreterResolvedObjectType holder , Object [] entries ) {
74
- return new InterpreterConstantPool (holder , entries );
89
+ public static InterpreterConstantPool create (InterpreterResolvedObjectType holder , ParserConstantPool parserConstantPool , Object [] cachedEntries ) {
90
+ return new InterpreterConstantPool (holder , parserConstantPool , cachedEntries );
75
91
}
76
92
77
93
@ Override
78
94
public int length () {
79
- return entries .length ;
95
+ return cachedEntries .length ;
80
96
}
81
97
82
98
@ Override
@@ -128,25 +144,24 @@ public JavaConstant lookupAppendix(int cpi, int opcode) {
128
144
129
145
@ VisibleForSerialization
130
146
@ Platforms (Platform .HOSTED_ONLY .class )
131
- public Object [] getEntries () {
132
- return entries ;
147
+ public Object [] getCachedEntries () {
148
+ return cachedEntries ;
149
+ }
150
+
151
+ public Object peekCachedEntry (int cpi ) {
152
+ return cachedEntries [cpi ];
133
153
}
134
154
135
155
public InterpreterResolvedObjectType getHolder () {
136
156
return holder ;
137
157
}
138
158
139
- // region Unimplemented methods
140
-
141
159
@ Override
142
160
public RuntimeException classFormatError (String message ) {
143
161
throw new ClassFormatError (message );
144
162
}
145
163
146
- @ Override
147
- public ParserConstantPool getParserConstantPool () {
148
- throw VMError .unimplemented ("getParserConstantPool" );
149
- }
164
+ // region Unimplemented methods
150
165
151
166
@ Override
152
167
public void loadReferencedType (int cpi , int opcode ) {
@@ -169,4 +184,89 @@ public Signature lookupSignature(int cpi) {
169
184
}
170
185
171
186
// endregion Unimplemented methods
187
+
188
+ @ Override
189
+ public ParserConstantPool getParserConstantPool () {
190
+ return parserConstantPool ;
191
+ }
192
+
193
+ protected Object resolve (int cpi , @ SuppressWarnings ("unused" ) InterpreterResolvedObjectType accessingClass ) {
194
+ assert Thread .holdsLock (this );
195
+ assert cpi != 0 ; // guaranteed by the caller
196
+
197
+ @ SuppressWarnings ("unused" )
198
+ Tag tag = tagAt (cpi ); // CPI bounds check
199
+
200
+ Object entry = cachedEntries [cpi ];
201
+ if (isUnresolved (entry )) {
202
+ /*
203
+ * Runtime resolution is deliberately unsupported for AOT types (using base
204
+ * InterpreterConstantPool). This can be relaxed in the future e.g. by attaching a
205
+ * RuntimeInterpreterConstantPool instead.
206
+ */
207
+ throw new UnsupportedResolutionException ();
208
+ }
209
+
210
+ return entry ;
211
+ }
212
+
213
+ public Object resolvedAt (int cpi , InterpreterResolvedObjectType accessingClass ) {
214
+ Object entry = cachedEntries [cpi ];
215
+ if (isUnresolved (entry )) {
216
+ // TODO(peterssen): GR-68611 Avoid deadlocks when hitting breakpoints (JDWP debugger)
217
+ // during class resolution.
218
+ /*
219
+ * Class resolution can run arbitrary code (not in the to-be resolved class <clinit>
220
+ * but) in the user class loaders where it can hit a breakpoint (JDWP debugger), causing
221
+ * a deadlock.
222
+ */
223
+ synchronized (this ) {
224
+ entry = cachedEntries [cpi ];
225
+ if (isUnresolved (entry )) {
226
+ cachedEntries [cpi ] = entry = resolve (cpi , accessingClass );
227
+ }
228
+ }
229
+ }
230
+
231
+ assert !isUnresolved (entry );
232
+ if (entry instanceof Throwable throwable ) {
233
+ // Cached exception.
234
+ throw uncheckedThrow (throwable );
235
+ }
236
+
237
+ return entry ;
238
+ }
239
+
240
+ private static boolean isUnresolved (Object entry ) {
241
+ return entry == null || entry instanceof UnresolvedJavaType || entry instanceof UnresolvedJavaMethod || entry instanceof UnresolvedJavaField ;
242
+ }
243
+
244
+ @ SuppressWarnings ("unchecked" )
245
+ private static <T extends Throwable > RuntimeException uncheckedThrow (Throwable t ) throws T {
246
+ throw (T ) t ;
247
+ }
248
+
249
+ public InterpreterResolvedJavaField resolvedFieldAt (InterpreterResolvedObjectType accessingKlass , int cpi ) {
250
+ Object resolvedEntry = resolvedAt (cpi , accessingKlass );
251
+ assert resolvedEntry != null ;
252
+ return (InterpreterResolvedJavaField ) resolvedEntry ;
253
+ }
254
+
255
+ public InterpreterResolvedJavaMethod resolvedMethodAt (InterpreterResolvedObjectType accessingKlass , int cpi ) {
256
+ Object resolvedEntry = resolvedAt (cpi , accessingKlass );
257
+ assert resolvedEntry != null ;
258
+ return (InterpreterResolvedJavaMethod ) resolvedEntry ;
259
+ }
260
+
261
+ public InterpreterResolvedObjectType resolvedTypeAt (InterpreterResolvedObjectType accessingKlass , int cpi ) {
262
+ Object resolvedEntry = resolvedAt (cpi , accessingKlass );
263
+ assert resolvedEntry != null ;
264
+ return (InterpreterResolvedObjectType ) resolvedEntry ;
265
+ }
266
+
267
+ public String resolveStringAt (int cpi ) {
268
+ Object resolvedEntry = resolvedAt (cpi , null );
269
+ assert resolvedEntry != null ;
270
+ return (String ) resolvedEntry ;
271
+ }
172
272
}
0 commit comments