Skip to content

Conversation

@rwestrel
Copy link
Contributor

@rwestrel rwestrel commented Oct 28, 2022

This change is mostly the same I sent for review 3 years ago but was
never integrated:

https://mail.openjdk.org/pipermail/hotspot-compiler-dev/2019-May/033803.html

The main difference is that, in the meantime, I submitted a couple of
refactoring changes extracted from the 2019 patch:

8266550: C2: mirror TypeOopPtr/TypeInstPtr/TypeAryPtr with TypeKlassPtr/TypeInstKlassPtr/TypeAryKlassPtr
8275201: C2: hide klass() accessor from TypeOopPtr and typeKlassPtr subclasses

As a result, the current patch is much smaller (but still not small).

The implementation is otherwise largely the same as in the 2019
patch. I tried to remove some of the code duplication between the
TypeOopPtr and TypeKlassPtr hierarchies by having some of the logic
shared in template methods. In the 2019 patch, interfaces were trusted
when types were constructed and I had added code to drop interfaces
from a type where they couldn't be trusted. This new patch proceeds
the other way around: interfaces are not trusted when a type is
constructed and code that uses the type must explicitly request that
they are included (this was suggested as an improvement by Vladimir
Ivanov I think).


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-6312651: Compiler should only use verified interface types for optimization

Reviewers

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/10901/head:pull/10901
$ git checkout pull/10901

Update a local copy of the PR:
$ git checkout pull/10901
$ git pull https://git.openjdk.org/jdk pull/10901/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 10901

View PR using the GUI difftool:
$ git pr show -t 10901

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/10901.diff

@bridgekeeper
Copy link

bridgekeeper bot commented Oct 28, 2022

👋 Welcome back roland! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@openjdk
Copy link

openjdk bot commented Oct 28, 2022

@rwestrel The following label will be automatically applied to this pull request:

  • hotspot-compiler

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command.

@openjdk openjdk bot added the hotspot-compiler hotspot-compiler-dev@openjdk.org label Oct 28, 2022
@openjdk openjdk bot added the rfr Pull request is ready for review label Oct 28, 2022
@mlbridge
Copy link

mlbridge bot commented Oct 28, 2022

Webrevs

Copy link
Contributor

@iwanowww iwanowww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, Roland! Overall, looks very good.

Submitted hs-tier1 - hs-tier4 testing. (Earlier, it went through hs-tier1 - hs-tier8 without new failures.)

Some minor comments/suggestions follow.

