/** * 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); } }
/** * Gets an approximate source code location for a node if possible. * * @return the StackTraceElements if an approximate source location is found, null otherwise */ public static StackTraceElement[] approxSourceStackTraceElement(Node node) { ArrayList<StackTraceElement> elements = new ArrayList<>(); Node n = node; while (n != null) { if (n instanceof MethodCallTargetNode) { elements.add(((MethodCallTargetNode) n).targetMethod().asStackTraceElement(-1)); n = ((MethodCallTargetNode) n).invoke().asNode(); } if (n instanceof StateSplit) { FrameState state = ((StateSplit) n).stateAfter(); while (state != null) { ResolvedJavaMethod method = state.method(); if (method != null) { elements.add(method.asStackTraceElement(state.bci - 1)); } state = state.outerFrameState(); } break; } n = n.predecessor(); } return elements.toArray(new StackTraceElement[elements.size()]); }