3333
3434import com .oracle .svm .core .heap .UnknownObjectField ;
3535import com .oracle .svm .core .util .VMError ;
36+ import com .oracle .svm .espresso .classfile .ConstantPool ;
3637import com .oracle .svm .espresso .classfile .ParserConstantPool ;
37- import com .oracle .svm .espresso .classfile .descriptors .Symbol ;
3838import com .oracle .svm .interpreter .metadata .serialization .VisibleForSerialization ;
3939
40- import jdk .vm .ci .meta .ConstantPool ;
4140import jdk .vm .ci .meta .JavaConstant ;
4241import jdk .vm .ci .meta .JavaField ;
4342import jdk .vm .ci .meta .JavaMethod ;
4443import jdk .vm .ci .meta .JavaType ;
4544import jdk .vm .ci .meta .ResolvedJavaMethod ;
4645import 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 ;
4749
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 ;
4961
50- private final InterpreterResolvedObjectType holder ;
5162 // Assigned after analysis.
52- @ UnknownObjectField (types = Object [].class ) private Object [] entries ;
63+ @ UnknownObjectField (types = Object [].class ) protected Object [] cachedEntries ;
5364
5465 Object objAt (int cpi ) {
5566 if (cpi == 0 ) {
@@ -60,23 +71,28 @@ Object objAt(int cpi) {
6071 // where an appropriate error should be thrown.
6172 throw VMError .shouldNotReachHere ("Cannot resolve CP entry 0" );
6273 }
63- return entries [cpi ];
74+ return cachedEntries [cpi ];
6475 }
6576
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 );
6879 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 ()]);
7086 }
7187
7288 @ 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 );
7591 }
7692
7793 @ Override
7894 public int length () {
79- return entries .length ;
95+ return cachedEntries .length ;
8096 }
8197
8298 @ Override
@@ -128,25 +144,24 @@ public JavaConstant lookupAppendix(int cpi, int opcode) {
128144
129145 @ VisibleForSerialization
130146 @ 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 ];
133153 }
134154
135155 public InterpreterResolvedObjectType getHolder () {
136156 return holder ;
137157 }
138158
139- // region Unimplemented methods
140-
141159 @ Override
142160 public RuntimeException classFormatError (String message ) {
143161 throw new ClassFormatError (message );
144162 }
145163
146- @ Override
147- public ParserConstantPool getParserConstantPool () {
148- throw VMError .unimplemented ("getParserConstantPool" );
149- }
164+ // region Unimplemented methods
150165
151166 @ Override
152167 public void loadReferencedType (int cpi , int opcode ) {
@@ -169,4 +184,89 @@ public Signature lookupSignature(int cpi) {
169184 }
170185
171186 // 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+ }
172272}
0 commit comments