GrowableArray<ciInstanceKlass*>* ciInstanceKlass::transitive_interfaces() const {
GrowableArray<ciInstanceKlass*>* result = NULL;
GUARDED_VM_ENTRY(
InstanceKlass* ik = get_instanceKlass();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to cache the result on ciInstanceKlass instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe but it's not as simple as it seems (for the reason discussed below for vm classes). Some classes are allocated in a special arena because they are shared between compilations. A _transitive_interfaces array would need to be allocated in that same arena (otherwise if lazily allocated during a particular compilation it would be in the thread's resource are and its content would be wiped out when the compilation is over but still reachable). That's not straightforward with the current implementation as the arena a ciInstanceKlass is allocated in is not available to the ciInstanceKlass so that would require extra changes and I'm not sure the extra complexity is worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

scratch that. I see it's done for _nonstatic_fields and will do the same.

if (vmClasses::name##_is_loaded()) { \
InstanceKlass* ik = vmClasses::name(); \
ciEnv::_##name = get_metadata(ik)->as_instance_klass(); \
Array<InstanceKlass*>* interfaces = ik->transitive_interfaces(); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of interface-related part of the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ciInstanceKlass objects for the vm classes all need to be allocated from the same long lived arena that's created in ciObjectFactory::initialize() because they are shared between compilations. Without that code, the ciInstanceKlass for a particular vm class is in the long lived arena but the ciInstanceKlass objects for the interfaces are created later when they are needed in the arena of some compilation. Once that compilation is over the interface objects are destroyed but still referenced from shared types such as TypeInstPtr::MIRROR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, got it now. Is it really needed considering there's transitive_interfaces() call later?

// If the klass is final, the resulting type will be exact.
static const TypeOopPtr* make_from_klass(ciKlass* klass) {
return make_from_klass_common(klass, true, false);
static const TypeOopPtr* make_from_klass(ciKlass* klass, bool trust_interface = false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to use an enum (trust_interfaces/ignore_interfaces) instead of a bool, so the intention is clear at call sites.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion. I will make that change.

mreg2type[Op_RegFlags] = TypeInt::CC;

TypeAryPtr::_array_interfaces = new TypePtr::InterfaceSet();
GrowableArray<ciInstanceKlass*>* array_interfaces = ciArrayKlass::interfaces();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move the code into a constructor or a factory method?
After that, the only user of TypePtr::InterfaceSet::add() will be TypePtr::interfaces().
It would be nice to make TypePtr::InterfaceSet immutable and cache query results (InterfaceSet::is_loaded() and InterfaceSet::exact_klass()).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good suggestion as well.

}
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), false, NULL, offset, instance_id, speculative, depth);
interfaces = this_interfaces.intersection_with(tp_interfaces);
return TypeInstPtr::make(ptr, ciEnv::current()->Object_klass(), interfaces, false, NULL,offset, instance_id, speculative, depth);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NULL,offset

missing space

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.

// below the centerline when the superclass is exact. We need to
// do the same here.
if (klass()->equals(ciEnv::current()->Object_klass()) && !klass_is_exact()) {
if (klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces.intersection_with(tp_interfaces).eq(this_interfaces) && !klass_is_exact()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this_interfaces.intersection_with(tp_interfaces).eq(this_interfaces)

Maybe a case for a helper method InterfaceSet::contains(InterfaceSet)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, there are several uses of this pattern. I will make that change.

ciInstanceKlass* ik = k->as_instance_klass();
bool klass_is_exact = ik->is_final();
if (!klass_is_exact &&
deps != NULL && UseUniqueSubclasses) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, put UseUniqueSubclasses guard at the top of the method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.

@iwanowww
Copy link
Contributor

iwanowww commented Nov 7, 2022

BTW will there still be a need in CastPP vs CheckCastPP dichotomy once the patch goes in?

@rwestrel
Copy link
Contributor Author

rwestrel commented Nov 8, 2022

BTW will there still be a need in CastPP vs CheckCastPP dichotomy once the patch goes in?

In principle, probably not.

@rwestrel
Copy link
Contributor Author

rwestrel commented Nov 9, 2022

Thanks, Roland! Overall, looks very good.

Thanks for reviewing this. I pushed new commits that should address your comments/suggestions.

Copy link
Contributor

@iwanowww iwanowww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much better, thanks!

Minor comments/suggestions follow.

FTR test results are clean. I'll submit performance testing shortly.

if (vmClasses::name##_is_loaded()) { \
InstanceKlass* ik = vmClasses::name(); \
ciEnv::_##name = get_metadata(ik)->as_instance_klass(); \
Array<InstanceKlass*>* interfaces = ik->transitive_interfaces(); \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, got it now. Is it really needed considering there's transitive_interfaces() call later?

}
}

GrowableArray<ciInstanceKlass*>* ciArrayKlass::interfaces() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR there's a subtle asymmetry between ciArrayKlass::interfaces() and ciInstanceKlass::transitive_interfaces() when it comes to memory allocation: the former allocates from resource area while the latter from compiler arena.

It doesn't cause any problems since ciArrayKlass::interfaces() is used only in Type::Initialize_shared() to instantiate shared TypeAryPtr::_array_interfaces, but it took me some time to find that out.

Maybe a helper method in type.cpp is a better place for that logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would that work? ciArrayKlass::interfaces() has to transition into the vm which is not something that would feel right in type.cpp.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, good point.

IMO you could just work directly with CI mirrors for Serializable and Cloneable, but now I'm curious why does CI code diverge from ObjArrayKlass::compute_secondary_supers()?
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/oops/objArrayKlass.cpp#L376

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And to answer my question: only Serializable and Cloneable are interfaces among those. The rest are arrays.

GrowableArray<ciInstanceKlass*>* ciInstanceKlass::transitive_interfaces() {
if (_transitive_interfaces == NULL) {
GUARDED_VM_ENTRY(
InstanceKlass* ik = get_instanceKlass();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A candidate for compute_transitive_interfaces() helper method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in new commit.

// return the ConP(Foo.klass)
assert(mirror_type->is_klass(), "mirror_type should represent a Klass*");
return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass()));
return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass(), Type::trust_interfaces));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

//
assert(loaded->ptr() != TypePtr::Null, "insanity check");
//
if( loaded->ptr() == TypePtr::TopPTR ) { return unloaded; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after if.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


// Both are unloaded, not the same class, not Object
// Or meet unloaded with a different loaded class, not java/lang/Object
if( ptr != TypePtr::BotPTR ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after if.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@rwestrel
Copy link
Contributor Author

Much better, thanks!

Minor comments/suggestions follow.

FTR test results are clean. I'll submit performance testing shortly.

Thanks. I updated the patch and removed the interface specific code in the VM_CLASS_DEFN() macro that's indeed no longer needed.

@iwanowww
Copy link
Contributor

FTR performance results look good.

Copy link
Contributor

@iwanowww iwanowww left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, Roland! I'm approving the PR. (hs-tier1 - hs-tier2 sanity testing passed with latest version.)

Feel free to handle ciArrayKlass::interfaces() as you find most appropriate.

@openjdk
Copy link

openjdk bot commented Nov 11, 2022

@rwestrel This change now passes all automated pre-integration checks.

ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details.

After integration, the commit message for the final commit will be:

6312651: Compiler should only use verified interface types for optimization

Reviewed-by: vlivanov, kvn

You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed.

At the time when this comment was updated there had been 167 new commits pushed to the master branch:

  • 0ec575a: 8297289: problem list runtime/vthread/RedefineClass.java and TestObjectAllocationSampleEvent.java
  • dcb8375: 8245246: Deprecate -profile option in javac
  • 52494df: 8290845: Consider an alternative item separator for multi-item option values
  • c56c69e: 8285604: closed sun/java2d/GdiRendering/ClipShapeRendering.java failed with "Incorrect color ffeeeeee instead of ff0000ff in pixel (100, 100)"
  • 6fd1442: 8296743: Tighten Class.getModifiers spec for array classes
  • 3a15e84: 8297258: Typo in java -help referencing -disable-@files instead of --disable-@files
  • 43ce047: 8178698: javax/sound/midi/Sequencer/MetaCallback.java failed with timeout
  • 035eaee: 8296324: JVMTI GetStackTrace truncates vthread stack trace for agents loaded into running VM
  • 59a308b: 8296632: Write a test to verify the content change of TextArea sends TextEvent
  • 11fc65f: 8023562: [TEST_BUG] java/awt/Mouse/EnterExitEvents/DragWindowTest.java failed on ubuntu 13 and mac 10.11
  • ... and 157 more: https://git.openjdk.org/jdk/compare/d4376f8b55391485365797d1c4d0dbbc6ed2ad92...master

As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.

➡️ To integrate this PR with the above commit message to the master branch, type /integrate in a new comment.

@openjdk openjdk bot added the ready Pull request is ready to be integrated label Nov 11, 2022
@rwestrel
Copy link
Contributor Author

Great work, Roland! I'm approving the PR. (hs-tier1 - hs-tier2 sanity testing passed with latest version.)

Feel free to handle ciArrayKlass::interfaces() as you find most appropriate.

Thanks for the review (and running tests).
I removed ciArrayKlass::interfaces() in the new commit. Is the resulting code what you suggested?

@iwanowww
Copy link
Contributor

I removed ciArrayKlass::interfaces() in the new commit. Is the resulting code what you suggested?

Yes, it is much clearer now. Thanks.

Copy link
Contributor

@vnkozlov vnkozlov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Thanks!

@rwestrel
Copy link
Contributor Author

@iwanowww @vnkozlov thanks for the reviews.

@rwestrel
Copy link
Contributor Author

/integrate

@openjdk
Copy link

openjdk bot commented Nov 21, 2022

Going to push as commit 45d1807.
Since your change was applied there have been 179 commits pushed to the master branch:

  • bcc6b12: 8296945: PublicMethodsTest is slow due to dependency verification with debug builds
  • fc61658: 8294591: Fix cast-function-type warning in TemplateTable
  • 544e317: 8059632: Method reference compilation uses incorrect qualifying type
  • 651e547: 8297217: Incorrect generation name in the heap verification log message with Serial GC
  • dd55310: 8297303: ProblemList java/awt/Mouse/EnterExitEvents/DragWindowTest.java on macosx-all
  • 3ea8971: 8269817: serviceability/jvmti/DynamicCodeGenerated/DynamicCodeGeneratedTest.java timed out with -Xcomp
  • 0a3b0fc: 8296784: Provide clean mallinfo/mallinfo2 wrapper for Linux glibc platforms
  • 7b3d581: 8297293: Add java/nio/channels/FileChannel/FileExtensionAndMap.java to ProblemList
  • 251e065: 8296764: NMT: reduce loads in os::malloc
  • 0845b39: 8296796: Provide clean, platform-agnostic interface to C-heap trimming
  • ... and 169 more: https://git.openjdk.org/jdk/compare/d4376f8b55391485365797d1c4d0dbbc6ed2ad92...master

Your commit was automatically rebased without conflicts.

@openjdk openjdk bot added the integrated Pull request has been integrated label Nov 21, 2022
@openjdk openjdk bot closed this Nov 21, 2022
@openjdk openjdk bot removed ready Pull request is ready to be integrated rfr Pull request is ready for review labels Nov 21, 2022
@openjdk
Copy link

openjdk bot commented Nov 21, 2022

@rwestrel Pushed as commit 45d1807.

💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

hotspot-compiler hotspot-compiler-dev@openjdk.org integrated Pull request has been integrated

Development

Successfully merging this pull request may close these issues.

3 participants