RFR: 8308869: C2: use profile data in subtype checks when profile has more than one class [v6]

Roland Westrelin roland at openjdk.org
Wed Jun 21 07:05:07 UTC 2023


On Tue, 20 Jun 2023 23:35:59 GMT, Vladimir Ivanov <vlivanov at openjdk.org> wrote:

> I'm trying to understand what are the implications if you generate profile-based type guards early (during parsing). Any particular benefits from late expansion or downsides from early expansion? I'd expect that additional type info may be helpful (even though bimorphic/polymorphic cases are less useful than monomorphic one).

Late expansion allows some optimizations to trigger that wouldn't otherwise. Something like:


if (o.klass = profile1) {
  goto success; 
} else if (o.klass = profile2) {
  goto success;
} else if (o instanceof super) {
  goto success;
} else {
  goto failure;
}

is unlikely to optimize as well as:

if (o instanceof super) {
}

with split if, loop predication or finding a dominating if with an identical type check.

> Handling it during parsing would relieve `SubTypeCheck` from caring about profile data and enable placing an uncommon trap on slow path for bimorphic case. (Doing that during macro expansion would require `SubTypeCheckNode` to keep JVM state.)

Carrying the JVM state in the `SubTypeCheck` looks like too much extra complexity to me. With profiling of branches, we could get an uncommon trap in:


if (!(a instanceof super)) {
  // never taken
}


even if profile data reports more than a single receiver at the checkcast.

> What are the implications if you make profiling changes separately? My understanding is you gain access to accurate probabilities and ability to distinguish between bi-/poly-/mega-morphic cases. Is it correct?

Pushing this without the change to profile data collection? We have no way to tell if, when profile data reports 2 classes, they are common or not. So yes, that's correct.

> Speaking of alternative ways to pass profile info around, you could just embed `ciCallProfile` in `SubTypeCheck`. Any particular reasons not to do so?

It felt easier in terms of memory management. If we have some extra data embedded in the `SubTypeCheck` node, is it a pointer or the full data structure? If it is a pointer, do we clone the data on node clone? Try to reclaim memory on node destruction? Where should the data live so it's not destroyed while we need it but doesn't live longer that's required?

-------------

PR Comment: https://git.openjdk.org/jdk/pull/14375#issuecomment-1600291223


More information about the hotspot-compiler-dev mailing list