private boolean tryCheckCastSingleImplementor(ValueNode receiver, TypeReference speculatedType) { ResolvedJavaType singleImplementor = speculatedType.getType(); if (singleImplementor != null) { ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveConcreteMethod(targetMethod(), invoke().getContextType()); if (singleImplementorMethod != null) { graph().add(anchor); graph().addBeforeFixed(invoke().asNode(), anchor); LogicNode condition = graph().addOrUniqueWithInputs(InstanceOfNode.create(speculatedType, receiver, getProfile(), anchor)); FixedGuardNode guard = graph().add(new FixedGuardNode(condition, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, false)); graph().addBeforeFixed(invoke().asNode(), guard); ValueNode valueNode = graph().addOrUnique(new PiNode(receiver, StampFactory.objectNonNull(speculatedType), guard)); arguments().set(0, valueNode); if (speculatedType.isExact()) { setInvokeKind(InvokeKind.Special); } else { setInvokeKind(InvokeKind.Virtual); setTargetMethod(singleImplementorMethod); return true;
if (invoke().getContextMethod() == null) { assert (invoke().stateAfter() != null && BytecodeFrame.isPlaceholderBci(invoke().stateAfter().bci)) || BytecodeFrame.isPlaceholderBci(invoke().stateDuring().bci); return; ResolvedJavaType contextType = (invoke().stateAfter() == null && invoke().stateDuring() == null) ? null : invoke().getContextType(); ResolvedJavaMethod specialCallTarget = findSpecialCallTarget(invokeKind, receiver(), targetMethod, contextType); if (specialCallTarget != null) { this.setTargetMethod(specialCallTarget); setInvokeKind(InvokeKind.Special); return; Assumptions assumptions = graph().getAssumptions(); if (invokeKind().isIndirect() && invokeKind().isInterface() && assumptions != null) { ValueNode receiver = receiver(); ResolvedJavaType declaredReceiverType = targetMethod().getDeclaringClass(); if (singleImplementor != null && !singleImplementor.equals(declaredReceiverType)) { TypeReference speculatedType = TypeReference.createTrusted(assumptions, singleImplementor); if (tryCheckCastSingleImplementor(receiver, speculatedType)) { return; TypeReference speculatedType = StampTool.typeReferenceOrNull(uncheckedStamp); if (speculatedType != null) { tryCheckCastSingleImplementor(receiver, speculatedType);
@Override protected void run(StructuredGraph graph) { for (NewFrameNode virtualFrame : graph.getNodes(NewFrameNode.TYPE)) { for (MethodCallTargetNode callTarget : virtualFrame.usages().filter(MethodCallTargetNode.class)) { if (callTarget.invoke() != null) { String properties = callTarget.getDebugProperties().toString(); String arguments = callTarget.arguments().toString(); Throwable exception = new VerificationError("Frame escapes at: %s#%s\nproperties:%s\narguments: %s", callTarget, callTarget.targetMethod(), properties, arguments); throw GraphUtil.approxSourceException(callTarget, exception); } } } } }
/** * Gets the instruction that produces the receiver object for this invocation, if any. * * @return the instruction that produces the receiver object for this invocation if any, * {@code null} if this invocation does not take a receiver object */ public ValueNode receiver() { return isStatic() ? null : arguments().get(0); }
@Override public boolean verify() { assert getUsageCount() <= 1 : "call target may only be used by a single invoke"; for (Node n : usages()) { assertTrue(n instanceof Invoke, "call target can only be used from an invoke (%s)", n); } if (invokeKind().isDirect()) { assertTrue(targetMethod().isConcrete(), "special calls or static calls are only allowed for concrete methods (%s)", targetMethod()); } if (invokeKind() == InvokeKind.Static) { assertTrue(targetMethod().isStatic(), "static calls are only allowed for static methods (%s)", targetMethod()); } else { assertFalse(targetMethod().isStatic(), "static calls are only allowed for non-static methods (%s)", targetMethod()); } return super.verify(); }
public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) { MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget(); MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnStamp(), oldCallTarget.getProfile())); invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget); }
private void lowerInvoke(Invoke invoke, LoweringTool tool, StructuredGraph graph) { if (invoke.callTarget() instanceof MethodCallTargetNode) { MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); NodeInputList<ValueNode> parameters = callTarget.arguments(); ValueNode receiver = parameters.size() <= 0 ? null : parameters.get(0); if (!callTarget.isStatic() && receiver.stamp(NodeView.DEFAULT) instanceof ObjectStamp && !StampTool.isPointerNonNull(receiver)) { ValueNode nonNullReceiver = createNullCheckedValue(receiver, invoke.asNode(), tool); parameters.set(0, nonNullReceiver); receiver = nonNullReceiver; JavaType[] signature = callTarget.targetMethod().getSignature().toParameterTypes(callTarget.isStatic() ? null : callTarget.targetMethod().getDeclaringClass()); if (InlineVTableStubs.getValue(options) && callTarget.invokeKind().isIndirect() && (AlwaysInlineVTableStubs.getValue(options) || invoke.isPolymorphic())) { HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) callTarget.targetMethod(); ResolvedJavaType receiverType = invoke.getReceiverType(); if (hsMethod.isInVirtualMethodTable(receiverType)) { ReadNode compiledEntry = graph.add(new ReadNode(address, any(), StampFactory.forKind(wordKind), BarrierType.NONE)); loweredCallTarget = graph.add(new HotSpotIndirectCallTargetNode(metaspaceMethod, compiledEntry, parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(), signature, callTarget.targetMethod(), HotSpotCallingConventionType.JavaCall, callTarget.invokeKind())); loweredCallTarget = graph.add(new HotSpotDirectCallTargetNode(parameters.toArray(new ValueNode[parameters.size()]), callTarget.returnStamp(), signature, callTarget.targetMethod(), HotSpotCallingConventionType.JavaCall, callTarget.invokeKind())); callTarget.replaceAndDelete(loweredCallTarget);
@Override public String targetName() { if (targetMethod() == null) { return "??Invalid!"; } return targetMethod().format("%h.%n"); }
/** * 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) { NodeSourcePosition position = node.getNodeSourcePosition(); if (position != null) { // use GraphBuilderConfiguration and enable trackNodeSourcePosition to get better source // positions. return approxSourceStackTraceElement(position); } 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(); elements.addAll(Arrays.asList(approxSourceStackTraceElement(state))); break; } n = n.predecessor(); } return elements.toArray(new StackTraceElement[elements.size()]); }
protected LoopScope tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { if (!callTarget.invokeKind().isDirect()) { return null; } ResolvedJavaMethod targetMethod = callTarget.targetMethod(); if (targetMethod.hasNeverInlineDirective()) { return null; } ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); for (InlineInvokePlugin plugin : inlineInvokePlugins) { InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments); if (inlineInfo != null) { if (inlineInfo.getMethodToInline() == null) { return null; } else { return doInline(methodScope, loopScope, invokeData, inlineInfo, arguments); } } } return null; }
assert singleReturn.result() == null || singleReturn.result() == singleCallTarget.invoke(); ResolvedJavaMethod resolvedTarget = lookup(singleCallTarget.targetMethod()); maybeEmitClassInitialization(b, singleCallTarget.invokeKind() == InvokeKind.Static, resolvedTarget.getDeclaringClass()); ValueNode[] replacedArguments = new ValueNode[singleCallTarget.arguments().size()]; for (int i = 0; i < replacedArguments.length; i++) { replacedArguments[i] = lookup(b, methodHandleArguments, singleCallTarget.arguments().get(i)); b.handleReplacedInvoke(singleCallTarget.invokeKind(), resolvedTarget, replacedArguments, false);
try (DebugCloseable position = invoke.asNode().withNodeSourcePosition()) { MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget(); assert !callTarget.isStatic() : callTarget.targetMethod(); StructuredGraph graph = callTarget.graph(); ValueNode oldReceiver = callTarget.arguments().get(0); ValueNode newReceiver = oldReceiver; if (newReceiver.getStackKind() == JavaKind.Object) { Stamp stamp = paramStamp.join(StampFactory.object(TypeReference.create(graph.getAssumptions(), callTarget.targetMethod().getDeclaringClass()))); if (!stamp.equals(paramStamp)) { callTarget.replaceFirstInput(oldReceiver, newReceiver);
private ResolvedJavaMethod getSpecialCallTarget(InvokeData invokeData, MethodCallTargetNode callTarget) { if (callTarget.invokeKind().isDirect()) { return null; } // check for trivial cases (e.g. final methods, nonvirtual methods) if (callTarget.targetMethod().canBeStaticallyBound()) { return callTarget.targetMethod(); } SpecialCallTargetCacheKey key = new SpecialCallTargetCacheKey(callTarget.invokeKind(), callTarget.targetMethod(), invokeData.contextType, callTarget.receiver().stamp(NodeView.DEFAULT)); Object specialCallTarget = specialCallTargetCache.get(key); if (specialCallTarget == null) { specialCallTarget = MethodCallTargetNode.devirtualizeCall(key.invokeKind, key.targetMethod, key.contextType, graph.getAssumptions(), key.receiverStamp); if (specialCallTarget == null) { specialCallTarget = CACHED_NULL_VALUE; } specialCallTargetCache.put(key, specialCallTarget); } return specialCallTarget == CACHED_NULL_VALUE ? null : (ResolvedJavaMethod) specialCallTarget; }
AnalysisMethod targetMethod = (AnalysisMethod) target.targetMethod(); bb.isCallAllowed(bb, callerMethod, targetMethod, target.getNodeSourcePosition()); TypeFlowBuilder<?>[] actualParametersBuilders = new TypeFlowBuilder<?>[target.arguments().size()]; for (int i = 0; i < actualParametersBuilders.length; i++) { ValueNode actualParam = target.arguments().get(i); if (actualParam.getStackKind() == JavaKind.Object) { TypeFlowBuilder<?> paramBuilder = state.lookup(actualParam); switch (target.invokeKind()) { case Static: invokeFlow = new StaticInvokeTypeFlow(invoke, target, actualParameters, actualReturn, location); }); if (target.invokeKind() == InvokeKind.Special || target.invokeKind() == InvokeKind.Virtual || target.invokeKind() == InvokeKind.Interface) { invokeBuilder.addObserverDependency(actualParametersBuilders[0]); AnalysisType returnType = (AnalysisType) target.targetMethod().getSignature().getReturnType(null); TypeFlowBuilder<?> actualReturnBuilder = TypeFlowBuilder.create(bb, invoke.asNode(), ActualReturnTypeFlow.class, () -> { ActualReturnTypeFlow actualReturn = new ActualReturnTypeFlow(invoke.asNode(), returnType);
ResolvedJavaMethod targetMethod = callTarget.targetMethod(); if (callTarget.invokeKind() == CallTargetNode.InvokeKind.Special || targetMethod.canBeStaticallyBound()) { return getExactInlineInfo(invoke, targetMethod); assert callTarget.invokeKind().isIndirect(); if (!(callTarget.receiver().stamp(NodeView.DEFAULT) instanceof ObjectStamp)) { return null; ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp(NodeView.DEFAULT); if (receiverStamp.alwaysNull()) { if (leafConcreteSubtype != null) { ResolvedJavaMethod resolvedMethod = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType); if (resolvedMethod != null && leafConcreteSubtype.canRecordTo(callTarget.graph().getAssumptions())) { return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype); if (concrete != null && concrete.canRecordTo(callTarget.graph().getAssumptions())) { return getAssumptionInlineInfo(invoke, concrete.getResult(), concrete);
private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, StampProvider stampProvider, ConstantReflectionProvider constantReflection) { MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget(); if (methodCallTarget.invokeKind() == InvokeKind.Interface) { ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod(); ResolvedJavaType leastCommonType = getLeastCommonType(); ResolvedJavaType contextType = invoke.getContextType(); // check if we have a common base type that implements the interface -> in that case // we have a vtable entry for the interface method and can use a less expensive // virtual call if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) { ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveConcreteMethod(targetMethod, contextType); if (baseClassTargetMethod != null) { devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveConcreteMethod(targetMethod, contextType), stampProvider, constantReflection); } } } }
if (methodCallTargetNode.invoke().useForInlining()) { StructuredGraph inlineGraph = providers.getReplacements().getSubstitution(methodCallTargetNode.targetMethod(), methodCallTargetNode.invoke().bci(), graph.trackNodeSourcePosition(), methodCallTargetNode.asNode().getNodeSourcePosition()); if (inlineGraph != null) { InliningUtil.inline(methodCallTargetNode.invoke(), inlineGraph, true, methodCallTargetNode.targetMethod());
@Override protected LoopScope handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { PEMethodScope methodScope = (PEMethodScope) s; /* * Decode the call target, but do not add it to the graph yet. This avoids adding usages for * all the arguments, which are expensive to remove again when we can inline the method. */ assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); if (callTarget instanceof MethodCallTargetNode) { MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget; if (methodCall.invokeKind().hasReceiver()) { invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant(); NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition(); if (invokeData.constantReceiver != null && invokePosition != null) { // new NodeSourcePosition(invokeData.constantReceiver, // invokePosition.getCaller(), invokePosition.getMethod(), // invokePosition.getBCI()); } } LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget); if (inlineLoopScope != null) { return inlineLoopScope; } } /* We know that we need an invoke, so now we can add the call target to the graph. */ graph.add(callTarget); registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); return super.handleInvoke(methodScope, loopScope, invokeData); }
protected StaticInvokeTypeFlow(Invoke invoke, MethodCallTargetNode target, TypeFlow<?>[] actualParameters, ActualReturnTypeFlow actualReturn, BytecodeLocation location) { super(invoke, target, actualParameters, actualReturn, location); calleeContext = null; assert target.invokeKind() == InvokeKind.Static; }
private static void printPath(Element start, PrintStream out) { Element cur = start; out.print("\tat " + cur.method.asStackTraceElement(0)); while (cur.parent != null) { out.print("\n\tat " + cur.parent.method.asStackTraceElement(cur.invoke.getSource().invoke().bci())); cur = cur.parent; } }