Search in sources :

Example 26 with FixedGuardNode

use of org.graalvm.compiler.nodes.FixedGuardNode in project graal by oracle.

the class GraphBuilderContext method addNonNullCast.

default ValueNode addNonNullCast(ValueNode value) {
    AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp(NodeView.DEFAULT);
    if (valueStamp.nonNull()) {
        return value;
    } else {
        LogicNode isNull = add(IsNullNode.create(value));
        FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true));
        Stamp newStamp = valueStamp.improveWith(StampFactory.objectNonNull());
        return add(PiNode.create(value, newStamp, fixedGuard));
    }
}
Also used : FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) ObjectStamp(org.graalvm.compiler.core.common.type.ObjectStamp) AbstractPointerStamp(org.graalvm.compiler.core.common.type.AbstractPointerStamp) Stamp(org.graalvm.compiler.core.common.type.Stamp) AbstractPointerStamp(org.graalvm.compiler.core.common.type.AbstractPointerStamp) LogicNode(org.graalvm.compiler.nodes.LogicNode)

Example 27 with FixedGuardNode

use of org.graalvm.compiler.nodes.FixedGuardNode in project graal by oracle.

the class IntegerSwitchNode method tryOptimizeEnumSwitch.

/**
 * For switch statements on enum values, the Java compiler has to generate complicated code:
 * because {@link Enum#ordinal()} can change when recompiling an enum, it cannot be used
 * directly as the value that is switched on. An intermediate int[] array, which is initialized
 * once at run time based on the actual {@link Enum#ordinal()} values, is used.
 *
 * The {@link ConstantFieldProvider} of Graal already detects the int[] arrays and marks them as
 * {@link ConstantNode#isDefaultStable() stable}, i.e., the array elements are constant. The
 * code in this method detects array loads from such a stable array and re-wires the switch to
 * use the keys from the array elements, so that the array load is unnecessary.
 */
