-
Notifications
You must be signed in to change notification settings - Fork 785
Fold MethodHandle.asType in Lambdaform-generated methods #23481
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: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -178,8 +178,9 @@ const char *messageNames[] = { | |
| "VM_targetMethodFromInvokeCacheArrayMemberNameObj", | ||
| "VM_isLambdaFormGeneratedMethod", | ||
| "VM_getMemberNameMethodInfo", | ||
| "VM_isMethodHandleExpectedType", | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! |
||
| "VM_getMemberNameFieldKnotIndexFromMethodHandleKnotIndex", | ||
| "VM_isMethodHandleExpectedType", | ||
| "VM_getConvertedMethodHandle", | ||
| "VM_isStable", | ||
| "VM_delegatingMethodHandleTarget", | ||
| "VM_getVMTargetOffset", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1097,6 +1097,36 @@ Operand *InterpreterEmulator::getReturnValue(TR_ResolvedMethod *callee) | |
| } | ||
| break; | ||
| } | ||
| case TR::java_lang_invoke_Invokers_checkGenericType: { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should check for and abort early if const refs are disabled. |
||
| if (!comp()->useConstRefs()) | ||
| break; | ||
|
|
||
| Operand *receiverMHOperand = topn(1); | ||
| Operand *desiredMTOperand = topn(0); | ||
| TR::KnownObjectTable::Index mhIndex = receiverMHOperand->getKnownObjectIndex(); | ||
| TR::KnownObjectTable::Index mtIndex = desiredMTOperand->getKnownObjectIndex(); | ||
| debugTrace(tracer(), "Known MethodHandle koi %d\n", mhIndex); | ||
| debugTrace(tracer(), "Known MethodType koi %d\n", mtIndex); | ||
| TR::KnownObjectTable *knot = comp()->getKnownObjectTable(); | ||
| if (knot && mhIndex != TR::KnownObjectTable::UNKNOWN && mtIndex != TR::KnownObjectTable::UNKNOWN | ||
| && !knot->isNull(mhIndex) && !knot->isNull(mtIndex)) { | ||
| if (comp()->fej9()->isMethodHandleExpectedType(comp(), mhIndex, mtIndex)) { | ||
| result = new (trStackMemory()) KnownObjOperand(mhIndex); | ||
| debugTrace(tracer(), "MH.asType: exact match\n"); | ||
| break; | ||
| } | ||
|
|
||
| TR::KnownObjectTable::Index convertedMHIndex | ||
| = comp()->fej9()->getConvertedMethodHandle(comp(), mhIndex, mtIndex); | ||
| if (TR::KnownObjectTable::UNKNOWN != convertedMHIndex) { | ||
| J9::ConstProvenanceGraph *cpg = comp()->constProvenanceGraph(); | ||
| cpg->addEdge(cpg->knownObject(mhIndex), cpg->knownObject(convertedMHIndex)); | ||
| result = new (trStackMemory()) KnownObjOperand(convertedMHIndex); | ||
| debugTrace(tracer(), "MH.asType: subtype match\n"); | ||
| } | ||
| } | ||
| break; | ||
| } | ||
| case TR::jdk_internal_foreign_layout_ValueLayouts_AbstractValueLayout_accessHandle: { | ||
| Operand *layoutOperand = top(); | ||
| TR::KnownObjectTable::Index layoutIndex = layoutOperand->getKnownObjectIndex(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,7 @@ | |
| #include "env/CompilerEnv.hpp" | ||
| #include "env/IO.hpp" | ||
| #include "env/VMJ9.h" | ||
| #include "env/J9ConstProvenanceGraph.hpp" | ||
| #include "env/j9method.h" | ||
| #include "il/ILOpCodes.hpp" | ||
| #include "il/ILOps.hpp" | ||
|
|
@@ -556,7 +557,9 @@ void TR_MethodHandleTransformer::visitCall(TR::TreeTop *tt, TR::Node *node) | |
| case TR::java_lang_invoke_Invokers_checkVarHandleGenericType: | ||
| process_java_lang_invoke_Invokers_checkVarHandleGenericType(tt, node); | ||
| break; | ||
|
|
||
| case TR::java_lang_invoke_Invokers_checkGenericType: | ||
| process_java_lang_invoke_Invokers_checkGenericType(tt, node); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
|
|
@@ -949,3 +952,42 @@ void TR_MethodHandleTransformer::process_java_lang_invoke_Invokers_checkVarHandl | |
| } | ||
| #endif // TR_ALLOW_NON_CONST_KNOWN_OBJECTS | ||
| } | ||
|
|
||
| void TR_MethodHandleTransformer::process_java_lang_invoke_Invokers_checkGenericType(TR::TreeTop *tt, TR::Node *node) | ||
| { | ||
| if (!comp()->useConstRefs()) | ||
| return; | ||
|
|
||
| auto mhNode = node->getArgument(0); | ||
| auto desiredMTNode = node->getArgument(1); | ||
| TR::KnownObjectTable::Index mhIndex = getObjectInfoOfNode(mhNode); | ||
| TR::KnownObjectTable::Index desiredMTIndex = getObjectInfoOfNode(desiredMTNode); | ||
| logprintf(trace(), comp()->log(), "MethodHandle is obj%d\n", mhIndex); | ||
| logprintf(trace(), comp()->log(), "MethodType is obj%d\n", desiredMTIndex); | ||
| auto knot = comp()->getKnownObjectTable(); | ||
| TR_J9VMBase *fej9 = static_cast<TR_J9VMBase *>(comp()->fe()); | ||
| if (knot && isKnownObject(mhIndex) && !knot->isNull(mhIndex) && isKnownObject(desiredMTIndex) | ||
| && !knot->isNull(desiredMTIndex)) { | ||
| logprintf(trace(), comp()->log(), "Checking exact compatibility\n"); | ||
| if (fej9->isMethodHandleExpectedType(comp(), mhIndex, desiredMTIndex)) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| logprintf(trace(), comp()->log(), "checkGenericType: exact match\n"); | ||
| anchorAllChildren(node, tt); | ||
| node->removeAllChildren(); | ||
| TR::Node::recreateWithSymRef(node, TR::aload, knot->constSymRef(mhIndex)); | ||
| return; | ||
| } | ||
|
|
||
| logprintf(trace(), comp()->log(), "Exact compatibility check failed - checking subtype compatibility\n"); | ||
| TR::KnownObjectTable::Index convertedMHIndex = fej9->getConvertedMethodHandle(comp(), mhIndex, desiredMTIndex); | ||
| if (TR::KnownObjectTable::UNKNOWN != convertedMHIndex) { | ||
| logprintf(trace(), comp()->log(), "checkGenericType: subtype match\n"); | ||
| J9::ConstProvenanceGraph *cpg = comp()->constProvenanceGraph(); | ||
| cpg->addEdge(cpg->knownObject(mhIndex), cpg->knownObject(convertedMHIndex)); | ||
| anchorAllChildren(node, tt); | ||
| node->removeAllChildren(); | ||
| TR::Node::recreateWithSymRef(node, TR::aload, knot->constSymRef(convertedMHIndex)); | ||
| return; | ||
| } | ||
| logprintf(trace(), comp()->log(), "MethodTypes are not compatible\n"); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -168,6 +168,24 @@ class TR_MethodHandleTransformer : public TR::Optimization { | |
| */ | ||
| void process_java_lang_invoke_Invokers_checkVarHandleGenericType(TR::TreeTop *tt, TR::Node *node); | ||
|
|
||
| /** | ||
| * \brief | ||
| * Eliminates calls to Invokers.checkGenericType when both the MethodHandle and the | ||
| * MethodType are known objects and either of the following is true: | ||
| * | ||
| * a) The given MethodType is the exact same object as the MethodType of the asTypeCache | ||
| * of the receiver MethodHandle. | ||
| * b) The given MethodType is the exact same object as the receiver MethodHandle's MethodType. | ||
| * | ||
| * Otherwise, the transformation is aborted. | ||
| * | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should also document the case where this is true: |
||
| * \param tt | ||
| * The treetop of the call node | ||
| * \param node | ||
| * The call node representing the call to java/lang/invoke/Invokers.checkGenericType | ||
| */ | ||
| void process_java_lang_invoke_Invokers_checkGenericType(TR::TreeTop *tt, TR::Node *node); | ||
|
|
||
| private: | ||
| int32_t _numLocals; // Number of parms, autos and temps | ||
| ObjectInfo *_currentObjectInfo; // Object info for current block being processed | ||
|
|
||
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.
VMAccess ends here, with the function returning a raw pointer (if successful). The callers of this function then takes the resulting raw pointer, and then calls
knot->getOrCreateIndex(result of this function), which is not GC safe. The VM access should be held all the way till the knot index is obtained, and the easiest way to do that would be to modify this function to return the knot index instead of the raw pointer, so that VM access is held throughout.