-
Notifications
You must be signed in to change notification settings - Fork 722
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
Update linkToInterface for OpenJDK MethodHandles #11367
Conversation
fyi @DanHeidinga |
runtime/vm/BytecodeInterpreter.hpp
Outdated
@@ -8396,7 +8396,15 @@ class INTERPRETER_CLASS | |||
if (interfaceClass == iTable->interfaceClass) { | |||
receiverClass->lastITable = iTable; | |||
foundITable: | |||
vTableOffset = ((UDATA*)(iTable + 1))[iTableIndex]; | |||
if (J9_UNEXPECTED(J9_ARE_ANY_BITS_SET(iTableIndex, J9_ITABLE_OFFSET_TAG_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.
This fetches J9JNIMethodID* from vmindexOffset
and then tries to decode it for an interface. Looking at the code that initializes the J9JNIMethodID:
https://github.com/eclipse/openj9/blob/a7b7dbe51e2c8801b4f0a22bb98322d7dda76692/runtime/vm/jnicsup.cpp#L2097-L2122
it explicitly states that it doesn't tag the vTableIndex for static interface methods or methods from Object as J9_JNI_MID_INTERFACE
.
If it's one of those cases, the code below that looks up the method will be wrong:
_sendMethod = *(J9Method **)(((UDATA)receiverClass) + vTableOffset);
Can you point me at the code that ensures we won't try to run linkToInterface
for private interface methods or for Object methods looked up on the interface?
With the OpenJ9 implementation, we handled these cases in the Java code that created the MH by returning DirectHandles or VirtualHandles wrapped with appropriate asTypes to ensure we couldn't hit them in the native code.
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.
[1] DirectMethodHandle
that handles invokeinterface
: has viewAsType
; has checkReceiver
, which gets called before linkToInterface
.
[2] DirectMethodHandle
check for invokeinterface
of Object methods.
[3] In [2], MethodHandleNatives.resolve
(native code) is used to generate MemberName
.
Unsure if I have identified the correct code. +@fengxue-IS for assist.
@DanHeidinga can you please provide a link to the corresponding J9 code?
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.
[2] looks like it covers the method from object case. Writing a test - or finding an existing one - would be a good way to validate the various cases here |
I ran tests, which are attached here: Test.java. They ...
The above tests pass. W.r.t. the OJDK code: The code mentioned in #11371 (comment) is also used in the above tests for generating exceptions.
|
Thanks for putting those tests together. The case I was thinking of was a private method on the interface being invoked directly:
This should map to the equivalent of an |
The above example fails.
@DanHeidinga Can you confirm if the below example is correct for
|
No, it's not. The case is for
The interface extends from Object and so can call Object's methods even though the interface doesn't declare them and there's no ITable for them. Another good example would be
|
Confirming that |
55555cb
to
ab0961e
Compare
@DanHeidinga The PR has been updated to correctly handle private interface methods, j.l.Object methods, vTable offset for the method and iTable index for the method. I don't think jnicsup.cpp::initializeMethodID will return a vTable offset with I reran the tests, Test.java. OpenJ9 with OpenJDK MHs enabled behaves identically to RI. |
if (J9_ARE_ANY_BITS_SET(vTableOffset, J9_JNI_MID_INTERFACE)) { | ||
/* Treat as iTable index for the method if J9_JNI_MID_INTERFACE is set. */ | ||
UDATA iTableIndex = vTableOffset & ~(UDATA)J9_JNI_MID_INTERFACE; | ||
J9Class *interfaceClass = J9_CLASS_FROM_METHOD(method); |
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.
The MemberName->vmtargetOffset
is directly holding onto a J9Method*
. How is that pointer updated during HCR? I'm concerned that the loop through the iTable
may fail to match the interfaceClass
if HCR has replaced the class with a newer version. (ie: The cached J9Method * may hold onto an obsolete class pointer)
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.
Should VM_VMHelpers::currentClass
get the most current version of class after HCR?
J9Class *interfaceClass = J9_CLASS_FROM_METHOD(method); | |
J9Class *interfaceClass = VM_VMHelpers::currentClass(J9_CLASS_FROM_METHOD(method)); |
Do we also need to update the J9Method
ref stored in MemberName
for HCR? Related code:
- hshelp.c::fixDirectHandles: Here
J9Methods
stored in OpenJ9 MHs are updated. We probably need to do the same forMemberNames->vmtarget
(J9Method
). - hshelp.c::fixJNIRefs will need to be invoked before fixing
MemberNames->vmindex
(J9JNIMethodID
). - jvmtiClass.c::redefineClassesCommon: invokes
hshelp.c::fixJNIRefs
andhshelp.c::fixDirectHandles
. - Related question: Implement MethodHandleNatives native code #10690 (comment)
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.
Should
VM_VMHelpers::currentClass
get the most current version of class after HCR?
This solves half the problem in that it ensures the most up-to-date version of the class is used in the itable search. Unfortunately, the itableIndex may not point to the same method in the new version of the class if the methods have been reordered.
It's really two pieces of data - class version & itable index - and both need to kept consistent and up to date.
- hshelp.c::fixDirectHandles: Here
J9Methods
stored in OpenJ9 MHs are updated. We probably need to do the same forMemberNames->vmtarget
(J9Method
).
This is carefully set up thru cooperation between the MH creation java code & the redef code to avoid a full heap walk to find the DirectHandles. We may be able to make the same invariants hold for MemberName but I'm less clear on how to do that without patching the OJDK java code.
Couple of options here:
-
Do a full heap walk on redefinition to fix the
vmtarget
&vmindex
fields of the MemberName. This will regress the use cases we fixed by adding the DirectHandle cache but it will be correct. -
Change
vmindex
to be an index into class->jniIDs table. This should let the existing mechanisms fix the JNIID when the class is redefined but will require changes to the way invocation occurs. We'll also need to figure out how to updatevmtarget
as well. -
Something else?
I'd suggest starting with option 1 as it's the easiest to get right and we can figure out how to optimize it later.
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 have updated this PR to handle the VM_VMHelpers::currentClass
change. For the bigger part, I have opened the following issue: #11528. This PR is ready to be reviewed and merged. The bigger part will be handled in a separate PR.
I'm not going to run a build on this given the travis build has passed and the code is all under ifdef anyway |
Now, it properly handles: - Private interface methods - j.l.Object methods - vTable offset for the method - iTable index for the method Also, the latest version of the class is retrieved for the iTable search. Co-authored-by: Jack Lu <Jack.S.Lu@ibm.com> Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
ab0961e
to
41fdedd
Compare
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.
This is a step in the right direction and with the opening of #11528 to track the HCR-related issues, I'm OK with merging this.
linkToVirtual behaviour is corrected for cases where J9JNIMethodID->vTableIndex is 0. Related: eclipse-openj9#11367 Signed-off-by: Babneet Singh <sbabneet@ca.ibm.com>
Now, it properly handles:
Also, the latest version of the class is retrieved for the
iTable
search.Co-authored-by: Jack Lu Jack.S.Lu@ibm.com
Signed-off-by: Babneet Singh sbabneet@ca.ibm.com