private boolean tryOptimizeEnumSwitch(SimplifierTool tool) {
    if (!(value() instanceof LoadIndexedNode)) {
        /* Not the switch pattern we are looking for. */
        return false;
    }
    LoadIndexedNode loadIndexed = (LoadIndexedNode) value();
    if (loadIndexed.usages().count() > 1) {
        /*
             * The array load is necessary for other reasons too, so there is no benefit optimizing
             * the switch.
             */
        return false;
    }
    assert loadIndexed.usages().first() == this;
    ValueNode newValue = loadIndexed.index();
    JavaConstant arrayConstant = loadIndexed.array().asJavaConstant();
    if (arrayConstant == null || ((ConstantNode) loadIndexed.array()).getStableDimension() != 1 || !((ConstantNode) loadIndexed.array()).isDefaultStable()) {
        /*
             * The array is a constant that we can optimize. We require the array elements to be
             * constant too, since we put them as literal constants into the switch keys.
             */
        return false;
    }
    Integer optionalArrayLength = tool.getConstantReflection().readArrayLength(arrayConstant);
    if (optionalArrayLength == null) {
        /* Loading a constant value can be denied by the VM. */
        return false;
    }
    int arrayLength = optionalArrayLength;
    Map<Integer, List<Integer>> reverseArrayMapping = new HashMap<>();
    for (int i = 0; i < arrayLength; i++) {
        JavaConstant elementConstant = tool.getConstantReflection().readArrayElement(arrayConstant, i);
        if (elementConstant == null || elementConstant.getJavaKind() != JavaKind.Int) {
            /* Loading a constant value can be denied by the VM. */
            return false;
        }
        int element = elementConstant.asInt();
        /*
             * The value loaded from the array is the old switch key, the index into the array is
             * the new switch key. We build a mapping from the old switch key to new keys.
             */
        reverseArrayMapping.computeIfAbsent(element, e -> new ArrayList<>()).add(i);
    }
    /* Build high-level representation of new switch keys. */
    List<KeyData> newKeyDatas = new ArrayList<>(arrayLength);
    ArrayList<AbstractBeginNode> newSuccessors = new ArrayList<>(blockSuccessorCount());
    for (int i = 0; i < keys.length; i++) {
        List<Integer> newKeys = reverseArrayMapping.get(keys[i]);
        if (newKeys == null || newKeys.size() == 0) {
            /* The switch case is unreachable, we can ignore it. */
            continue;
        }
        /*
             * We do not have detailed profiling information about the individual new keys, so we
             * have to assume they split the probability of the old key.
             */
        double newKeyProbability = keyProbabilities[i] / newKeys.size();
        int newKeySuccessor = addNewSuccessor(keySuccessor(i), newSuccessors);
        for (int newKey : newKeys) {
            newKeyDatas.add(new KeyData(newKey, newKeyProbability, newKeySuccessor));
        }
    }
    int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors);
    double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1];
    /*
         * We remove the array load, but we still need to preserve exception semantics by keeping
         * the bounds check. Fortunately the array length is a constant.
         */
    LogicNode boundsCheck = graph().unique(new IntegerBelowNode(newValue, ConstantNode.forInt(arrayLength, graph())));
    graph().addBeforeFixed(this, graph().add(new FixedGuardNode(boundsCheck, DeoptimizationReason.BoundsCheckException, DeoptimizationAction.InvalidateReprofile)));
    /*
         * Build the low-level representation of the new switch keys and replace ourself with a new
         * node.
         */
    doReplace(newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability);
    /* The array load is now unnecessary. */
    assert loadIndexed.hasNoUsages();
    GraphUtil.removeFixedWithUnusedInputs(loadIndexed);
    return true;
}
Also used : DeoptimizationReason(jdk.vm.ci.meta.DeoptimizationReason) Arrays(java.util.Arrays) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) DeoptimizationAction(jdk.vm.ci.meta.DeoptimizationAction) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) NodeLIRBuilderTool(org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool) SimplifierTool(org.graalvm.compiler.graph.spi.SimplifierTool) IntegerStamp(org.graalvm.compiler.core.common.type.IntegerStamp) StampFactory(org.graalvm.compiler.core.common.type.StampFactory) JavaKind(jdk.vm.ci.meta.JavaKind) NodeClass(org.graalvm.compiler.graph.NodeClass) Map(java.util.Map) LoadIndexedNode(org.graalvm.compiler.nodes.java.LoadIndexedNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) NodeInfo(org.graalvm.compiler.nodeinfo.NodeInfo) GraphUtil(org.graalvm.compiler.nodes.util.GraphUtil) NodeView(org.graalvm.compiler.nodes.NodeView) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) PrimitiveStamp(org.graalvm.compiler.core.common.type.PrimitiveStamp) Stamp(org.graalvm.compiler.core.common.type.Stamp) LIRLowerable(org.graalvm.compiler.nodes.spi.LIRLowerable) JavaConstant(jdk.vm.ci.meta.JavaConstant) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) List(java.util.List) ConstantFieldProvider(org.graalvm.compiler.core.common.spi.ConstantFieldProvider) Simplifiable(org.graalvm.compiler.graph.spi.Simplifiable) Comparator(java.util.Comparator) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) IntegerBelowNode(org.graalvm.compiler.nodes.calc.IntegerBelowNode) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) JavaConstant(jdk.vm.ci.meta.JavaConstant) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) LoadIndexedNode(org.graalvm.compiler.nodes.java.LoadIndexedNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) ArrayList(java.util.ArrayList) List(java.util.List) LogicNode(org.graalvm.compiler.nodes.LogicNode)

Example 28 with FixedGuardNode

use of org.graalvm.compiler.nodes.FixedGuardNode in project graal by oracle.

the class RuntimeStrengthenStampsPhase method removeUnreachableInvokes.

