RFR 8214971 : Replace use of string.equals("") with isEmpty()
Claes Redestad
claes.redestad at oracle.com
Fri Dec 7 12:51:10 UTC 2018
Hi,
On 2018-12-07 03:56, Stuart Marks wrote:
> On 12/6/18 2:42 PM, Claes Redestad wrote:
>> I filed this bug after seeing it in startup profiles, where isEmpty()
>> avoids an instanceof and four(!) method calls, so getting rid of a
>> few of these has a measurable impact on startup. It seemed prudent to
>> just replace it all while we're at it.
>
> Interesting. The compact strings stuff saves a lot of space, but it
> means that more setup work needs to be done before an actual equality
> comparison can be done. Thus, equals("") has gotten quite a bit more
> expensive relative to isEmpty() compared with the situation prior to
> compact strings.
>
> Still, it seems like a method call could be saved here:
>
> if (anObject instanceof String) {
> String aString = (String)anObject;
> if (coder() == aString.coder()) {
> return isLatin1() ? StringLatin1.equals(value,
> aString.value)
> : StringUTF16.equals(value,
> aString.value);
> }
> }
>
> by saving the result of coder() in a local variable and then comparing
> it directly to LATIN1. Is it worth it?
the reason this might be a bad idea is that guarding the coder field
reads in
methods that first test whether COMPACT_STRINGS is enabled enables the JIT
to better optimize away untaken code paths. This ensures optimal as can be
performance for the different run modes. See javadoc for COMPACT_STRINGS
in String.java[1] for some discussion on this.
One possible improvement would to wrap coder() == aString.coder() in a
method isSameCoder(String):
private boolean isSameCoder(String other) {
return COMPACT_STRINGS ? coder == other.coder : true;
}
.. one less method call, but still perfectly optimizable, so less taxing
during
startup with no peak performance drawback.
>
> (Note, this isn't relevant to the current review.)
But interesting nonetheless :-)
/Claes
[1]
/** * If String compaction is disabled, the bytes in {@code value} are *
always encoded in UTF16. * * For methods with several possible
implementation paths, when String * compaction is disabled, only one
code path is taken. * * The instance field value is generally opaque to
optimizing JIT * compilers. Therefore, in performance-sensitive place,
an explicit * check of the static boolean {@code COMPACT_STRINGS} is
done first * before checking the {@code coder} field since the static
boolean * {@code COMPACT_STRINGS} would be constant folded away by an *
optimizing JIT compiler. The idioms for these cases are as follows. * *
For code such as: * * if (coder == LATIN1) { ... } * * can be written
more optimally as * * if (coder() == LATIN1) { ... } * * or: * * if
(COMPACT_STRINGS && coder == LATIN1) { ... } * * An optimizing JIT
compiler can fold the above conditional as: * * COMPACT_STRINGS == true
=> if (coder == LATIN1) { ... } * COMPACT_STRINGS == false => if (false)
{ ... } * * @implNote * The actual value for this field is injected by
JVM. The static * initialization block is used to set the value here to
communicate * that this static final field is not statically foldable,
and to * avoid any possible circular dependency during vm
initialization. */
More information about the core-libs-dev
mailing list