-
Notifications
You must be signed in to change notification settings - Fork 143
8373202: [lworld] ObjectReference.equals should follow == semantics for value objects #1834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: lworld
Are you sure you want to change the base?
Conversation
|
👋 Welcome back amenkov! A progress list of the required criteria for merging this PR into |
|
❗ This change is not yet ready to be integrated. |
src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
Outdated
Show resolved
Hide resolved
src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
Outdated
Show resolved
Hide resolved
|
|
Webrevs
|
| (Error VM_DEAD) | ||
| ) | ||
| ) | ||
| (Command IsSameObject=11 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you going to add "preview API" warnings to these two APIs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure it makes much sense.
They are quite generic, I think about adding them to mainline in jdk 27 (but don't use by ObjectReferenceImpl.equals/hashCode)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They might be generic, but they serve no useful purpose outside of valhalla support.
src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
Outdated
Show resolved
Hide resolved
src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| // Inline type is a concrete value class. | ||
| boolean isInlined() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this called isInlined()? Shouldn't it be isValueClass()? Do we want to expose it to users through ReferenceType? Should we also consider exposing a new isIdentity() API?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this called isInlined()? Shouldn't it be isValueClass()?
I had the same question. The isInlined() matches the obsolete approach. The isValueClass() looks better.
Do we want to expose it to users through ReferenceType?
If the JDI implementation needed it then there are some chances debuggers may need it as well. We have some time to decide. Preview allows to change the API specs in the future. I have a minor preference to expose it now. It is pretty simple and clear.
Should we also consider exposing a new isIdentity() API?
It would be consistent with other modifier bits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInlined name (and its implementation) is consistent with hotspot code.
This API if required by ObjectReferenceImpl to determine if the reference is a value object (so the class cannot be abstract or interface).
To me IsIdentity (I think isValue is better) should be in ClassType, I'm updating ClassTypeImpl, it can be added to ClassType interface later if debuggers really need it).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInlined name (and its implementation) is consistent with hotspot code.
But in the case of JDI we are talking about a potentially external API.
To me IsIdentity (I think isValue is better) should be in ClassType
We need to be careful of the use of "value" in JDI since we already have com.sun.jdi.Value, which peculates into all sorts of APIs like ObjectReference.getValue(Field) and BooleanValue. It doesn't help any that we also have Value.type().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ClassType laready has isEnum(), so isValue looks more consistent.
Maybe isValueClass? Anyway it's not too important now (while it's internal API)
| return JDWP.ObjectReference.ObjectHashCode.process(vm, this).hashCode; | ||
| } catch (JDWPException exc) { | ||
| throw exc.toJDIException(); | ||
| if (isValueObject() && vm.canUseIsSameObject()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see how this logic can be correct for value objects if vm.canUseIsSameObject() returns false. We still have a value object in that case. Is using Long.hashCode(ref()) the right thing to do? Same thing applies to equals() above. I think if a JVM supports value objects then the debug agent has to support IsSameObject and HashCode. The version check should really only be in regard to whether or not value objects are supported in general by the JVM, because if they are they have to be supported by the debug agent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should execute jdwp command only when it's available (vm.canUseIsSameObject returns true) and the object is value object.
Note that isValueObject() may not work for old releases, so we need to check both conditions here or move version check to ClassTypeImpl.isValueClass
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the JVM supports value objects, the debug agent has to support IsSameObject and ObjectHashCode. I don't see how we can have a functional JDWP and JDI otherwise. The logic above is proving that. It allows for the impossible to support situation where isValueObject() can return true, yet IsSameObject is not supported, meaning we can't properly compute the hash code.
If IsValueObject returns true, the invariant should be that IsSameObject is supported.
src/jdk.jdi/share/classes/com/sun/tools/jdi/VirtualMachineImpl.java
Outdated
Show resolved
Hide resolved
| (Error VM_DEAD) | ||
| ) | ||
| ) | ||
| (Command IsSameObject=11 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They might be generic, but they serve no useful purpose outside of valhalla support.
| return JDWP.ObjectReference.ObjectHashCode.process(vm, this).hashCode; | ||
| } catch (JDWPException exc) { | ||
| throw exc.toJDIException(); | ||
| if (isValueObject() && vm.canUseIsSameObject()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the JVM supports value objects, the debug agent has to support IsSameObject and ObjectHashCode. I don't see how we can have a functional JDWP and JDI otherwise. The logic above is proving that. It allows for the impossible to support situation where isValueObject() can return true, yet IsSameObject is not supported, meaning we can't properly compute the hash code.
If IsValueObject returns true, the invariant should be that IsSameObject is supported.
| The test reproduces scenarios when ObjectReference for value object is fetched during the object construction | ||
| and the object content is changed later. When "this" ObjectReference for value object is requested, | ||
| JDI returns existing reference if there are other references to the equal value object or create a new one otherwise. | ||
| The test debugs "new Value(3,6)" statement by setting breakpoints in Value class constructor at locations | ||
| when the object being constructed is (0,0), (3,0) and (3,6). | ||
| Test scenarios are defined by test arguments; TestScaffold passes them creating debuggee process (TargetApp class). | ||
| Debugsee initializes static fields with value objects (0,0), (3,0), (3,6) depending on the passed arguments. | ||
| Debugger gets ObjectReferences for the fields before testing. | ||
| Tested scenarios: | ||
| - no existing references; | ||
| - all 3 references exists; | ||
| - there are references for 1 and 3 breakpoints. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comment lines should all start with a "*".
| (Error INVALID_OBJECT) | ||
| (Error VM_DEAD) | ||
| ) | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed, "since" is needed and with possible preview comment (check what we had for Loom preview).
| public boolean canUseIsSameObject() { | ||
| return versionInfo().jdwpMajor >= 27; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We may want to generalize this with something like 'maySupportValueClasses()'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not so sure this API is really even needed. I don't believe the current calls to it are valid.
| } catch (JDWPException exc) { | ||
| throw exc.toJDIException(); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: The lines 164, 177 can be simplified a little bit with move of the renamed vm.canUseIsSameObject() check equivalent to the isValueClass().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Valhalla is not supported on the target VM, there is no way for isValueClass() or isValueObject() to ever return true. If Valhalla is supported, they can return true, and we have to assume that JDWP and the debug agent support Valhalla also. We can't have Valhalla support in the JVM and not also have it in JDWP and the debug agent. The debugger/JDI will break if isValueObject() returns false for a value object.
Updated implementation of ObjectReference.equals and ObjectReference.hashCode to comply the spec for value objects.
Added the test for value object ctor debugging, the test verifies the behaviour is expected.
There is an issue with instance filter, it till be fixed separately (it's not yet clear how it would be better to fix it)
testing: tier1..4, hs-tier5-svc
Progress
Issue
Reviewing
Using
gitCheckout this PR locally:
$ git fetch https://git.openjdk.org/valhalla.git pull/1834/head:pull/1834$ git checkout pull/1834Update a local copy of the PR:
$ git checkout pull/1834$ git pull https://git.openjdk.org/valhalla.git pull/1834/headUsing Skara CLI tools
Checkout this PR locally:
$ git pr checkout 1834View PR using the GUI difftool:
$ git pr show -t 1834Using diff file
Download this PR as a diff file:
https://git.openjdk.org/valhalla/pull/1834.diff
Using Webrev
Link to Webrev Comment