private static void removeUnreachableInvokes(CallTreeNode node) {
    for (Invoke invoke : node.unreachableInvokes) {
        if (!invoke.asNode().isAlive()) {
            continue;
        }
        if (invoke.callTarget().invokeKind().hasReceiver()) {
            InliningUtil.nonNullReceiver(invoke);
        }
        FixedGuardNode guard = new FixedGuardNode(LogicConstantNode.forBoolean(true, node.graph), DeoptimizationReason.UnreachedCode, DeoptimizationAction.None, true);
        node.graph.addBeforeFixed(invoke.asNode(), node.graph.add(guard));
    }
}
Also used : FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) Invoke(org.graalvm.compiler.nodes.Invoke)

Example 29 with FixedGuardNode

use of org.graalvm.compiler.nodes.FixedGuardNode in project graal by oracle.

the class MethodCallTargetNode method tryCheckCastSingleImplementor.

private boolean tryCheckCastSingleImplementor(ValueNode receiver, TypeReference speculatedType) {
    ResolvedJavaType singleImplementor = speculatedType.getType();
    if (singleImplementor != null) {
        ResolvedJavaMethod singleImplementorMethod = singleImplementor.resolveConcreteMethod(targetMethod(), invoke().getContextType());
        if (singleImplementorMethod != null) {
            /**
             * We have an invoke on an interface with a single implementor. We can replace this
             * with an invoke virtual.
             *
             * To do so we need to ensure two properties: 1) the receiver must implement the
             * interface (declaredReceiverType). The verifier does not prove this so we need a
             * dynamic check. 2) we need to ensure that there is still only one implementor of
             * this interface, i.e. that we are calling the right method. We could do this with
             * an assumption but as we need an instanceof check anyway we can verify both
             * properties by checking of the receiver is an instance of the single implementor.
             */
            ValueAnchorNode anchor = new ValueAnchorNode(null);
            if (anchor != 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;
        }
    }
    return false;
}
Also used : FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) ValueAnchorNode(org.graalvm.compiler.nodes.extended.ValueAnchorNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) PiNode(org.graalvm.compiler.nodes.PiNode) ResolvedJavaType(jdk.vm.ci.meta.ResolvedJavaType) ResolvedJavaMethod(jdk.vm.ci.meta.ResolvedJavaMethod)

Example 30 with FixedGuardNode

use of org.graalvm.compiler.nodes.FixedGuardNode in project graal by oracle.

the class ConvertDeoptimizeToGuardPhase method propagateFixed.

