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. */

Reply via email to