/** * For one or more `invoke` arguments, flow-sensitive information may suggest their narrowing or * simplification. In those cases, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode * MethodCallTargetNode} is prepared just for this callsite, consuming reduced arguments. * * <p>Specializing the {@link com.oracle.graal.nodes.java.MethodCallTargetNode * MethodCallTargetNode} as described above may enable two optimizations: * * <ul> * <li>devirtualization of an {@link com.oracle.graal.nodes.CallTargetNode.InvokeKind#Interface} * or {@link com.oracle.graal.nodes.CallTargetNode.InvokeKind#Virtual} callsite * (devirtualization made possible after narrowing the type of the receiver) * <li>(future work) actual-argument-aware inlining, ie, to specialize callees on the types of * arguments other than the receiver (examples: multi-methods, the inlining problem, lambdas * as arguments). * </ul> * * <p>Precondition: inputs haven't been deverbosified yet. */ private void visitInvoke(Invoke invoke) { if (invoke.asNode().stamp() instanceof IllegalStamp) { return; // just to be safe } boolean isMethodCallTarget = invoke.callTarget() instanceof MethodCallTargetNode; if (!isMethodCallTarget) { return; } FlowUtil.replaceInPlace( invoke.asNode(), invoke.callTarget(), deverbosifyInputsCopyOnWrite((MethodCallTargetNode) invoke.callTarget())); MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); if (callTarget.invokeKind() != CallTargetNode.InvokeKind.Interface && callTarget.invokeKind() != CallTargetNode.InvokeKind.Virtual) { return; } ValueNode receiver = callTarget.receiver(); if (receiver == null) { return; } if (!FlowUtil.hasLegalObjectStamp(receiver)) { return; } Witness w = state.typeInfo(receiver); ResolvedJavaType type; ResolvedJavaType stampType = StampTool.typeOrNull(receiver); if (w == null || w.cluelessAboutType()) { // can't improve on stamp but wil try to devirtualize anyway type = stampType; } else { type = FlowUtil.tighten(w.type(), stampType); } if (type == null) { return; } ResolvedJavaMethod method = type.resolveMethod(callTarget.targetMethod(), invoke.getContextType()); if (method == null) { return; } if (method.canBeStaticallyBound() || Modifier.isFinal(type.getModifiers())) { metricMethodResolved.increment(); callTarget.setInvokeKind(CallTargetNode.InvokeKind.Special); callTarget.setTargetMethod(method); } }