@NodeInfo public abstract class EscapeObjectState extends VirtualState implements ValueNumberable { public static final NodeClass<EscapeObjectState> TYPE = NodeClass.create(EscapeObjectState.class); @Input protected VirtualObjectNode object; public VirtualObjectNode object() { return object; } public EscapeObjectState(NodeClass<? extends EscapeObjectState> c, VirtualObjectNode object) { super(c); this.object = object; } @Override public abstract EscapeObjectState duplicateWithVirtualState(); @Override public boolean isPartOfThisState(VirtualState state) { return this == state; } @Override public void applyToVirtual(VirtualClosure closure) { closure.apply(this); } }
@NodeInfo public abstract class AbstractEndNode extends FixedNode implements IterableNodeType, LIRLowerable { public static final NodeClass<AbstractEndNode> TYPE = NodeClass.create(AbstractEndNode.class); protected AbstractEndNode(NodeClass<? extends AbstractEndNode> c) { super(c, StampFactory.forVoid()); } @Override public void generate(NodeLIRBuilderTool gen) { gen.visitEndNode(this); } public AbstractMergeNode merge() { return (AbstractMergeNode) usages().first(); } @Override public boolean verify() { assertTrue(getUsageCount() <= 1, "at most one usage"); return super.verify(); } @Override public Iterable<? extends Node> cfgSuccessors() { return Arrays.asList(merge()); } }
@NodeInfo static final class DummyGuardHandle extends ValueNode implements GuardedNode { public static final NodeClass<DummyGuardHandle> TYPE = NodeClass.create(DummyGuardHandle.class); @Input(InputType.Guard) GuardingNode guard; protected DummyGuardHandle(GuardingNode guard) { super(TYPE, StampFactory.forVoid()); this.guard = guard; } public GuardingNode getGuard() { return guard; } public void setGuard(GuardingNode guard) { updateUsagesInterface(this.guard, guard); this.guard = guard; } @Override public ValueNode asNode() { return this; } }
/** * A node that changes the type of its input, usually narrowing it. For example, a GuardedValueNode * is used to keep the nodes depending on guards inside a loop during speculative guard movement. * * <p>A GuardedValueNode will only go away if its guard is null or {@link StructuredGraph#start()}. */ @NodeInfo public final class GuardedValueNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy { public static final NodeClass<GuardedValueNode> TYPE = NodeClass.create(GuardedValueNode.class); @Input ValueNode object; protected final Stamp piStamp; public GuardedValueNode(ValueNode object, GuardingNode guard, Stamp stamp) { super(TYPE, stamp, guard); this.object = object; this.piStamp = stamp; } public GuardedValueNode(ValueNode object, GuardingNode guard) { this(object, guard, object.stamp()); } public ValueNode object() { return object; } @Override public void generate(NodeLIRBuilderTool generator) { if (object.getStackKind() != JavaKind.Void && object.getStackKind() != JavaKind.Illegal) { generator.setResult(this, generator.operand(object)); } } @Override public boolean inferStamp() { return updateStamp(piStamp.improveWith(object().stamp())); } @Override public void virtualize(VirtualizerTool tool) { ValueNode alias = tool.getAlias(object()); if (alias instanceof VirtualObjectNode) { tool.replaceWithVirtual((VirtualObjectNode) alias); } } @Override public Node canonical(CanonicalizerTool tool) { if (getGuard() == null) { if (stamp().equals(object().stamp())) { return object(); } else { return new PiNode(object(), stamp()); } } return this; } @Override public ValueNode getOriginalNode() { return object; } }
@NodeInfo(allowedUsageTypes = {InputType.Association}) public final class EndNode extends AbstractEndNode { public static final NodeClass<EndNode> TYPE = NodeClass.create(EndNode.class); public EndNode() { super(TYPE); } }
/** The {@code StoreFieldNode} represents a write to a static or instance field. */ @NodeInfo(nameTemplate = "StoreField#{p#field/s}") public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable { public static final NodeClass<StoreFieldNode> TYPE = NodeClass.create(StoreFieldNode.class); @Input ValueNode value; @OptionalInput(InputType.State) FrameState stateAfter; public FrameState stateAfter() { return stateAfter; } public void setStateAfter(FrameState x) { assert x == null || x.isAlive() : "frame state must be in a graph"; updateUsages(stateAfter, x); stateAfter = x; } public boolean hasSideEffect() { return true; } public ValueNode value() { return value; } public StoreFieldNode(ValueNode object, ResolvedJavaField field, ValueNode value) { super(TYPE, StampFactory.forVoid(), object, field); this.value = value; } public StoreFieldNode( ValueNode object, ResolvedJavaField field, ValueNode value, FrameState stateAfter) { super(TYPE, StampFactory.forVoid(), object, field); this.value = value; this.stateAfter = stateAfter; } @Override public void virtualize(VirtualizerTool tool) { ValueNode alias = tool.getAlias(object()); if (alias instanceof VirtualObjectNode) { VirtualInstanceNode virtual = (VirtualInstanceNode) alias; int fieldIndex = virtual.fieldIndex(field()); if (fieldIndex != -1) { tool.setVirtualEntry(virtual, fieldIndex, value(), false); tool.delete(); } } } public FrameState getState() { return stateAfter; } }
@NodeInfo static final class TestNode extends Node { public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class); @Input NodeInputList<ValueNode> itail; @Input ConstantNode i1; @Input FloatingNode i2; protected TestNode() { super(TYPE); } }
@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) static final class TestNode extends Node { public static final NodeClass<TestNode> TYPE = NodeClass.create(TestNode.class); @Input TestNode input; @Successor TestNode successor; protected TestNode(TestNode input, TestNode successor) { super(TYPE); this.input = input; this.successor = successor; } }
/** Start node for a {@link Stub}'s graph. */ @NodeInfo(cycles = CYCLES_0, size = SIZE_0) public final class StubStartNode extends StartNode { public static final NodeClass<StubStartNode> TYPE = NodeClass.create(StubStartNode.class); protected final Stub stub; public StubStartNode(Stub stub) { super(TYPE); this.stub = stub; } public Stub getStub() { return stub; } }
@NodeInfo public abstract class DeoptimizingStubCall extends DeoptimizingFixedWithNextNode { public static final NodeClass<DeoptimizingStubCall> TYPE = NodeClass.create(DeoptimizingStubCall.class); public DeoptimizingStubCall(NodeClass<? extends DeoptimizingStubCall> c, Stamp stamp) { super(c, stamp); } @Override public boolean canDeoptimize() { return true; } }
/** A call to the runtime code {@code Deoptimization::fetch_unroll_info}. */ @NodeInfo(allowedUsageTypes = {InputType.Memory}) public final class DeoptimizationFetchUnrollInfoCallNode extends FixedWithNextNode implements LIRLowerable, MemoryCheckpoint.Single { public static final NodeClass<DeoptimizationFetchUnrollInfoCallNode> TYPE = NodeClass.create(DeoptimizationFetchUnrollInfoCallNode.class); @Input SaveAllRegistersNode registerSaver; @Input ValueNode mode; protected final ForeignCallsProvider foreignCalls; public DeoptimizationFetchUnrollInfoCallNode( @InjectedNodeParameter ForeignCallsProvider foreignCalls, ValueNode registerSaver, ValueNode mode) { super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(FETCH_UNROLL_INFO.getResultType()))); this.registerSaver = (SaveAllRegistersNode) registerSaver; this.mode = mode; this.foreignCalls = foreignCalls; } @Override public LocationIdentity getLocationIdentity() { return LocationIdentity.any(); } public SaveRegistersOp getSaveRegistersOp() { return registerSaver.getSaveRegistersOp(); } /** * Returns the node representing the exec_mode/unpack_kind used during this fetch_unroll_info * call. */ public ValueNode getMode() { return mode; } @Override public void generate(NodeLIRBuilderTool gen) { Value result = ((HotSpotLIRGenerator) gen.getLIRGeneratorTool()) .emitDeoptimizationFetchUnrollInfoCall(gen.operand(getMode()), getSaveRegistersOp()); gen.setResult(this, result); } @NodeIntrinsic public static native Word fetchUnrollInfo(long registerSaver, int mode); }
/** * The {@code Parameter} instruction is a placeholder for an incoming argument to a function call. */ @NodeInfo(nameTemplate = "P({p#index})") public final class ParameterNode extends AbstractLocalNode implements IterableNodeType, UncheckedInterfaceProvider { public static final NodeClass<ParameterNode> TYPE = NodeClass.create(ParameterNode.class); private Stamp uncheckedStamp; public ParameterNode(int index, StampPair stamp) { super(TYPE, index, stamp.getTrustedStamp()); this.uncheckedStamp = stamp.getUncheckedStamp(); } public Stamp uncheckedStamp() { return uncheckedStamp; } }
/** Logic node that negates its argument. */ @NodeInfo public final class LogicNegationNode extends LogicNode implements Canonicalizable.Unary<LogicNode> { public static final NodeClass<LogicNegationNode> TYPE = NodeClass.create(LogicNegationNode.class); @Input(InputType.Condition) LogicNode value; public LogicNegationNode(LogicNode value) { super(TYPE); this.value = value; } public static LogicNode create(LogicNode value) { LogicNode synonym = findSynonym(value); if (synonym != null) { return synonym; } return new LogicNegationNode(value); } private static LogicNode findSynonym(LogicNode value) { if (value instanceof LogicConstantNode) { LogicConstantNode logicConstantNode = (LogicConstantNode) value; return LogicConstantNode.forBoolean(!logicConstantNode.getValue()); } else if (value instanceof LogicNegationNode) { return ((LogicNegationNode) value).getValue(); } return null; } public LogicNode getValue() { return value; } @Override public LogicNode canonical(CanonicalizerTool tool, LogicNode forValue) { LogicNode synonym = findSynonym(forValue); if (synonym != null) { return synonym; } return this; } }
/** * This node represents an unconditional explicit request for immediate deoptimization. * * <p>After this node, execution will continue using a fallback execution engine (such as an * interpreter) at the position described by the {@link #stateBefore() deoptimization state}. */ @NodeInfo public abstract class AbstractDeoptimizeNode extends ControlSinkNode implements IterableNodeType, DeoptimizingNode.DeoptBefore { public static final NodeClass<AbstractDeoptimizeNode> TYPE = NodeClass.create(AbstractDeoptimizeNode.class); @OptionalInput(InputType.State) FrameState stateBefore; protected AbstractDeoptimizeNode( NodeClass<? extends AbstractDeoptimizeNode> c, FrameState stateBefore) { super(c, StampFactory.forVoid()); this.stateBefore = stateBefore; } @Override public boolean canDeoptimize() { return true; } @Override public FrameState stateBefore() { return stateBefore; } @Override public void setStateBefore(FrameState f) { updateUsages(stateBefore, f); stateBefore = f; } public abstract ValueNode getActionAndReason(MetaAccessProvider metaAccess); public abstract ValueNode getSpeculation(MetaAccessProvider metaAccess); }
// @formatter:off @NodeInfo( cycles = CYCLES_UNKNOWN, cyclesRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate", size = SIZE_UNKNOWN, sizeRationale = "If this node is not optimized away it will be lowered to a call, which we cannot estimate") // @formatter:on public abstract class MacroNode extends FixedWithNextNode implements Lowerable { public static final NodeClass<MacroNode> TYPE = NodeClass.create(MacroNode.class); @Input protected NodeInputList<ValueNode> arguments; protected final int bci; protected final ResolvedJavaMethod targetMethod; protected final StampPair returnStamp; protected final InvokeKind invokeKind; protected MacroNode( NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) { super(c, returnStamp.getTrustedStamp()); assert targetMethod.getSignature().getParameterCount(!targetMethod.isStatic()) == arguments.length; this.arguments = new NodeInputList<>(this, arguments); this.bci = bci; this.targetMethod = targetMethod; this.returnStamp = returnStamp; this.invokeKind = invokeKind; assert !isPlaceholderBci(bci); } public int getBci() { return bci; } public ResolvedJavaMethod getTargetMethod() { return targetMethod; } protected FrameState stateAfter() { return null; } /** * Gets a snippet to be used for lowering this macro node. The returned graph (if non-null) must * have been {@linkplain #lowerReplacement(StructuredGraph, LoweringTool) lowered}. */ @SuppressWarnings("unused") protected StructuredGraph getLoweredSnippetGraph(LoweringTool tool) { return null; } /** * Applies {@linkplain LoweringPhase lowering} to a replacement graph. * * @param replacementGraph a replacement (i.e., snippet or method substitution) graph */ @SuppressWarnings("try") protected StructuredGraph lowerReplacement( final StructuredGraph replacementGraph, LoweringTool tool) { final PhaseContext c = new PhaseContext( tool.getMetaAccess(), tool.getConstantReflection(), tool.getConstantFieldProvider(), tool.getLowerer(), tool.getReplacements(), tool.getStampProvider(), tool.getNodeCostProvider()); if (!graph().hasValueProxies()) { new RemoveValueProxyPhase().apply(replacementGraph); } GuardsStage guardsStage = graph().getGuardsStage(); if (!guardsStage.allowsFloatingGuards()) { new GuardLoweringPhase().apply(replacementGraph, null); if (guardsStage.areFrameStatesAtDeopts()) { new FrameStateAssignmentPhase().apply(replacementGraph); } } try (Scope s = Debug.scope("LoweringSnippetTemplate", replacementGraph)) { new LoweringPhase(new CanonicalizerPhase(), tool.getLoweringStage()) .apply(replacementGraph, c); } catch (Throwable e) { throw Debug.handle(e); } return replacementGraph; } @Override public void lower(LoweringTool tool) { StructuredGraph replacementGraph = getLoweredSnippetGraph(tool); InvokeNode invoke = replaceWithInvoke(); assert invoke.verify(); if (replacementGraph != null) { // Pull out the receiver null check so that a replaced // receiver can be lowered if necessary if (!targetMethod.isStatic()) { ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); if (nonNullReceiver instanceof Lowerable) { ((Lowerable) nonNullReceiver).lower(tool); } } InliningUtil.inline(invoke, replacementGraph, false, null); Debug.dump(Debug.INFO_LOG_LEVEL, graph(), "After inlining replacement %s", replacementGraph); } else { if (isPlaceholderBci(invoke.bci())) { throw new GraalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this); } if (invoke.stateAfter() == null) { ResolvedJavaMethod method = graph().method(); if (method.getAnnotation(MethodSubstitution.class) != null || method.getAnnotation(Snippet.class) != null) { // One cause for this is that a MacroNode is created for a method that // no longer needs a MacroNode. For example, Class.getComponentType() // only needs a MacroNode prior to JDK9 as it was given a non-native // implementation in JDK9. throw new GraalError( "%s macro created for call to %s in %s must be lowerable to a snippet or intrinsic graph. " + "Maybe a macro node is not needed for this method in the current JDK?", getClass().getSimpleName(), targetMethod.format("%h.%n(%p)"), graph()); } throw new GraalError("%s: cannot lower to invoke without state: %s", graph(), this); } invoke.lower(tool); } } protected InvokeNode replaceWithInvoke() { InvokeNode invoke = createInvoke(); graph().replaceFixedWithFixed(this, invoke); return invoke; } protected InvokeNode createInvoke() { MethodCallTargetNode callTarget = graph() .add( new MethodCallTargetNode( invokeKind, targetMethod, arguments.toArray(new ValueNode[arguments.size()]), returnStamp, null)); InvokeNode invoke = graph().add(new InvokeNode(callTarget, bci)); if (stateAfter() != null) { invoke.setStateAfter(stateAfter().duplicate()); if (getStackKind() != JavaKind.Void) { invoke.stateAfter().replaceFirstInput(this, invoke); } } return invoke; } }
@NodeInfo( allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN) public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { public static final NodeClass<CheckcastArrayCopyCallNode> TYPE = NodeClass.create(CheckcastArrayCopyCallNode.class); @Input ValueNode src; @Input ValueNode srcPos; @Input ValueNode dest; @Input ValueNode destPos; @Input ValueNode length; @Input ValueNode destElemKlass; @Input ValueNode superCheckOffset; protected final boolean uninit; protected final HotSpotGraalRuntimeProvider runtime; protected CheckcastArrayCopyCallNode( @InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode superCheckOffset, ValueNode destElemKlass, boolean uninit) { super(TYPE, StampFactory.forKind(JavaKind.Int)); this.src = src; this.srcPos = srcPos; this.dest = dest; this.destPos = destPos; this.length = length; this.superCheckOffset = superCheckOffset; this.destElemKlass = destElemKlass; this.uninit = uninit; this.runtime = runtime; } public ValueNode getSource() { return src; } public ValueNode getSourcePosition() { return srcPos; } public ValueNode getDestination() { return dest; } public ValueNode getDestinationPosition() { return destPos; } public ValueNode getLength() { return length; } public boolean isUninit() { return uninit; } private ValueNode computeBase(ValueNode base, ValueNode pos) { FixedWithNextNode basePtr = graph().add(new GetObjectAddressNode(base)); graph().addBeforeFixed(this, basePtr); int shift = CodeUtil.log2(getArrayIndexScale(JavaKind.Object)); ValueNode scaledIndex = graph().unique(new LeftShiftNode(pos, ConstantNode.forInt(shift, graph()))); ValueNode offset = graph() .unique( new AddNode( scaledIndex, ConstantNode.forInt(getArrayBaseOffset(JavaKind.Object), graph()))); return graph().unique(new OffsetAddressNode(basePtr, offset)); } @Override public void lower(LoweringTool tool) { if (graph().getGuardsStage().areFrameStatesAtDeopts()) { ForeignCallDescriptor desc = HotSpotHostForeignCallsProvider.lookupCheckcastArraycopyDescriptor(isUninit()); StructuredGraph graph = graph(); ValueNode srcAddr = computeBase(getSource(), getSourcePosition()); ValueNode destAddr = computeBase(getDestination(), getDestinationPosition()); ValueNode len = getLength(); if (len.stamp().getStackKind() != runtime.getTarget().wordJavaKind) { len = IntegerConvertNode.convert( len, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph()); } ForeignCallNode call = graph.add( new ForeignCallNode( runtime.getHostBackend().getForeignCalls(), desc, srcAddr, destAddr, len, superCheckOffset, destElemKlass)); call.setStateAfter(stateAfter()); graph.replaceFixedWithFixed(this, call); } } @Override public LocationIdentity getLocationIdentity() { /* * Because of restrictions that the memory graph of snippets matches the original node, * pretend that we kill any. */ return LocationIdentity.any(); } @NodeIntrinsic public static native int checkcastArraycopy( Object src, int srcPos, Object dest, int destPos, int length, Word superCheckOffset, Object destElemKlass, @ConstantNodeParameter boolean uninit); }
/** * Represents the lowered version of an atomic compare-and-swap operation{@code CompareAndSwapNode}. */ @NodeInfo( allowedUsageTypes = {Value, Memory}, cycles = CYCLES_30, size = SIZE_8) public final class LoweredCompareAndSwapNode extends FixedAccessNode implements StateSplit, LIRLowerable, MemoryCheckpoint.Single { public static final NodeClass<LoweredCompareAndSwapNode> TYPE = NodeClass.create(LoweredCompareAndSwapNode.class); @Input ValueNode expectedValue; @Input ValueNode newValue; @OptionalInput(State) FrameState stateAfter; @Override public FrameState stateAfter() { return stateAfter; } @Override public void setStateAfter(FrameState x) { assert x == null || x.isAlive() : "frame state must be in a graph"; updateUsages(stateAfter, x); stateAfter = x; } @Override public boolean hasSideEffect() { return true; } public ValueNode getExpectedValue() { return expectedValue; } public ValueNode getNewValue() { return newValue; } public LoweredCompareAndSwapNode( AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) { super( TYPE, address, location, StampFactory.forKind(JavaKind.Boolean.getStackKind()), barrierType); assert expectedValue.getStackKind() == newValue.getStackKind(); this.expectedValue = expectedValue; this.newValue = newValue; } @Override public boolean canNullCheck() { return false; } @Override public void generate(NodeLIRBuilderTool gen) { assert getNewValue().stamp().isCompatible(getExpectedValue().stamp()); LIRGeneratorTool tool = gen.getLIRGeneratorTool(); LIRKind resultKind = tool.getLIRKind(stamp()); Value trueResult = tool.emitConstant(resultKind, JavaConstant.TRUE); Value falseResult = tool.emitConstant(resultKind, JavaConstant.FALSE); Value result = tool.emitCompareAndSwap( gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue()), trueResult, falseResult); gen.setResult(this, result); } }