
org.graalvm.compiler.nodes.GraphState Maven / Gradle / Ivy
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.nodes;
import java.util.EnumSet;
import java.util.Formatter;
import java.util.Objects;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.util.GraphUtil;
import jdk.vm.ci.meta.SpeculationLog;
/**
* Describes {@link StructuredGraph} state with respect to compilation.
*
* This state is defined by fields which represent
*
* - The progress made in the compilation (e.g. which stages have been reached (see
* {@link StageFlag}), which verification is performed by {@link FrameState}s (see
* {@link FrameStateVerification}))
* - The properties of the intermediate representation (e.g. if new {@link DeoptimizingNode}s can
* be introduced (see {@link GuardsStage}), if the graph contains nodes that require a stage to be
* applied on the graph (see {@link #getFutureRequiredStages()}))
*
*/
public final class GraphState {
/**
* These sets of {@link StageFlag}s represent the necessary stages that must be applied to a
* {@link StructuredGraph} for a complete compilation.
*/
private static final EnumSet HIGH_TIER_MANDATORY_STAGES = EnumSet.of(
StageFlag.HIGH_TIER_LOWERING);
private static final EnumSet MID_TIER_MANDATORY_STAGES = EnumSet.of(
StageFlag.VALUE_PROXY_REMOVAL,
StageFlag.SAFEPOINTS_INSERTION,
StageFlag.GUARD_LOWERING,
StageFlag.MID_TIER_LOWERING,
StageFlag.FSA,
StageFlag.BARRIER_ADDITION);
private static final EnumSet LOW_TIER_MANDATORY_STAGES = EnumSet.of(
StageFlag.LOW_TIER_LOWERING,
StageFlag.EXPAND_LOGIC,
StageFlag.ADDRESS_LOWERING);
private static final EnumSet ENTERPRISE_MID_TIER_MANDATORY_STAGES = EnumSet.of(
StageFlag.VALUE_PROXY_REMOVAL,
StageFlag.SAFEPOINTS_INSERTION,
StageFlag.GUARD_LOWERING,
StageFlag.MID_TIER_LOWERING,
StageFlag.FSA,
StageFlag.BARRIER_ADDITION,
StageFlag.NODE_VECTORIZATION);
/**
* This set of {@link StageFlag}s represents the stages a {@link StructuredGraph} initially
* requires to correctly pass all the other stages of the compilation. (See
* {@link #getFutureRequiredStages()})
*/
public static final EnumSet INITIAL_REQUIRED_STAGES = EnumSet.of(StageFlag.CANONICALIZATION);
/**
* Indicates a stage is in progress.
*/
private StageFlag currentStage;
/**
* Flag to indicate {@link #forceDisableFrameStateVerification()} was called.
*/
private boolean disabledFrameStateVerification;
/**
* Represents the status of {@linkplain FrameState} verification of
* {@linkplain AbstractStateSplit} state after.
*/
private FrameStateVerification frameStateVerification;
/**
* Records the stages required by this graph. For example, if a stage introduces nodes that need
* to be lowered in the graph, the graph will require a lowering stage to be in a correct state
* after the compilation. After the lowering has been executed, the requirement will be
* fulfilled. {@link GraphState#futureRequiredStages} should be empty after the compilation.
*/
private EnumSet futureRequiredStages;
/**
* Represents the state and properties of {@link DeoptimizingNode}s and {@link FrameState}s in
* the graph.
*/
private GuardsStage guardsStage;
/**
* Records which stages have been applied to the graph.
*/
private EnumSet stageFlags;
/**
* Contains the {@link SpeculationLog} used to perform speculative operations on this graph.
*/
private final SpeculationLog speculationLog;
/**
* Creates a {@link GraphState} with the given fields.
*
* @param isSubstitution determines this {@linkplain #getFrameStateVerification() frame state
* verification}. {@link FrameStateVerification#NONE} is used if it is {@code true},
* otherwise it is {@link FrameStateVerification#ALL}. If it is {@code true},
* {@link #isFrameStateVerificationDisabled()} will be {@code true}.
*/
public GraphState(StageFlag currentStage,
boolean disabledFrameStateVerification,
boolean isSubstitution,
EnumSet futureRequiredStages,
GuardsStage guardsStage,
SpeculationLog speculationLog,
EnumSet stageFlags) {
this(currentStage,
disabledFrameStateVerification || isSubstitution,
isSubstitution ? FrameStateVerification.NONE : FrameStateVerification.ALL,
futureRequiredStages,
guardsStage,
speculationLog,
stageFlags);
}
/**
* Creates a {@link GraphState} with the given fields.
*
* @param guardsStage the {@link GuardsStage} of this graph state,
* {@link GuardsStage#FLOATING_GUARDS} if it is {@code null}.
*/
public GraphState(StageFlag currentStage,
boolean disabledFrameStateVerification,
FrameStateVerification frameStateVerification,
EnumSet futureRequiredStages,
GuardsStage guardsStage,
SpeculationLog speculationLog,
EnumSet stageFlags) {
this.currentStage = currentStage;
this.disabledFrameStateVerification = disabledFrameStateVerification;
this.frameStateVerification = frameStateVerification;
this.futureRequiredStages = futureRequiredStages == null ? EnumSet.noneOf(StageFlag.class) : futureRequiredStages;
this.guardsStage = guardsStage == null ? GuardsStage.FLOATING_GUARDS : guardsStage;
this.speculationLog = speculationLog;
this.stageFlags = stageFlags == null ? EnumSet.noneOf(StageFlag.class) : stageFlags;
}
/**
* Creates a {@link GraphState} with {@linkplain #getGuardsStage() guards stage} set to
* {@link GuardsStage#FLOATING_GUARDS}, empty {@link EnumSet} for {@linkplain #getStageFlags()
* stage flags} and {@linkplain #getFutureRequiredStages() future required stages},
* {@linkplain #getFrameStateVerification() frame state verification} set to
* {@link FrameStateVerification#ALL} and {@code null} for the other fields.
*/
public static GraphState defaultGraphState() {
return new GraphState(null, false, false, null, null, null, null);
}
/**
* Creates a copy of this graph state. The copy's {@linkplain #getStageFlags() stage flags} and
* {@linkplain #getFutureRequiredStages() future required stages} are deep copy of this graph
* state's respective fields.
*/
public GraphState copy() {
return new GraphState(this.currentStage,
disabledFrameStateVerification,
this.frameStateVerification,
EnumSet.copyOf(this.futureRequiredStages),
this.guardsStage,
this.speculationLog,
EnumSet.copyOf(this.stageFlags));
}
/**
* Creates a copy of this graph state with the given {@linkplain #getSpeculationLog()
* speculation log}. The copy's {@linkplain #getStageFlags() stage flags} and
* {@linkplain #getFutureRequiredStages() future required stages} are deep copy of this graph
* state's respective fields.
*
* @param isSubstitution determines the copy's {@linkplain #getFrameStateVerification() frame
* state verification}. (See
* {@link #GraphState(StageFlag, boolean, boolean, EnumSet, GuardsStage, SpeculationLog, EnumSet)})
*/
public GraphState copyWith(boolean isSubstitution, SpeculationLog speculationLogForCopy) {
return new GraphState(this.currentStage,
disabledFrameStateVerification,
isSubstitution,
EnumSet.copyOf(this.futureRequiredStages),
this.guardsStage,
speculationLogForCopy,
EnumSet.copyOf(this.stageFlags));
}
@Override
public String toString() {
return toString("");
}
/**
* Creates a {@link String} with this {@linkplain #getGuardsStage() guards stage},
* {@linkplain #getStageFlags() stage flags}, {@linkplain #getFrameStateVerification() frame
* state verification} and {@linkplain #getFutureRequiredStages() future required stages}.
*
* @param prefix the string inserted at the beginning of each line of the resulting string.
*/
public String toString(String prefix) {
Formatter formatter = new Formatter();
formatter.format("%sGraphState:%n", prefix);
formatter.format("%s\tGuards stage: %s%n", prefix, guardsStage.toString());
formatter.format("%s\tStage flags:%n", prefix);
for (StageFlag flag : stageFlags) {
formatter.format("%s\t\t%s%n", prefix, flag.toString());
}
formatter.format("%s\tFrame state verification: %s%n", prefix, frameStateVerification.toString());
formatter.format("%s\tFuture required stages: %s%n", prefix, futureRequiredStages.toString());
return formatter.toString();
}
/**
* Creates a {@link String} representing the differences between this
* {@linkplain #getGuardsStage() guards stage}, {@linkplain #getStageFlags() stage flags},
* {@linkplain #getFrameStateVerification() frame state verification} and
* {@linkplain #getFutureRequiredStages() future required stages} and {@code previous}'s
* respective fields. If {@code this} {@link #equals} {@code previous}, an empty string is
* returned.
*/
public String updateFromPreviousToString(GraphState previous) {
if (this.equals(previous)) {
return "";
}
StringBuilder builder = new StringBuilder();
builder.append('{');
builder.append(valueStringAsDiff(previous.guardsStage, this.guardsStage, "Guards stage: ", ", "));
builder.append(newFlagsToString(previous.stageFlags, this.stageFlags, "+", "Stage flags: "));
builder.append(valueStringAsDiff(previous.frameStateVerification, this.frameStateVerification, "Frame state verification: ", ", "));
builder.append(newFlagsToString(previous.futureRequiredStages, this.futureRequiredStages, "+", "Future required stages: "));
builder.append(newFlagsToString(this.futureRequiredStages, previous.futureRequiredStages, "-", ""));
builder.setLength(builder.length() - 2);
builder.append('}');
return builder.toString();
}
/**
* @return the {@link String} representing the difference between {@code oldValue} and
* {@code newValue}, surrounded by {@code prefix} and {@code suffix}. If both values are
* equal, returns an empty string.
*/
private static String valueStringAsDiff(T oldValue, T newValue, String prefix, String suffix) {
if (oldValue == newValue) {
return "";
}
return String.format("%s%s -> %s%s", prefix, oldValue, newValue, suffix);
}
/**
* @return a {@link String} representing the {@link StageFlag}s that differ between
* {@code oldSet} and {@code newSet}. If both sets are equal, returns an empty string.
*/
private static String newFlagsToString(EnumSet oldSet, EnumSet newSet, String flagPrefix, String prefix) {
Formatter formatter = new Formatter();
EnumSet newFlags = newSet.clone();
newFlags.removeAll(oldSet);
if (!newFlags.isEmpty()) {
formatter.format(prefix);
for (StageFlag flag : newFlags) {
formatter.format("%s%s, ", flagPrefix, flag.toString());
}
}
return formatter.toString();
}
@Override
public int hashCode() {
return Objects.hash(currentStage, disabledFrameStateVerification, frameStateVerification, futureRequiredStages, guardsStage, speculationLog, stageFlags);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof GraphState)) {
return false;
}
GraphState graphState = (GraphState) obj;
return this.currentStage == graphState.currentStage &&
this.disabledFrameStateVerification == graphState.disabledFrameStateVerification &&
this.frameStateVerification == graphState.frameStateVerification &&
this.futureRequiredStages.equals(graphState.futureRequiredStages) &&
this.guardsStage == graphState.guardsStage &&
Objects.equals(this.speculationLog, graphState.speculationLog) &&
this.stageFlags.equals(graphState.stageFlags);
}
/**
* @return the {@link SpeculationLog} used to perform speculative operations on this graph.
*/
public SpeculationLog getSpeculationLog() {
return speculationLog;
}
/**
* Determines if {@linkplain #getFrameStateVerification() frame state verification} has been
* forcefully disabled.
*
* @return {@code true} if {@link #forceDisableFrameStateVerification()} or
* {@link StructuredGraph#clearAllStateAfterForTestingOnly()} has been called or if this
* graph was build as a substitution (see
* {@link #GraphState(StageFlag, boolean, boolean, EnumSet, GuardsStage, SpeculationLog, EnumSet)}).
*/
public boolean isFrameStateVerificationDisabled() {
return disabledFrameStateVerification;
}
/**
* Different node types verified during {@linkplain GraphState.FrameStateVerification}. See
* {@linkplain GraphState.FrameStateVerification} for details.
*/
public enum FrameStateVerificationFeature {
STATE_SPLITS,
MERGES,
LOOP_BEGINS,
LOOP_EXITS
}
/**
* The different stages of the compilation of a {@link Graph} regarding the status of
* {@linkplain FrameState} verification of {@linkplain AbstractStateSplit} state after.
* Verification starts with the mode {@linkplain FrameStateVerification#ALL}, i.e., all state
* splits with side-effects, merges and loop exits need a proper state after. The verification
* mode progresses monotonously until the {@linkplain FrameStateVerification#NONE} mode is
* reached. From there on, no further {@linkplain AbstractStateSplit#stateAfter} verification
* happens.
*/
public enum FrameStateVerification {
/**
* Verify all {@linkplain AbstractStateSplit} nodes that return {@code true} for
* {@linkplain AbstractStateSplit#hasSideEffect()} have a
* {@linkplain AbstractStateSplit#stateAfter} assigned. Additionally, verify
* {@linkplain LoopExitNode} and {@linkplain AbstractMergeNode} have a valid
* {@linkplain AbstractStateSplit#stateAfter}. This is necessary to avoid missing
* {@linkplain FrameState} after optimizations. See {@link GraphUtil#mayRemoveSplit} for
* more details.
*
* This stage is the initial verification stage for every graph.
*/
ALL(EnumSet.allOf(FrameStateVerificationFeature.class)),
/**
* Same as {@linkplain #ALL} except that {@linkplain LoopExitNode} nodes are no longer
* verified.
*/
ALL_EXCEPT_LOOP_EXIT(EnumSet.complementOf(EnumSet.of(FrameStateVerificationFeature.LOOP_EXITS))),
/**
* Same as {@linkplain #ALL_EXCEPT_LOOP_EXIT} except that {@linkplain LoopBeginNode} are no
* longer verified.
*/
ALL_EXCEPT_LOOPS(EnumSet.complementOf(EnumSet.of(FrameStateVerificationFeature.LOOP_BEGINS, FrameStateVerificationFeature.LOOP_EXITS))),
/**
* Verification is disabled. Typically used after assigning {@linkplain FrameState} to
* {@linkplain DeoptimizeNode} or for {@linkplain Snippet} compilations.
*/
NONE(EnumSet.noneOf(FrameStateVerificationFeature.class));
private EnumSet features;
FrameStateVerification(EnumSet features) {
this.features = features;
}
/**
* Determines if the current verification mode implies this feature.
*
* @param feature the other verification feature to check
* @return {@code true} if this verification mode implies the feature, {@code false}
* otherwise
*/
boolean implies(FrameStateVerificationFeature feature) {
return this.features.contains(feature);
}
}
/**
* @return the status of the {@link FrameState} verification of {@link AbstractStateSplit} state
* after.
*/
public FrameStateVerification getFrameStateVerification() {
return frameStateVerification;
}
/**
* Checks if this {@linkplain #getFrameStateVerification() frame state verification} can be
* weakened to the given {@link FrameStateVerification}. Verification can only be relaxed over
* the course of compilation.
*/
public boolean canWeakenFrameStateVerification(FrameStateVerification stage) {
if (isFrameStateVerificationDisabled()) {
assert frameStateVerification == FrameStateVerification.NONE : "Frame state verification is disabled, should be NONE but is " + frameStateVerification;
return true;
}
return frameStateVerification.ordinal() <= stage.ordinal();
}
/**
* Sets the given {@link FrameStateVerification} as this
* {@linkplain #getFrameStateVerification() frame state verification}.
*/
public void weakenFrameStateVerification(FrameStateVerification newFrameStateVerification) {
if (isFrameStateVerificationDisabled()) {
assert frameStateVerification == FrameStateVerification.NONE : "Frame state verification is disabled, should be NONE but is " + frameStateVerification;
return;
}
assert canWeakenFrameStateVerification(newFrameStateVerification) : "Old verification " + frameStateVerification + " must imply new verification " + newFrameStateVerification +
", i.e., verification can only be relaxed over the course of compilation";
frameStateVerification = newFrameStateVerification;
}
/**
* Forcefully disable {@linkplain #getFrameStateVerification() frame state verification} for the
* rest of this compilation. This must only be used for stubs, snippets, and test code that
* builds custom compilation pipelines.
*
* Normal compilations must use {@link #weakenFrameStateVerification(FrameStateVerification)} to
* progress through the standard stages of frame state verification. Calling this method is
* not equivalent to calling {@code weakenFrameStateVerification(NONE)}.
*/
public void forceDisableFrameStateVerification() {
weakenFrameStateVerification(FrameStateVerification.NONE);
this.disabledFrameStateVerification = true;
}
/**
* The different stages of the compilation of a {@link Graph} regarding the status of
* {@link GuardNode}s, {@link DeoptimizingNode}s and {@link FrameState}s. The stage of a graph
* progresses monotonously.
*/
public enum GuardsStage {
/**
* During this stage, there can be {@link FloatingNode floating} {@link DeoptimizingNode}s
* such as {@link GuardNode}s. New {@link DeoptimizingNode}s can be introduced without
* constraints. {@link FrameState}s are associated with {@link StateSplit} nodes.
*/
FLOATING_GUARDS,
/**
* During this stage, all {@link DeoptimizingNode}s must be {@link FixedNode fixed} but new
* {@link DeoptimizingNode}s can still be introduced. {@link FrameState}s are still
* associated with {@link StateSplit} nodes.
*/
FIXED_DEOPTS,
/**
* During this stage, all {@link DeoptimizingNode}s must be {@link FixedNode fixed}. New
* {@link DeoptimizingNode}s cannot be introduced. {@link FrameState}s are now associated
* with {@link DeoptimizingNode}s.
*/
AFTER_FSA;
/**
* Checks if this guards stage indicates that the graph may contain {@link FloatingNode
* floating} {@link DeoptimizingNode}s such as {@link GuardNode}s.
*/
public boolean allowsFloatingGuards() {
return this == FLOATING_GUARDS;
}
/**
* Checks if this guards stage indicates new {@link DeoptimizingNode}s can be introduced in
* the graph.
*/
public boolean allowsGuardInsertion() {
return this.ordinal() <= FIXED_DEOPTS.ordinal();
}
/**
* Checks if this guards stage indicates all {@link FrameState}s are associated with
* {@link DeoptimizingNode}s.
*/
public boolean areFrameStatesAtDeopts() {
return this == AFTER_FSA;
}
/**
* Checks if this guards stage indicates all {@link FrameState}s are associated with
* {@link StateSplit} nodes.
*/
public boolean areFrameStatesAtSideEffects() {
return !this.areFrameStatesAtDeopts();
}
/**
* Checks if this guards stage indicates all the {@link DeoptimizingNode}s are
* {@link FixedNode fixed}.
*/
public boolean areDeoptsFixed() {
return this.ordinal() >= FIXED_DEOPTS.ordinal();
}
/**
* Checks if this guards stage indicates it is necessary to have value proxies in the graph.
*/
public boolean requiresValueProxies() {
return this != AFTER_FSA;
}
/**
* Checks if this guards stage indicates a later or equivalent stage of the compilation than
* the given stage.
*/
public boolean reachedGuardsStage(GuardsStage stage) {
return this.ordinal() >= stage.ordinal();
}
}
/**
* @return the current {@link GuardsStage} for this graph state.
*/
public GuardsStage getGuardsStage() {
return guardsStage;
}
/**
* Sets the {@linkplain #getGuardsStage() guards stage} of this graph state. The new
* {@link GuardsStage} needs to indicate a progression in the compilation, not a regression.
*/
public void setGuardsStage(GuardsStage guardsStage) {
assert guardsStage.ordinal() >= this.guardsStage.ordinal();
this.guardsStage = guardsStage;
}
/**
* Determines if this graph state is configured in a way it only allows explicit exception edges
* and no floating guards which would be lowered to deoptimize nodes.
*/
public boolean isExplicitExceptionsNoDeopt() {
return guardsStage == GuardsStage.FIXED_DEOPTS && isAfterStage(StageFlag.GUARD_LOWERING);
}
/**
* Configure the graph to only allow explicit exception edges without floating guard nodes. That
* is the graph:
*
*
* - has explicit exception edges on {@link WithExceptionNode#exceptionEdge} successors
* - the graph does not support floating {@link GuardNode} as they lower to
* {@link DeoptimizeNode}
* - {@link GuardNode} nodes are never lowered since they are not part of the graph. The graph
* is always {@link #isAfterStage(StageFlag)} {@link StageFlag#GUARD_LOWERING}
*
*
* Note that this operation is only possible on empty graphs, i.e., it must be called at the
* beginning of a compilation when a graph is created since it influences how the parser and
* other components build the graph and meta data.
*/
public void configureExplicitExceptionsNoDeopt() {
assert !isExplicitExceptionsNoDeopt();
assert stageFlags.isEmpty() : "Must not have set a stage flag before";
assert guardsStage == GuardsStage.FLOATING_GUARDS : "Default guards stage is floating guards";
setGuardsStage(GraphState.GuardsStage.FIXED_DEOPTS);
setAfterStage(StageFlag.GUARD_LOWERING);
}
public void configureExplicitExceptionsNoDeoptIfNecessary() {
if (!isExplicitExceptionsNoDeopt()) {
configureExplicitExceptionsNoDeopt();
}
}
/**
* Indicates FSA has been applied to this graph. (See {@link #setGuardsStage(GuardsStage)} and
* {@link #setAfterStage(StageFlag)})
*/
public void setAfterFSA() {
setGuardsStage(GuardsStage.AFTER_FSA);
setAfterStage(StageFlag.FSA);
}
/**
* Different stages of the compilation regarding the status of various graph properties. The
* order used to defined theses stages corresponds to their order in a standard compilation.
*/
public enum StageFlag {
CANONICALIZATION,
/* Stages applied by high tier. */
FINAL_PARTIAL_ESCAPE,
HIGH_TIER_LOWERING,
/* Stages applied by mid tier. */
FLOATING_READS,
GUARD_MOVEMENT,
GUARD_LOWERING,
VALUE_PROXY_REMOVAL,
SAFEPOINTS_INSERTION,
MID_TIER_LOWERING,
OPTIMISTIC_ALIASING,
FSA,
NODE_VECTORIZATION,
VECTOR_MATERIALIZATION,
OPTIMISTIC_GUARDS,
BARRIER_ADDITION,
BARRIER_ELIMINATION,
/* Stages applied by low tier. */
LOW_TIER_LOWERING,
VECTOR_LOWERING,
EXPAND_LOGIC,
FIXED_READS,
ADDRESS_LOWERING,
FINAL_CANONICALIZATION,
TARGET_VECTOR_LOWERING,
}
/**
* Checks if this graph state is before a stage. This stage must not be in progress (see
* {@link #isDuringStage(StageFlag)}) nor have been applied yet (see
* {@link #isAfterStage(StageFlag)}).
*/
public boolean isBeforeStage(StageFlag stage) {
return !isDuringStage(stage) && !isAfterStage(stage);
}
/**
* Phases may set this flag to indicate that a stage is in progress. This is optional:
* {@link #isAfterStage(StageFlag)} may become true for a stage even if
* {@link #isDuringStage(StageFlag)} was never set for that stage.
*/
public boolean isDuringStage(StageFlag stage) {
return currentStage == stage;
}
/**
* Checks if a stage has already been applied to this graph.
*/
public boolean isAfterStage(StageFlag stage) {
return stageFlags.contains(stage);
}
/**
* Checks if multiple stages have been already applied to this graph.
*/
public boolean isAfterStages(EnumSet stages) {
return stageFlags.containsAll(stages);
}
/**
* Sets this {@link #currentStage} to indicate that a stage is in progress. This stage must not
* have been applied yet.
*/
public void setDuringStage(StageFlag stage) {
assert isBeforeStage(stage) : "Cannot set during stage " + stage + " since the graph is not before that stage";
currentStage = stage;
}
/**
* Adds the given stage to this {@linkplain #getStageFlags() stage flags} to indicate this stage
* has been applied. This stage must not have been applied yet.
*/
public void setAfterStage(StageFlag stage) {
assert !isAfterStage(stage) : "Cannot set after stage " + stage + " since the graph is already in that state";
stageFlags.add(stage);
currentStage = null;
}
/**
* @return the stages (see {@link StageFlag}) that were applied to this graph.
*/
public EnumSet getStageFlags() {
return stageFlags;
}
/**
* Checks if all the stages represented by the given {@link MandatoryStages} have been applied
* to this graph.
*/
public boolean hasAllMandatoryStages(MandatoryStages mandatoryStages) {
return stageFlags.containsAll(mandatoryStages.highTier) && stageFlags.containsAll(mandatoryStages.midTier) && stageFlags.containsAll(mandatoryStages.lowTier);
}
/**
* @return the number of stages that are in {@code targetStages} but not in the
* {@linkplain #getStageFlags() stage flags} of this graph state.
*/
public int countMissingStages(EnumSet targetStages) {
EnumSet target = EnumSet.copyOf(targetStages);
target.removeAll(stageFlags);
return target.size();
}
/**
* Adds the given {@link StageFlag} to the {@linkplain #getFutureRequiredStages() future
* required stages} of this graph state.
*/
public void addFutureStageRequirement(StageFlag stage) {
futureRequiredStages.add(stage);
}
/**
* Removes the {@linkplain #getFutureRequiredStages() requirement} to the given
* {@link StageFlag} from this graph state.
*/
public void removeRequirementToStage(StageFlag stage) {
futureRequiredStages.remove(stage);
}
/**
* Checks if the given {@link StageFlag} is contained in this graph state's
* {@linkplain #getFutureRequiredStages() future required stages}.
*/
public boolean requiresFutureStage(StageFlag stage) {
return futureRequiredStages.contains(stage);
}
/**
* Checks if this graph state has remaining {@link StageFlag}s requirements in
* {@linkplain #getFutureRequiredStages() future required stages}.
*/
public boolean requiresFutureStages() {
return !futureRequiredStages.isEmpty();
}
/**
* @return which stages this graph state requires. These {@linkplain #getFutureRequiredStages()
* future required stages} might includes lowering phases for nodes that were introduced
* in the graph by previous stages for example.
*/
public EnumSet getFutureRequiredStages() {
return futureRequiredStages;
}
/**
* Represents the necessary stages that must be applied to a {@link StructuredGraph} for a
* complete compilation depending on the compiler configuration chosen. There is a different
* {@link EnumSet} of {@link StageFlag}s for each tier of the compilation.
*/
public enum MandatoryStages {
ECONOMY(HIGH_TIER_MANDATORY_STAGES, MID_TIER_MANDATORY_STAGES, LOW_TIER_MANDATORY_STAGES),
COMMUNITY(HIGH_TIER_MANDATORY_STAGES, MID_TIER_MANDATORY_STAGES, LOW_TIER_MANDATORY_STAGES),
ENTERPRISE(HIGH_TIER_MANDATORY_STAGES, ENTERPRISE_MID_TIER_MANDATORY_STAGES, LOW_TIER_MANDATORY_STAGES);
private final EnumSet highTier;
private final EnumSet midTier;
private final EnumSet lowTier;
MandatoryStages(EnumSet highTier, EnumSet midTier, EnumSet lowTier) {
this.highTier = highTier;
this.midTier = midTier;
this.lowTier = lowTier;
}
/**
* @return the {@link MandatoryStages} corresponding to the given string. If no such value
* is found, returns {@link #COMMUNITY}.
*/
public static MandatoryStages getFromName(String name) {
switch (name.toLowerCase()) {
case "economy":
return ECONOMY;
case "community":
return COMMUNITY;
case "enterprise":
return ENTERPRISE;
default:
return COMMUNITY;
}
}
/**
* @return the {@link EnumSet} of {@link StageFlag}s that are mandatory for high tier.
*/
public EnumSet getHighTier() {
return highTier;
}
/**
* @return the {@link EnumSet} of {@link StageFlag}s that are mandatory for mid tier.
*/
public EnumSet getMidTier() {
return midTier;
}
/**
* @return the {@link EnumSet} of {@link StageFlag}s that are mandatory for low tier.
*/
public EnumSet getLowTier() {
return lowTier;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy