RFR 8222289: Overhaul logic for reading/writing constant pool entries

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Apr 10 17:55:27 UTC 2019


Hi,
this patch significantly rewrites the way in which constant pool entries 
are read/written/handled by javac. A good description of the issues in 
the current architecture is given in the JBS entry [4].

Webrev:

http://cr.openjdk.java.net/~mcimadamore/8222289/

A crucial part of the solution is the new PoolConstant interface. This 
is an interface that all javac entities that want to be written onto the 
constant pool must adhere to. The interface has methods for obtaining a 
pool tag, and, crucially, to obtain a unique key with which the entity 
can be stored in the pool data structure, so as to quickly check for 
duplicates.

I've also defined a sub-interface of the PoolConstant interface called 
LoadableConstant, which represents the pool constants that can be loaded 
with ldc, and stored as static args to bootstrap methods in indy/condy.

DynamicMethodSymbol now has been rewritten to express static argument 
list using LoadableConstant, rather than Object.

This patch takes care of most issues in the existing architecture; most 
notably, thanks to PoolReader, most of the duplication in 
ModuleNameReader can be removed. Also, I've took great care in removing 
all eager conversions to pool indices ahead of instruction writing 
(which then resulted in back-requests to the pool in order to fetch the 
entry at given address from the Code class). To do this, I tweaked the 
Code class a bit, so that all methods for emitting opcodes will now take 
a pool constant object (which can be null if an instruction does not 
refer to the pool).

Some changes were also necessary in Items, more specifically, in order 
to represent the value of an ImmediateItem as a LoadableConstant, rather 
than just an Object.

The PoolWriter/Reader API is mostly straightforward, with a bunch of 
putXYZ/getXYZ methods, where XYZ is some Javac entity that needs to be 
written/read. Among the things to note, PoolWriter needs some special 
logic to handle the case where a pool entry write request is generated 
in the middle of another request (a queue has been used to deal with 
this). The PoolReader uses the same two-phase index + resolution  
approach used currently by ClassReader (resolving all entries eagerly is 
not only a performance nightmare, since not all entries will be used, 
but also a source of bugs, since javac is very sensitive to when entries 
- esp. those for classes - are turned into real symbols).

Extensive testing has been carried out. All relevant tests pass on the 
new code. In addition to that, I also compared the output of javac 
before/after the patch and made sure the results were the same. Since 
the output in general is different (the CP indices before/after are 
different), I have put together a javap patch [5] which stabilizes the 
javap output by normalizing all CP indices. This has proven to be a very 
useful tool, and we might pursue that on a followup change.

Performance testing has also been carried out using our internal tools - 
all results seem to indicate that, at worst, the new code is 1.5% slower 
than the old one. Given that the new code is significantly more 
expressive than the old one, I think the performance difference is 
totally acceptable. Furthermore, when value types will be available I 
expect a lot of the cost associated with boxing constants (e.g. from 
String to LoadableConstant) to fade away.


Alternatives considered:

* Model the constant pool with a proper hierarchy of classes each of 
which models a different CP entry. This approach has been tried in 
Valhalla (see [1], [2] and [3]), but ultimately it was rejected because 
it was not possible to make it perform in a way that was satisfactory. 
Also, when reading the pool, fully materializing the entries (even the 
unused ones) was prohibitive, and was avoided (even in the Valhalla 
branch) in order to have acceptable performances.

* Use the new ConstantDesc; while this approach has the potential to get 
rid of the nasty boxing for primitive constants (thanks to the fact that 
e.g. String already implements ConstantDesc), the ConstantDesc API is 
not sufficiently expressive for modeling an entire constant pool. First, 
not all entries are modeled (e.g. only loadable constant are, by 
design); secondly, there's no way to query e.g. the pool tag given a 
ConstantDesc. We might revise the implementation should some of these 
issues be addressed in future releases.

Cheers
Maurizio


[1] - 
http://hg.openjdk.java.net/valhalla/valhalla9/langtools/file/85cc92a65da8/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolWriter.java
[2] - 
http://hg.openjdk.java.net/valhalla/valhalla9/langtools/file/85cc92a65da8/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/PoolReader.java
[3] - 
http://hg.openjdk.java.net/valhalla/valhalla9/langtools/file/85cc92a65da8/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Pool.java
[4] - https://bugs.openjdk.java.net/browse/JDK-8222289
[5] - http://cr.openjdk.java.net/~mcimadamore/x-javapStableOutput_v3/




More information about the compiler-dev mailing list