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 {
|