src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Sdiff src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph

src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java

Print this page




  28 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
  29 import static org.graalvm.compiler.graph.InputEdges.translateInto;
  30 import static org.graalvm.compiler.graph.Node.WithAllEdges;
  31 import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
  32 
  33 import java.lang.annotation.Annotation;
  34 import java.lang.reflect.AnnotatedElement;
  35 import java.lang.reflect.Field;
  36 import java.lang.reflect.Modifier;
  37 import java.util.ArrayList;
  38 import java.util.Arrays;
  39 import java.util.EnumSet;
  40 import java.util.Iterator;
  41 import java.util.NoSuchElementException;
  42 import java.util.Objects;
  43 import java.util.concurrent.atomic.AtomicInteger;
  44 
  45 import org.graalvm.compiler.core.common.FieldIntrospection;
  46 import org.graalvm.compiler.core.common.Fields;
  47 import org.graalvm.compiler.core.common.FieldsScanner;
  48 import org.graalvm.compiler.debug.Debug;
  49 import org.graalvm.compiler.debug.DebugCloseable;
  50 import org.graalvm.compiler.debug.DebugCounter;
  51 import org.graalvm.compiler.debug.DebugTimer;
  52 import org.graalvm.compiler.debug.GraalError;

  53 import org.graalvm.compiler.graph.Edges.Type;
  54 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
  55 import org.graalvm.compiler.graph.Node.EdgeVisitor;
  56 import org.graalvm.compiler.graph.Node.Input;
  57 import org.graalvm.compiler.graph.Node.OptionalInput;
  58 import org.graalvm.compiler.graph.Node.Successor;
  59 import org.graalvm.compiler.graph.iterators.NodeIterable;
  60 import org.graalvm.compiler.graph.spi.Canonicalizable;
  61 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
  62 import org.graalvm.compiler.graph.spi.Simplifiable;
  63 import org.graalvm.compiler.nodeinfo.InputType;
  64 import org.graalvm.compiler.nodeinfo.NodeCycles;
  65 import org.graalvm.compiler.nodeinfo.NodeInfo;
  66 import org.graalvm.compiler.nodeinfo.NodeSize;
  67 import org.graalvm.compiler.nodeinfo.Verbosity;
  68 import org.graalvm.util.EconomicMap;
  69 import org.graalvm.util.Equivalence;
  70 
  71 /**
  72  * Metadata for every {@link Node} type. The metadata includes:
  73  * <ul>
  74  * <li>The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods
  75  * for iterating over such fields.</li>
  76  * <li>The identifier for an {@link IterableNodeType} class.</li>
  77  * </ul>
  78  */
  79 public final class NodeClass<T> extends FieldIntrospection<T> {
  80 
  81     // Timers for creation of a NodeClass instance
  82     private static final DebugTimer Init_FieldScanning = Debug.timer("NodeClass.Init.FieldScanning");
  83     private static final DebugTimer Init_FieldScanningInner = Debug.timer("NodeClass.Init.FieldScanning.Inner");
  84     private static final DebugTimer Init_AnnotationParsing = Debug.timer("NodeClass.Init.AnnotationParsing");
  85     private static final DebugTimer Init_Edges = Debug.timer("NodeClass.Init.Edges");
  86     private static final DebugTimer Init_Data = Debug.timer("NodeClass.Init.Data");
  87     private static final DebugTimer Init_AllowedUsages = Debug.timer("NodeClass.Init.AllowedUsages");
  88     private static final DebugTimer Init_IterableIds = Debug.timer("NodeClass.Init.IterableIds");
  89 
  90     public static final long MAX_EDGES = 8;
  91     public static final long MAX_LIST_EDGES = 6;
  92     public static final long OFFSET_MASK = 0xFC;
  93     public static final long LIST_MASK = 0x01;
  94     public static final long NEXT_EDGE = 0x08;
  95 
  96     @SuppressWarnings("try")
  97     private static <T extends Annotation> T getAnnotationTimed(AnnotatedElement e, Class<T> annotationClass) {
  98         try (DebugCloseable s = Init_AnnotationParsing.start()) {
  99             return e.getAnnotation(annotationClass);
 100         }
 101     }
 102 
 103     /**
 104      * Gets the {@link NodeClass} associated with a given {@link Class}.
 105      */
 106     public static <T> NodeClass<T> create(Class<T> c) {
 107         assert get(c) == null;
 108         Class<? super T> superclass = c.getSuperclass();
 109         NodeClass<? super T> nodeSuperclass = null;
 110         if (superclass != NODE_CLASS) {
 111             nodeSuperclass = get(superclass);
 112         }
 113         return new NodeClass<>(c, nodeSuperclass);
 114     }
 115 
 116     @SuppressWarnings("unchecked")
 117     public static <T> NodeClass<T> get(Class<T> superclass) {
 118         try {


 127     private static final Class<?> NODE_CLASS = Node.class;
 128     private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
 129     private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
 130 
 131     private static AtomicInteger nextIterableId = new AtomicInteger();
 132     private static AtomicInteger nextLeafId = new AtomicInteger();
 133 
 134     private final InputEdges inputs;
 135     private final SuccessorEdges successors;
 136     private final NodeClass<? super T> superNodeClass;
 137 
 138     private final boolean canGVN;
 139     private final int startGVNNumber;
 140     private final String nameTemplate;
 141     private final int iterableId;
 142     private final EnumSet<InputType> allowedUsageTypes;
 143     private int[] iterableIds;
 144     private final long inputsIteration;
 145     private final long successorIteration;
 146 
 147     private static final DebugCounter ITERABLE_NODE_TYPES = Debug.counter("IterableNodeTypes");
 148     private final DebugCounter nodeIterableCount;
 149 
 150     /**
 151      * Determines if this node type implements {@link Canonicalizable}.
 152      */
 153     private final boolean isCanonicalizable;
 154 
 155     /**
 156      * Determines if this node type implements {@link BinaryCommutative}.
 157      */
 158     private final boolean isCommutative;
 159 
 160     /**
 161      * Determines if this node type implements {@link Simplifiable}.
 162      */
 163     private final boolean isSimplifiable;
 164     private final boolean isLeafNode;
 165 
 166     private final int leafId;
 167 
 168     public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass) {
 169         this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0);
 170     }
 171 
 172     @SuppressWarnings("try")
 173     public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
 174         super(clazz);

 175         this.superNodeClass = superNodeClass;
 176         assert NODE_CLASS.isAssignableFrom(clazz);
 177 
 178         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
 179         this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz);
 180         if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) {
 181             assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both";
 182         }
 183 
 184         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 185 
 186         NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass);
 187         try (DebugCloseable t = Init_FieldScanning.start()) {
 188             fs.scan(clazz, clazz.getSuperclass(), false);
 189         }
 190 
 191         try (DebugCloseable t1 = Init_Edges.start()) {
 192             successors = new SuccessorEdges(fs.directSuccessors, fs.successors);
 193             successorIteration = computeIterationMask(successors.type(), successors.getDirectCount(), successors.getOffsets());
 194             inputs = new InputEdges(fs.directInputs, fs.inputs);
 195             inputsIteration = computeIterationMask(inputs.type(), inputs.getDirectCount(), inputs.getOffsets());
 196         }
 197         try (DebugCloseable t1 = Init_Data.start()) {
 198             data = new Fields(fs.data);
 199         }
 200 
 201         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 202         if (isLeafNode) {
 203             this.leafId = nextLeafId.getAndIncrement();
 204         } else {
 205             this.leafId = -1;
 206         }
 207 
 208         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
 209         startGVNNumber = clazz.getName().hashCode();
 210 
 211         NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class);
 212         assert info != null : "Missing NodeInfo annotation on " + clazz;
 213         if (!info.nameTemplate().isEmpty()) {
 214             this.nameTemplate = info.nameTemplate();
 215         } else if (!info.shortName().isEmpty()) {
 216             this.nameTemplate = info.shortName();
 217         } else {
 218             this.nameTemplate = "";
 219         }
 220 
 221         try (DebugCloseable t1 = Init_AllowedUsages.start()) {
 222             allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone();
 223             allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes()));
 224         }
 225 
 226         if (presetIterableIds != null) {
 227             this.iterableIds = presetIterableIds;
 228             this.iterableId = presetIterableId;
 229         } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
 230             ITERABLE_NODE_TYPES.increment();
 231             try (DebugCloseable t1 = Init_IterableIds.start()) {
 232                 this.iterableId = nextIterableId.getAndIncrement();
 233 
 234                 NodeClass<?> snc = superNodeClass;
 235                 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
 236                     snc.addIterableId(iterableId);
 237                     snc = snc.superNodeClass;
 238                 }
 239 
 240                 this.iterableIds = new int[]{iterableId};
 241             }
 242         } else {
 243             this.iterableId = Node.NOT_ITERABLE;
 244             this.iterableIds = null;
 245         }
 246         nodeIterableCount = Debug.counter("NodeIterable_%s", clazz);
 247         assert verifyIterableIds();
 248 
 249         try (Debug.Scope scope = Debug.scope("NodeCosts")) {
 250             /*
 251              * Note: We do not check for the existence of the node cost annotations during
 252              * construction as not every node needs to have them set. However if costs are queried,
 253              * after the construction of the node class, they must be properly set. This is
 254              * important as we can not trust our cost model if there are unspecified nodes. Nodes
 255              * that do not need cost annotations are e.g. abstractions like FixedNode or
 256              * FloatingNode or ValueNode. Sub classes where costs are not specified will ask the
 257              * superclass for their costs during node class initialization. Therefore getters for
 258              * cycles and size can omit verification during creation.
 259              */
 260             NodeCycles c = info.cycles();
 261             if (c == NodeCycles.CYCLES_UNSET) {
 262                 cycles = superNodeClass != null ? superNodeClass.cycles : NodeCycles.CYCLES_UNSET;
 263             } else {
 264                 cycles = c;
 265             }
 266             assert cycles != null;
 267             NodeSize s = info.size();
 268             if (s == NodeSize.SIZE_UNSET) {
 269                 size = superNodeClass != null ? superNodeClass.size : NodeSize.SIZE_UNSET;
 270             } else {
 271                 size = s;
 272             }
 273             assert size != null;
 274             Debug.log("Node cost for node of type __| %s |_, cycles:%s,size:%s", clazz, cycles, size);
 275         }
 276 
 277     }
 278 
 279     private final NodeCycles cycles;
 280     private final NodeSize size;
 281 
 282     public NodeCycles cycles() {
 283         return cycles;
 284     }
 285 
 286     public NodeSize size() {
 287         return size;
 288     }
 289 
 290     public static long computeIterationMask(Type type, int directCount, long[] offsets) {
 291         long mask = 0;
 292         if (offsets.length > NodeClass.MAX_EDGES) {
 293             throw new GraalError("Exceeded maximum of %d edges (%s)", NodeClass.MAX_EDGES, type);
 294         }
 295         if (offsets.length - directCount > NodeClass.MAX_LIST_EDGES) {
 296             throw new GraalError("Exceeded maximum of %d list edges (%s)", NodeClass.MAX_LIST_EDGES, type);


 340             NodeInfo info = getClazz().getAnnotation(NodeInfo.class);
 341             if (!info.shortName().isEmpty()) {
 342                 shortName = info.shortName();
 343             } else {
 344                 String localShortName = getClazz().getSimpleName();
 345                 if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals("EndNode")) {
 346                     shortName = localShortName.substring(0, localShortName.length() - 4);
 347                 } else {
 348                     shortName = localShortName;
 349                 }
 350             }
 351         }
 352         return shortName;
 353     }
 354 
 355     @Override
 356     public Fields[] getAllFields() {
 357         return new Fields[]{data, inputs, successors};
 358     }
 359 
 360     public int[] iterableIds() {
 361         nodeIterableCount.increment();
 362         return iterableIds;
 363     }
 364 
 365     public int iterableId() {
 366         return iterableId;
 367     }
 368 
 369     public boolean valueNumberable() {
 370         return canGVN;
 371     }
 372 
 373     /**
 374      * Determines if this node type implements {@link Canonicalizable}.
 375      */
 376     public boolean isCanonicalizable() {
 377         return isCanonicalizable;
 378     }
 379 
 380     /**
 381      * Determines if this node type implements {@link BinaryCommutative}.


 434         final boolean optional;
 435 
 436         public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) {
 437             super(offset, name, type, declaringClass);
 438             this.inputType = inputType;
 439             this.optional = optional;
 440         }
 441 
 442         @Override
 443         public String toString() {
 444             return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}";
 445         }
 446     }
 447 
 448     protected static class NodeFieldsScanner extends FieldsScanner {
 449 
 450         public final ArrayList<InputInfo> inputs = new ArrayList<>();
 451         public final ArrayList<EdgeInfo> successors = new ArrayList<>();
 452         int directInputs;
 453         int directSuccessors;

 454 
 455         protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass<?> superNodeClass) {
 456             super(calc);

 457             if (superNodeClass != null) {
 458                 translateInto(superNodeClass.inputs, inputs);
 459                 translateInto(superNodeClass.successors, successors);
 460                 translateInto(superNodeClass.data, data);
 461                 directInputs = superNodeClass.inputs.getDirectCount();
 462                 directSuccessors = superNodeClass.successors.getDirectCount();
 463             }
 464         }
 465 
 466         @SuppressWarnings("try")
 467         @Override
 468         protected void scanField(Field field, long offset) {
 469             Input inputAnnotation = getAnnotationTimed(field, Node.Input.class);
 470             OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class);
 471             Successor successorAnnotation = getAnnotationTimed(field, Successor.class);
 472             try (DebugCloseable s = Init_FieldScanningInner.start()) {
 473                 Class<?> type = field.getType();
 474                 int modifiers = field.getModifiers();
 475 
 476                 if (inputAnnotation != null || optionalInputAnnotation != null) {
 477                     assert successorAnnotation == null : "field cannot be both input and successor";
 478                     if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
 479                         // NodeInputList fields should not be final since they are
 480                         // written (via Unsafe) in clearInputs()
 481                         GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field);
 482                         GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field);
 483                     } else {
 484                         GraalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
 485                         GraalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field);
 486                         directInputs++;
 487                     }
 488                     InputType inputType;
 489                     if (inputAnnotation != null) {
 490                         assert optionalInputAnnotation == null : "inputs can either be optional or non-optional";
 491                         inputType = inputAnnotation.value();
 492                     } else {




  28 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
  29 import static org.graalvm.compiler.graph.InputEdges.translateInto;
  30 import static org.graalvm.compiler.graph.Node.WithAllEdges;
  31 import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
  32 
  33 import java.lang.annotation.Annotation;
  34 import java.lang.reflect.AnnotatedElement;
  35 import java.lang.reflect.Field;
  36 import java.lang.reflect.Modifier;
  37 import java.util.ArrayList;
  38 import java.util.Arrays;
  39 import java.util.EnumSet;
  40 import java.util.Iterator;
  41 import java.util.NoSuchElementException;
  42 import java.util.Objects;
  43 import java.util.concurrent.atomic.AtomicInteger;
  44 
  45 import org.graalvm.compiler.core.common.FieldIntrospection;
  46 import org.graalvm.compiler.core.common.Fields;
  47 import org.graalvm.compiler.core.common.FieldsScanner;
  48 import org.graalvm.compiler.debug.CounterKey;
  49 import org.graalvm.compiler.debug.DebugCloseable;
  50 import org.graalvm.compiler.debug.DebugContext;

  51 import org.graalvm.compiler.debug.GraalError;
  52 import org.graalvm.compiler.debug.TimerKey;
  53 import org.graalvm.compiler.graph.Edges.Type;
  54 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
  55 import org.graalvm.compiler.graph.Node.EdgeVisitor;
  56 import org.graalvm.compiler.graph.Node.Input;
  57 import org.graalvm.compiler.graph.Node.OptionalInput;
  58 import org.graalvm.compiler.graph.Node.Successor;
  59 import org.graalvm.compiler.graph.iterators.NodeIterable;
  60 import org.graalvm.compiler.graph.spi.Canonicalizable;
  61 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative;
  62 import org.graalvm.compiler.graph.spi.Simplifiable;
  63 import org.graalvm.compiler.nodeinfo.InputType;
  64 import org.graalvm.compiler.nodeinfo.NodeCycles;
  65 import org.graalvm.compiler.nodeinfo.NodeInfo;
  66 import org.graalvm.compiler.nodeinfo.NodeSize;
  67 import org.graalvm.compiler.nodeinfo.Verbosity;
  68 import org.graalvm.util.EconomicMap;
  69 import org.graalvm.util.Equivalence;
  70 
  71 /**
  72  * Metadata for every {@link Node} type. The metadata includes:
  73  * <ul>
  74  * <li>The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods
  75  * for iterating over such fields.</li>
  76  * <li>The identifier for an {@link IterableNodeType} class.</li>
  77  * </ul>
  78  */
  79 public final class NodeClass<T> extends FieldIntrospection<T> {
  80 
  81     // Timers for creation of a NodeClass instance
  82     private static final TimerKey Init_FieldScanning = DebugContext.timer("NodeClass.Init.FieldScanning");
  83     private static final TimerKey Init_FieldScanningInner = DebugContext.timer("NodeClass.Init.FieldScanning.Inner");
  84     private static final TimerKey Init_AnnotationParsing = DebugContext.timer("NodeClass.Init.AnnotationParsing");
  85     private static final TimerKey Init_Edges = DebugContext.timer("NodeClass.Init.Edges");
  86     private static final TimerKey Init_Data = DebugContext.timer("NodeClass.Init.Data");
  87     private static final TimerKey Init_AllowedUsages = DebugContext.timer("NodeClass.Init.AllowedUsages");
  88     private static final TimerKey Init_IterableIds = DebugContext.timer("NodeClass.Init.IterableIds");
  89 
  90     public static final long MAX_EDGES = 8;
  91     public static final long MAX_LIST_EDGES = 6;
  92     public static final long OFFSET_MASK = 0xFC;
  93     public static final long LIST_MASK = 0x01;
  94     public static final long NEXT_EDGE = 0x08;
  95 
  96     @SuppressWarnings("try")
  97     private static <T extends Annotation> T getAnnotationTimed(AnnotatedElement e, Class<T> annotationClass, DebugContext debug) {
  98         try (DebugCloseable s = Init_AnnotationParsing.start(debug)) {
  99             return e.getAnnotation(annotationClass);
 100         }
 101     }
 102 
 103     /**
 104      * Gets the {@link NodeClass} associated with a given {@link Class}.
 105      */
 106     public static <T> NodeClass<T> create(Class<T> c) {
 107         assert get(c) == null;
 108         Class<? super T> superclass = c.getSuperclass();
 109         NodeClass<? super T> nodeSuperclass = null;
 110         if (superclass != NODE_CLASS) {
 111             nodeSuperclass = get(superclass);
 112         }
 113         return new NodeClass<>(c, nodeSuperclass);
 114     }
 115 
 116     @SuppressWarnings("unchecked")
 117     public static <T> NodeClass<T> get(Class<T> superclass) {
 118         try {


 127     private static final Class<?> NODE_CLASS = Node.class;
 128     private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
 129     private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
 130 
 131     private static AtomicInteger nextIterableId = new AtomicInteger();
 132     private static AtomicInteger nextLeafId = new AtomicInteger();
 133 
 134     private final InputEdges inputs;
 135     private final SuccessorEdges successors;
 136     private final NodeClass<? super T> superNodeClass;
 137 
 138     private final boolean canGVN;
 139     private final int startGVNNumber;
 140     private final String nameTemplate;
 141     private final int iterableId;
 142     private final EnumSet<InputType> allowedUsageTypes;
 143     private int[] iterableIds;
 144     private final long inputsIteration;
 145     private final long successorIteration;
 146 
 147     private static final CounterKey ITERABLE_NODE_TYPES = DebugContext.counter("IterableNodeTypes");

 148 
 149     /**
 150      * Determines if this node type implements {@link Canonicalizable}.
 151      */
 152     private final boolean isCanonicalizable;
 153 
 154     /**
 155      * Determines if this node type implements {@link BinaryCommutative}.
 156      */
 157     private final boolean isCommutative;
 158 
 159     /**
 160      * Determines if this node type implements {@link Simplifiable}.
 161      */
 162     private final boolean isSimplifiable;
 163     private final boolean isLeafNode;
 164 
 165     private final int leafId;
 166 
 167     public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass) {
 168         this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0);
 169     }
 170 
 171     @SuppressWarnings("try")
 172     public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) {
 173         super(clazz);
 174         DebugContext debug = DebugContext.forCurrentThread();
 175         this.superNodeClass = superNodeClass;
 176         assert NODE_CLASS.isAssignableFrom(clazz);
 177 
 178         this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz);
 179         this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz);
 180         if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) {
 181             assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both";
 182         }
 183 
 184         this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz);
 185 
 186         NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass, debug);
 187         try (DebugCloseable t = Init_FieldScanning.start(debug)) {
 188             fs.scan(clazz, clazz.getSuperclass(), false);
 189         }
 190 
 191         try (DebugCloseable t1 = Init_Edges.start(debug)) {
 192             successors = new SuccessorEdges(fs.directSuccessors, fs.successors);
 193             successorIteration = computeIterationMask(successors.type(), successors.getDirectCount(), successors.getOffsets());
 194             inputs = new InputEdges(fs.directInputs, fs.inputs);
 195             inputsIteration = computeIterationMask(inputs.type(), inputs.getDirectCount(), inputs.getOffsets());
 196         }
 197         try (DebugCloseable t1 = Init_Data.start(debug)) {
 198             data = new Fields(fs.data);
 199         }
 200 
 201         isLeafNode = inputs.getCount() + successors.getCount() == 0;
 202         if (isLeafNode) {
 203             this.leafId = nextLeafId.getAndIncrement();
 204         } else {
 205             this.leafId = -1;
 206         }
 207 
 208         canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz);
 209         startGVNNumber = clazz.getName().hashCode();
 210 
 211         NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class, debug);
 212         assert info != null : "Missing NodeInfo annotation on " + clazz;
 213         if (!info.nameTemplate().isEmpty()) {
 214             this.nameTemplate = info.nameTemplate();
 215         } else if (!info.shortName().isEmpty()) {
 216             this.nameTemplate = info.shortName();
 217         } else {
 218             this.nameTemplate = "";
 219         }
 220 
 221         try (DebugCloseable t1 = Init_AllowedUsages.start(debug)) {
 222             allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone();
 223             allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes()));
 224         }
 225 
 226         if (presetIterableIds != null) {
 227             this.iterableIds = presetIterableIds;
 228             this.iterableId = presetIterableId;
 229         } else if (IterableNodeType.class.isAssignableFrom(clazz)) {
 230             ITERABLE_NODE_TYPES.increment(debug);
 231             try (DebugCloseable t1 = Init_IterableIds.start(debug)) {
 232                 this.iterableId = nextIterableId.getAndIncrement();
 233 
 234                 NodeClass<?> snc = superNodeClass;
 235                 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) {
 236                     snc.addIterableId(iterableId);
 237                     snc = snc.superNodeClass;
 238                 }
 239 
 240                 this.iterableIds = new int[]{iterableId};
 241             }
 242         } else {
 243             this.iterableId = Node.NOT_ITERABLE;
 244             this.iterableIds = null;
 245         }

 246         assert verifyIterableIds();
 247 
 248         try (DebugContext.Scope scope = debug.scope("NodeCosts")) {
 249             /*
 250              * Note: We do not check for the existence of the node cost annotations during
 251              * construction as not every node needs to have them set. However if costs are queried,
 252              * after the construction of the node class, they must be properly set. This is
 253              * important as we can not trust our cost model if there are unspecified nodes. Nodes
 254              * that do not need cost annotations are e.g. abstractions like FixedNode or
 255              * FloatingNode or ValueNode. Sub classes where costs are not specified will ask the
 256              * superclass for their costs during node class initialization. Therefore getters for
 257              * cycles and size can omit verification during creation.
 258              */
 259             NodeCycles c = info.cycles();
 260             if (c == NodeCycles.CYCLES_UNSET) {
 261                 cycles = superNodeClass != null ? superNodeClass.cycles : NodeCycles.CYCLES_UNSET;
 262             } else {
 263                 cycles = c;
 264             }
 265             assert cycles != null;
 266             NodeSize s = info.size();
 267             if (s == NodeSize.SIZE_UNSET) {
 268                 size = superNodeClass != null ? superNodeClass.size : NodeSize.SIZE_UNSET;
 269             } else {
 270                 size = s;
 271             }
 272             assert size != null;
 273             debug.log("Node cost for node of type __| %s |_, cycles:%s,size:%s", clazz, cycles, size);
 274         }

 275     }
 276 
 277     private final NodeCycles cycles;
 278     private final NodeSize size;
 279 
 280     public NodeCycles cycles() {
 281         return cycles;
 282     }
 283 
 284     public NodeSize size() {
 285         return size;
 286     }
 287 
 288     public static long computeIterationMask(Type type, int directCount, long[] offsets) {
 289         long mask = 0;
 290         if (offsets.length > NodeClass.MAX_EDGES) {
 291             throw new GraalError("Exceeded maximum of %d edges (%s)", NodeClass.MAX_EDGES, type);
 292         }
 293         if (offsets.length - directCount > NodeClass.MAX_LIST_EDGES) {
 294             throw new GraalError("Exceeded maximum of %d list edges (%s)", NodeClass.MAX_LIST_EDGES, type);


 338             NodeInfo info = getClazz().getAnnotation(NodeInfo.class);
 339             if (!info.shortName().isEmpty()) {
 340                 shortName = info.shortName();
 341             } else {
 342                 String localShortName = getClazz().getSimpleName();
 343                 if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals("EndNode")) {
 344                     shortName = localShortName.substring(0, localShortName.length() - 4);
 345                 } else {
 346                     shortName = localShortName;
 347                 }
 348             }
 349         }
 350         return shortName;
 351     }
 352 
 353     @Override
 354     public Fields[] getAllFields() {
 355         return new Fields[]{data, inputs, successors};
 356     }
 357 
 358     int[] iterableIds() {

 359         return iterableIds;
 360     }
 361 
 362     public int iterableId() {
 363         return iterableId;
 364     }
 365 
 366     public boolean valueNumberable() {
 367         return canGVN;
 368     }
 369 
 370     /**
 371      * Determines if this node type implements {@link Canonicalizable}.
 372      */
 373     public boolean isCanonicalizable() {
 374         return isCanonicalizable;
 375     }
 376 
 377     /**
 378      * Determines if this node type implements {@link BinaryCommutative}.


 431         final boolean optional;
 432 
 433         public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) {
 434             super(offset, name, type, declaringClass);
 435             this.inputType = inputType;
 436             this.optional = optional;
 437         }
 438 
 439         @Override
 440         public String toString() {
 441             return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}";
 442         }
 443     }
 444 
 445     protected static class NodeFieldsScanner extends FieldsScanner {
 446 
 447         public final ArrayList<InputInfo> inputs = new ArrayList<>();
 448         public final ArrayList<EdgeInfo> successors = new ArrayList<>();
 449         int directInputs;
 450         int directSuccessors;
 451         final DebugContext debug;
 452 
 453         protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass<?> superNodeClass, DebugContext debug) {
 454             super(calc);
 455             this.debug = debug;
 456             if (superNodeClass != null) {
 457                 translateInto(superNodeClass.inputs, inputs);
 458                 translateInto(superNodeClass.successors, successors);
 459                 translateInto(superNodeClass.data, data);
 460                 directInputs = superNodeClass.inputs.getDirectCount();
 461                 directSuccessors = superNodeClass.successors.getDirectCount();
 462             }
 463         }
 464 
 465         @SuppressWarnings("try")
 466         @Override
 467         protected void scanField(Field field, long offset) {
 468             Input inputAnnotation = getAnnotationTimed(field, Node.Input.class, debug);
 469             OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class, debug);
 470             Successor successorAnnotation = getAnnotationTimed(field, Successor.class, debug);
 471             try (DebugCloseable s = Init_FieldScanningInner.start(debug)) {
 472                 Class<?> type = field.getType();
 473                 int modifiers = field.getModifiers();
 474 
 475                 if (inputAnnotation != null || optionalInputAnnotation != null) {
 476                     assert successorAnnotation == null : "field cannot be both input and successor";
 477                     if (INPUT_LIST_CLASS.isAssignableFrom(type)) {
 478                         // NodeInputList fields should not be final since they are
 479                         // written (via Unsafe) in clearInputs()
 480                         GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field);
 481                         GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field);
 482                     } else {
 483                         GraalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type);
 484                         GraalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field);
 485                         directInputs++;
 486                     }
 487                     InputType inputType;
 488                     if (inputAnnotation != null) {
 489                         assert optionalInputAnnotation == null : "inputs can either be optional or non-optional";
 490                         inputType = inputAnnotation.value();
 491                     } else {


src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File