@SuppressWarnings("try")
private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) {
    Node current = from;
    while (current != null) {
        if (GraalOptions.GuardPriorities.getValue(from.getOptions()) && current instanceof FixedGuardNode) {
            FixedGuardNode otherGuard = (FixedGuardNode) current;
            if (otherGuard.computePriority().isHigherPriorityThan(deopt.computePriority())) {
                moveAsDeoptAfter(otherGuard, deopt);
                return;
            }
        } else if (current instanceof AbstractBeginNode) {
            if (current instanceof AbstractMergeNode) {
                AbstractMergeNode mergeNode = (AbstractMergeNode) current;
                FixedNode next = mergeNode.next();
                while (mergeNode.isAlive()) {
                    AbstractEndNode end = mergeNode.forwardEnds().first();
                    propagateFixed(end, deopt, loweringProvider);
                }
                assert next.isAlive();
                propagateFixed(next, deopt, loweringProvider);
                return;
            } else if (current.predecessor() instanceof IfNode) {
                IfNode ifNode = (IfNode) current.predecessor();
                // Prioritize the source position of the IfNode
                try (DebugCloseable closable = ifNode.withNodeSourcePosition()) {
                    StructuredGraph graph = ifNode.graph();
                    LogicNode conditionNode = ifNode.condition();
                    boolean negateGuardCondition = current == ifNode.trueSuccessor();
                    FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
                    FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
                    AbstractBeginNode survivingSuccessor;
                    if (negateGuardCondition) {
                        survivingSuccessor = ifNode.falseSuccessor();
                    } else {
                        survivingSuccessor = ifNode.trueSuccessor();
                    }
                    graph.removeSplitPropagate(ifNode, survivingSuccessor);
                    Node newGuard = guard;
                    if (survivingSuccessor instanceof LoopExitNode) {
                        newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
                    }
                    survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
                    graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
                    FixedNode next = pred.next();
                    pred.setNext(guard);
                    guard.setNext(next);
                    SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
                    survivingSuccessor.simplify(simplifierTool);
                    return;
                }
            } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) {
                assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start());
                moveAsDeoptAfter((AbstractBeginNode) current, deopt);
                return;
            }
        }
        current = current.predecessor();
    }
}
Also used : FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) StartNode(org.graalvm.compiler.nodes.StartNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) CompareNode(org.graalvm.compiler.nodes.calc.CompareNode) GuardNode(org.graalvm.compiler.nodes.GuardNode) ValuePhiNode(org.graalvm.compiler.nodes.ValuePhiNode) ConstantNode(org.graalvm.compiler.nodes.ConstantNode) StartNode(org.graalvm.compiler.nodes.StartNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) StaticDeoptimizingNode(org.graalvm.compiler.nodes.StaticDeoptimizingNode) DeoptimizeNode(org.graalvm.compiler.nodes.DeoptimizeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) ValueNode(org.graalvm.compiler.nodes.ValueNode) LoopExitNode(org.graalvm.compiler.nodes.LoopExitNode) Node(org.graalvm.compiler.graph.Node) EndNode(org.graalvm.compiler.nodes.EndNode) FixedWithNextNode(org.graalvm.compiler.nodes.FixedWithNextNode) ProxyNode(org.graalvm.compiler.nodes.ProxyNode) AbstractMergeNode(org.graalvm.compiler.nodes.AbstractMergeNode) FixedNode(org.graalvm.compiler.nodes.FixedNode) IfNode(org.graalvm.compiler.nodes.IfNode) SimplifierTool(org.graalvm.compiler.graph.spi.SimplifierTool) AbstractBeginNode(org.graalvm.compiler.nodes.AbstractBeginNode) FixedGuardNode(org.graalvm.compiler.nodes.FixedGuardNode) StructuredGraph(org.graalvm.compiler.nodes.StructuredGraph) AbstractEndNode(org.graalvm.compiler.nodes.AbstractEndNode) LogicNode(org.graalvm.compiler.nodes.LogicNode) ControlSplitNode(org.graalvm.compiler.nodes.ControlSplitNode) DebugCloseable(org.graalvm.compiler.debug.DebugCloseable)

Aggregations

FixedGuardNode (org.graalvm.compiler.nodes.FixedGuardNode)31 LogicNode (org.graalvm.compiler.nodes.LogicNode)25 ValueNode (org.graalvm.compiler.nodes.ValueNode)24 ResolvedJavaType (jdk.vm.ci.meta.ResolvedJavaType)10 ObjectStamp (org.graalvm.compiler.core.common.type.ObjectStamp)8 TypeReference (org.graalvm.compiler.core.common.type.TypeReference)8 ConstantNode (org.graalvm.compiler.nodes.ConstantNode)8 ResolvedJavaMethod (jdk.vm.ci.meta.ResolvedJavaMethod)7 Stamp (org.graalvm.compiler.core.common.type.Stamp)7 JavaConstant (jdk.vm.ci.meta.JavaConstant)6 DebugCloseable (org.graalvm.compiler.debug.DebugCloseable)5 StructuredGraph (org.graalvm.compiler.nodes.StructuredGraph)5 RuntimeConstraint (jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint)4 IntegerStamp (org.graalvm.compiler.core.common.type.IntegerStamp)4 AbstractBeginNode (org.graalvm.compiler.nodes.AbstractBeginNode)4 FixedNode (org.graalvm.compiler.nodes.FixedNode)4 IfNode (org.graalvm.compiler.nodes.IfNode)4 LogicConstantNode (org.graalvm.compiler.nodes.LogicConstantNode)4 PiNode (org.graalvm.compiler.nodes.PiNode)4 InvocationPlugin (org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin)4