1 /* 2 * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.graph; 26 27 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; 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 jdk.internal.vm.compiler.collections.EconomicMap; 46 import jdk.internal.vm.compiler.collections.Equivalence; 47 import org.graalvm.compiler.core.common.FieldIntrospection; 48 import org.graalvm.compiler.core.common.Fields; 49 import org.graalvm.compiler.core.common.FieldsScanner; 50 import org.graalvm.compiler.debug.CounterKey; 51 import org.graalvm.compiler.debug.DebugCloseable; 52 import org.graalvm.compiler.debug.DebugContext; 53 import org.graalvm.compiler.debug.GraalError; 54 import org.graalvm.compiler.debug.TTY; 55 import org.graalvm.compiler.debug.TimerKey; 56 import org.graalvm.compiler.graph.Edges.Type; 57 import org.graalvm.compiler.graph.Graph.DuplicationReplacement; 58 import org.graalvm.compiler.graph.Node.EdgeVisitor; 59 import org.graalvm.compiler.graph.Node.Input; 60 import org.graalvm.compiler.graph.Node.OptionalInput; 61 import org.graalvm.compiler.graph.Node.Successor; 62 import org.graalvm.compiler.graph.iterators.NodeIterable; 63 import org.graalvm.compiler.graph.spi.Canonicalizable; 64 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; 65 import org.graalvm.compiler.graph.spi.Simplifiable; 66 import org.graalvm.compiler.nodeinfo.InputType; 67 import org.graalvm.compiler.nodeinfo.NodeCycles; 68 import org.graalvm.compiler.nodeinfo.NodeInfo; 69 import org.graalvm.compiler.nodeinfo.NodeSize; 70 import org.graalvm.compiler.nodeinfo.Verbosity; 71 72 /** 73 * Metadata for every {@link Node} type. The metadata includes: 74 * <ul> 75 * <li>The offsets of fields annotated with {@link Input} and {@link Successor} as well as methods 76 * for iterating over such fields.</li> 77 * <li>The identifier for an {@link IterableNodeType} class.</li> 78 * </ul> 79 */ 80 public final class NodeClass<T> extends FieldIntrospection<T> { 81 82 // Timers for creation of a NodeClass instance 83 private static final TimerKey Init_FieldScanning = DebugContext.timer("NodeClass.Init.FieldScanning"); 84 private static final TimerKey Init_FieldScanningInner = DebugContext.timer("NodeClass.Init.FieldScanning.Inner"); 85 private static final TimerKey Init_AnnotationParsing = DebugContext.timer("NodeClass.Init.AnnotationParsing"); 86 private static final TimerKey Init_Edges = DebugContext.timer("NodeClass.Init.Edges"); 87 private static final TimerKey Init_Data = DebugContext.timer("NodeClass.Init.Data"); 88 private static final TimerKey Init_AllowedUsages = DebugContext.timer("NodeClass.Init.AllowedUsages"); 89 private static final TimerKey Init_IterableIds = DebugContext.timer("NodeClass.Init.IterableIds"); 90 91 public static final long MAX_EDGES = 8; 92 public static final long MAX_LIST_EDGES = 6; 93 public static final long OFFSET_MASK = 0xFC; 94 public static final long LIST_MASK = 0x01; 95 public static final long NEXT_EDGE = 0x08; 96 97 @SuppressWarnings("try") 98 private static <T extends Annotation> T getAnnotationTimed(AnnotatedElement e, Class<T> annotationClass, DebugContext debug) { 99 try (DebugCloseable s = Init_AnnotationParsing.start(debug)) { 100 return e.getAnnotation(annotationClass); 101 } 102 } 103 104 /** 105 * Gets the {@link NodeClass} associated with a given {@link Class}. 106 */ 107 public static <T> NodeClass<T> create(Class<T> c) { 108 assert getUnchecked(c) == null; 109 Class<? super T> superclass = c.getSuperclass(); 110 NodeClass<? super T> nodeSuperclass = null; 111 if (superclass != NODE_CLASS) { 112 nodeSuperclass = get(superclass); 113 } 114 return new NodeClass<>(c, nodeSuperclass); 115 } 116 117 @SuppressWarnings("unchecked") 118 private static <T> NodeClass<T> getUnchecked(Class<T> clazz) { 119 try { 120 Field field = clazz.getDeclaredField("TYPE"); 121 field.setAccessible(true); 122 return (NodeClass<T>) field.get(null); 123 } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { 124 throw new RuntimeException(e); 125 } 126 } 127 128 public static <T> NodeClass<T> get(Class<T> clazz) { 129 int numTries = 0; 130 while (true) { 131 boolean shouldBeInitializedBefore = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz); 132 133 NodeClass<T> result = getUnchecked(clazz); 134 if (result != null || clazz == NODE_CLASS) { 135 return result; 136 } 137 138 /* 139 * GR-9537: We observed a transient problem with TYPE fields being null. Retry a couple 140 * of times and print something to the log so that we can gather more diagnostic 141 * information without failing gates. 142 */ 143 numTries++; 144 boolean shouldBeInitializedAfter = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz); 145 String msg = "GR-9537 Reflective field access of TYPE field returned null. This is probably a bug in HotSpot class initialization. " + 146 " clazz: " + clazz.getTypeName() + ", numTries: " + numTries + 147 ", shouldBeInitializedBefore: " + shouldBeInitializedBefore + ", shouldBeInitializedAfter: " + shouldBeInitializedAfter; 148 if (numTries <= 100) { 149 TTY.println(msg); 150 UnsafeAccess.UNSAFE.ensureClassInitialized(clazz); 151 } else { 152 throw GraalError.shouldNotReachHere(msg); 153 } 154 return result; 155 } 156 } 157 158 private static final Class<?> NODE_CLASS = Node.class; 159 private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class; 160 private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; 161 162 private static AtomicInteger nextIterableId = new AtomicInteger(); 163 private static AtomicInteger nextLeafId = new AtomicInteger(); 164 165 private final InputEdges inputs; 166 private final SuccessorEdges successors; 167 private final NodeClass<? super T> superNodeClass; 168 169 private final boolean canGVN; 170 private final int startGVNNumber; 171 private final String nameTemplate; 172 private final int iterableId; 173 private final EnumSet<InputType> allowedUsageTypes; 174 private int[] iterableIds; 175 private final long inputsIteration; 176 private final long successorIteration; 177 178 private static final CounterKey ITERABLE_NODE_TYPES = DebugContext.counter("IterableNodeTypes"); 179 180 /** 181 * Determines if this node type implements {@link Canonicalizable}. 182 */ 183 private final boolean isCanonicalizable; 184 185 /** 186 * Determines if this node type implements {@link BinaryCommutative}. 187 */ 188 private final boolean isCommutative; 189 190 /** 191 * Determines if this node type implements {@link Simplifiable}. 192 */ 193 private final boolean isSimplifiable; 194 private final boolean isLeafNode; 195 196 private final int leafId; 197 198 public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass) { 199 this(clazz, superNodeClass, new FieldsScanner.DefaultCalcOffset(), null, 0); 200 } 201 202 @SuppressWarnings("try") 203 public NodeClass(Class<T> clazz, NodeClass<? super T> superNodeClass, FieldsScanner.CalcOffset calcOffset, int[] presetIterableIds, int presetIterableId) { 204 super(clazz); 205 DebugContext debug = DebugContext.forCurrentThread(); 206 this.superNodeClass = superNodeClass; 207 assert NODE_CLASS.isAssignableFrom(clazz); 208 209 this.isCanonicalizable = Canonicalizable.class.isAssignableFrom(clazz); 210 this.isCommutative = BinaryCommutative.class.isAssignableFrom(clazz); 211 if (Canonicalizable.Unary.class.isAssignableFrom(clazz) || Canonicalizable.Binary.class.isAssignableFrom(clazz)) { 212 assert Canonicalizable.Unary.class.isAssignableFrom(clazz) ^ Canonicalizable.Binary.class.isAssignableFrom(clazz) : clazz + " should implement either Unary or Binary, not both"; 213 } 214 215 this.isSimplifiable = Simplifiable.class.isAssignableFrom(clazz); 216 217 NodeFieldsScanner fs = new NodeFieldsScanner(calcOffset, superNodeClass, debug); 218 try (DebugCloseable t = Init_FieldScanning.start(debug)) { 219 fs.scan(clazz, clazz.getSuperclass(), false); 220 } 221 222 try (DebugCloseable t1 = Init_Edges.start(debug)) { 223 successors = new SuccessorEdges(fs.directSuccessors, fs.successors); 224 successorIteration = computeIterationMask(successors.type(), successors.getDirectCount(), successors.getOffsets()); 225 inputs = new InputEdges(fs.directInputs, fs.inputs); 226 inputsIteration = computeIterationMask(inputs.type(), inputs.getDirectCount(), inputs.getOffsets()); 227 } 228 try (DebugCloseable t1 = Init_Data.start(debug)) { 229 data = new Fields(fs.data); 230 } 231 232 isLeafNode = inputs.getCount() + successors.getCount() == 0; 233 if (isLeafNode) { 234 this.leafId = nextLeafId.getAndIncrement(); 235 } else { 236 this.leafId = -1; 237 } 238 239 canGVN = Node.ValueNumberable.class.isAssignableFrom(clazz); 240 startGVNNumber = clazz.getName().hashCode(); 241 242 NodeInfo info = getAnnotationTimed(clazz, NodeInfo.class, debug); 243 assert info != null : "Missing NodeInfo annotation on " + clazz; 244 if (!info.nameTemplate().isEmpty()) { 245 this.nameTemplate = info.nameTemplate(); 246 } else if (!info.shortName().isEmpty()) { 247 this.nameTemplate = info.shortName(); 248 } else { 249 this.nameTemplate = ""; 250 } 251 252 try (DebugCloseable t1 = Init_AllowedUsages.start(debug)) { 253 allowedUsageTypes = superNodeClass == null ? EnumSet.noneOf(InputType.class) : superNodeClass.allowedUsageTypes.clone(); 254 allowedUsageTypes.addAll(Arrays.asList(info.allowedUsageTypes())); 255 } 256 257 if (presetIterableIds != null) { 258 this.iterableIds = presetIterableIds; 259 this.iterableId = presetIterableId; 260 } else if (IterableNodeType.class.isAssignableFrom(clazz)) { 261 ITERABLE_NODE_TYPES.increment(debug); 262 try (DebugCloseable t1 = Init_IterableIds.start(debug)) { 263 this.iterableId = nextIterableId.getAndIncrement(); 264 265 NodeClass<?> snc = superNodeClass; 266 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { 267 snc.addIterableId(iterableId); 268 snc = snc.superNodeClass; 269 } 270 271 this.iterableIds = new int[]{iterableId}; 272 } 273 } else { 274 this.iterableId = Node.NOT_ITERABLE; 275 this.iterableIds = null; 276 } 277 assert verifyIterableIds(); 278 279 try (DebugContext.Scope scope = debug.scope("NodeCosts")) { 280 /* 281 * Note: We do not check for the existence of the node cost annotations during 282 * construction as not every node needs to have them set. However if costs are queried, 283 * after the construction of the node class, they must be properly set. This is 284 * important as we can not trust our cost model if there are unspecified nodes. Nodes 285 * that do not need cost annotations are e.g. abstractions like FixedNode or 286 * FloatingNode or ValueNode. Sub classes where costs are not specified will ask the 287 * superclass for their costs during node class initialization. Therefore getters for 288 * cycles and size can omit verification during creation. 289 */ 290 NodeCycles c = info.cycles(); 291 if (c == NodeCycles.CYCLES_UNSET) { 292 cycles = superNodeClass != null ? superNodeClass.cycles : NodeCycles.CYCLES_UNSET; 293 } else { 294 cycles = c; 295 } 296 assert cycles != null; 297 NodeSize s = info.size(); 298 if (s == NodeSize.SIZE_UNSET) { 299 size = superNodeClass != null ? superNodeClass.size : NodeSize.SIZE_UNSET; 300 } else { 301 size = s; 302 } 303 assert size != null; 304 debug.log("Node cost for node of type __| %s |_, cycles:%s,size:%s", clazz, cycles, size); 305 } 306 } 307 308 private final NodeCycles cycles; 309 private final NodeSize size; 310 311 public NodeCycles cycles() { 312 return cycles; 313 } 314 315 public NodeSize size() { 316 return size; 317 } 318 319 public static long computeIterationMask(Type type, int directCount, long[] offsets) { 320 long mask = 0; 321 if (offsets.length > NodeClass.MAX_EDGES) { 322 throw new GraalError("Exceeded maximum of %d edges (%s)", NodeClass.MAX_EDGES, type); 323 } 324 if (offsets.length - directCount > NodeClass.MAX_LIST_EDGES) { 325 throw new GraalError("Exceeded maximum of %d list edges (%s)", NodeClass.MAX_LIST_EDGES, type); 326 } 327 328 for (int i = offsets.length - 1; i >= 0; i--) { 329 long offset = offsets[i]; 330 assert ((offset & 0xFF) == offset) : "field offset too large!"; 331 mask <<= NodeClass.NEXT_EDGE; 332 mask |= offset; 333 if (i >= directCount) { 334 mask |= 0x3; 335 } 336 } 337 return mask; 338 } 339 340 private synchronized void addIterableId(int newIterableId) { 341 assert !containsId(newIterableId, iterableIds); 342 int[] copy = Arrays.copyOf(iterableIds, iterableIds.length + 1); 343 copy[iterableIds.length] = newIterableId; 344 iterableIds = copy; 345 } 346 347 private boolean verifyIterableIds() { 348 NodeClass<?> snc = superNodeClass; 349 while (snc != null && IterableNodeType.class.isAssignableFrom(snc.getClazz())) { 350 assert containsId(iterableId, snc.iterableIds); 351 snc = snc.superNodeClass; 352 } 353 return true; 354 } 355 356 private static boolean containsId(int iterableId, int[] iterableIds) { 357 for (int i : iterableIds) { 358 if (i == iterableId) { 359 return true; 360 } 361 } 362 return false; 363 } 364 365 private String shortName; 366 367 public String shortName() { 368 if (shortName == null) { 369 NodeInfo info = getClazz().getAnnotation(NodeInfo.class); 370 if (!info.shortName().isEmpty()) { 371 shortName = info.shortName(); 372 } else { 373 String localShortName = getClazz().getSimpleName(); 374 if (localShortName.endsWith("Node") && !localShortName.equals("StartNode") && !localShortName.equals("EndNode")) { 375 shortName = localShortName.substring(0, localShortName.length() - 4); 376 } else { 377 shortName = localShortName; 378 } 379 } 380 } 381 return shortName; 382 } 383 384 @Override 385 public Fields[] getAllFields() { 386 return new Fields[]{data, inputs, successors}; 387 } 388 389 int[] iterableIds() { 390 return iterableIds; 391 } 392 393 public int iterableId() { 394 return iterableId; 395 } 396 397 public boolean valueNumberable() { 398 return canGVN; 399 } 400 401 /** 402 * Determines if this node type implements {@link Canonicalizable}. 403 */ 404 public boolean isCanonicalizable() { 405 return isCanonicalizable; 406 } 407 408 /** 409 * Determines if this node type implements {@link BinaryCommutative}. 410 */ 411 public boolean isCommutative() { 412 return isCommutative; 413 } 414 415 /** 416 * Determines if this node type implements {@link Simplifiable}. 417 */ 418 public boolean isSimplifiable() { 419 return isSimplifiable; 420 } 421 422 static int allocatedNodeIterabledIds() { 423 return nextIterableId.get(); 424 } 425 426 public EnumSet<InputType> getAllowedUsageTypes() { 427 return allowedUsageTypes; 428 } 429 430 /** 431 * Describes a field representing an input or successor edge in a node. 432 */ 433 protected static class EdgeInfo extends FieldsScanner.FieldInfo { 434 435 public EdgeInfo(long offset, String name, Class<?> type, Class<?> declaringClass) { 436 super(offset, name, type, declaringClass); 437 } 438 439 /** 440 * Sorts non-list edges before list edges. 441 */ 442 @Override 443 public int compareTo(FieldsScanner.FieldInfo o) { 444 if (NodeList.class.isAssignableFrom(o.type)) { 445 if (!NodeList.class.isAssignableFrom(type)) { 446 return -1; 447 } 448 } else { 449 if (NodeList.class.isAssignableFrom(type)) { 450 return 1; 451 } 452 } 453 return super.compareTo(o); 454 } 455 } 456 457 /** 458 * Describes a field representing an {@linkplain Type#Inputs input} edge in a node. 459 */ 460 protected static class InputInfo extends EdgeInfo { 461 final InputType inputType; 462 final boolean optional; 463 464 public InputInfo(long offset, String name, Class<?> type, Class<?> declaringClass, InputType inputType, boolean optional) { 465 super(offset, name, type, declaringClass); 466 this.inputType = inputType; 467 this.optional = optional; 468 } 469 470 @Override 471 public String toString() { 472 return super.toString() + "{inputType=" + inputType + ", optional=" + optional + "}"; 473 } 474 } 475 476 protected static class NodeFieldsScanner extends FieldsScanner { 477 478 public final ArrayList<InputInfo> inputs = new ArrayList<>(); 479 public final ArrayList<EdgeInfo> successors = new ArrayList<>(); 480 int directInputs; 481 int directSuccessors; 482 final DebugContext debug; 483 484 protected NodeFieldsScanner(FieldsScanner.CalcOffset calc, NodeClass<?> superNodeClass, DebugContext debug) { 485 super(calc); 486 this.debug = debug; 487 if (superNodeClass != null) { 488 translateInto(superNodeClass.inputs, inputs); 489 translateInto(superNodeClass.successors, successors); 490 translateInto(superNodeClass.data, data); 491 directInputs = superNodeClass.inputs.getDirectCount(); 492 directSuccessors = superNodeClass.successors.getDirectCount(); 493 } 494 } 495 496 @SuppressWarnings("try") 497 @Override 498 protected void scanField(Field field, long offset) { 499 Input inputAnnotation = getAnnotationTimed(field, Node.Input.class, debug); 500 OptionalInput optionalInputAnnotation = getAnnotationTimed(field, Node.OptionalInput.class, debug); 501 Successor successorAnnotation = getAnnotationTimed(field, Successor.class, debug); 502 try (DebugCloseable s = Init_FieldScanningInner.start(debug)) { 503 Class<?> type = field.getType(); 504 int modifiers = field.getModifiers(); 505 506 if (inputAnnotation != null || optionalInputAnnotation != null) { 507 assert successorAnnotation == null : "field cannot be both input and successor"; 508 if (INPUT_LIST_CLASS.isAssignableFrom(type)) { 509 // NodeInputList fields should not be final since they are 510 // written (via Unsafe) in clearInputs() 511 GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeInputList input field %s should not be final", field); 512 GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeInputList input field %s should not be public", field); 513 } else { 514 GraalError.guarantee(NODE_CLASS.isAssignableFrom(type) || type.isInterface(), "invalid input type: %s", type); 515 GraalError.guarantee(!Modifier.isFinal(modifiers), "Node input field %s should not be final", field); 516 directInputs++; 517 } 518 InputType inputType; 519 if (inputAnnotation != null) { 520 assert optionalInputAnnotation == null : "inputs can either be optional or non-optional"; 521 inputType = inputAnnotation.value(); 522 } else { 523 inputType = optionalInputAnnotation.value(); 524 } 525 inputs.add(new InputInfo(offset, field.getName(), type, field.getDeclaringClass(), inputType, field.isAnnotationPresent(Node.OptionalInput.class))); 526 } else if (successorAnnotation != null) { 527 if (SUCCESSOR_LIST_CLASS.isAssignableFrom(type)) { 528 // NodeSuccessorList fields should not be final since they are 529 // written (via Unsafe) in clearSuccessors() 530 GraalError.guarantee(!Modifier.isFinal(modifiers), "NodeSuccessorList successor field % should not be final", field); 531 GraalError.guarantee(!Modifier.isPublic(modifiers), "NodeSuccessorList successor field %s should not be public", field); 532 } else { 533 GraalError.guarantee(NODE_CLASS.isAssignableFrom(type), "invalid successor type: %s", type); 534 GraalError.guarantee(!Modifier.isFinal(modifiers), "Node successor field %s should not be final", field); 535 directSuccessors++; 536 } 537 successors.add(new EdgeInfo(offset, field.getName(), type, field.getDeclaringClass())); 538 } else { 539 GraalError.guarantee(!NODE_CLASS.isAssignableFrom(type) || field.getName().equals("Null"), "suspicious node field: %s", field); 540 GraalError.guarantee(!INPUT_LIST_CLASS.isAssignableFrom(type), "suspicious node input list field: %s", field); 541 GraalError.guarantee(!SUCCESSOR_LIST_CLASS.isAssignableFrom(type), "suspicious node successor list field: %s", field); 542 super.scanField(field, offset); 543 } 544 } 545 } 546 } 547 548 @Override 549 public String toString() { 550 StringBuilder str = new StringBuilder(); 551 str.append("NodeClass ").append(getClazz().getSimpleName()).append(" ["); 552 inputs.appendFields(str); 553 str.append("] ["); 554 successors.appendFields(str); 555 str.append("] ["); 556 data.appendFields(str); 557 str.append("]"); 558 return str.toString(); 559 } 560 561 private static int deepHashCode0(Object o) { 562 if (o == null) { 563 return 0; 564 } else if (!o.getClass().isArray()) { 565 return o.hashCode(); 566 } else if (o instanceof Object[]) { 567 return Arrays.deepHashCode((Object[]) o); 568 } else if (o instanceof byte[]) { 569 return Arrays.hashCode((byte[]) o); 570 } else if (o instanceof short[]) { 571 return Arrays.hashCode((short[]) o); 572 } else if (o instanceof int[]) { 573 return Arrays.hashCode((int[]) o); 574 } else if (o instanceof long[]) { 575 return Arrays.hashCode((long[]) o); 576 } else if (o instanceof char[]) { 577 return Arrays.hashCode((char[]) o); 578 } else if (o instanceof float[]) { 579 return Arrays.hashCode((float[]) o); 580 } else if (o instanceof double[]) { 581 return Arrays.hashCode((double[]) o); 582 } else if (o instanceof boolean[]) { 583 return Arrays.hashCode((boolean[]) o); 584 } else { 585 throw shouldNotReachHere(); 586 } 587 } 588 589 public int valueNumber(Node n) { 590 int number = 0; 591 if (canGVN) { 592 number = startGVNNumber; 593 for (int i = 0; i < data.getCount(); ++i) { 594 Class<?> type = data.getType(i); 595 if (type.isPrimitive()) { 596 if (type == Integer.TYPE) { 597 int intValue = data.getInt(n, i); 598 number += intValue; 599 } else if (type == Long.TYPE) { 600 long longValue = data.getLong(n, i); 601 number += longValue ^ (longValue >>> 32); 602 } else if (type == Boolean.TYPE) { 603 boolean booleanValue = data.getBoolean(n, i); 604 if (booleanValue) { 605 number += 7; 606 } 607 } else if (type == Float.TYPE) { 608 float floatValue = data.getFloat(n, i); 609 number += Float.floatToRawIntBits(floatValue); 610 } else if (type == Double.TYPE) { 611 double doubleValue = data.getDouble(n, i); 612 long longValue = Double.doubleToRawLongBits(doubleValue); 613 number += longValue ^ (longValue >>> 32); 614 } else if (type == Short.TYPE) { 615 short shortValue = data.getShort(n, i); 616 number += shortValue; 617 } else if (type == Character.TYPE) { 618 char charValue = data.getChar(n, i); 619 number += charValue; 620 } else if (type == Byte.TYPE) { 621 byte byteValue = data.getByte(n, i); 622 number += byteValue; 623 } else { 624 assert false : "unhandled property type: " + type; 625 } 626 } else { 627 Object o = data.getObject(n, i); 628 number += deepHashCode0(o); 629 } 630 number *= 13; 631 } 632 } 633 return number; 634 } 635 636 private static boolean deepEquals0(Object e1, Object e2) { 637 if (e1 == e2) { 638 return true; 639 } else if (e1 == null || e2 == null) { 640 return false; 641 } else if (!e1.getClass().isArray() || e1.getClass() != e2.getClass()) { 642 return e1.equals(e2); 643 } else if (e1 instanceof Object[] && e2 instanceof Object[]) { 644 return deepEquals((Object[]) e1, (Object[]) e2); 645 } else if (e1 instanceof int[]) { 646 return Arrays.equals((int[]) e1, (int[]) e2); 647 } else if (e1 instanceof long[]) { 648 return Arrays.equals((long[]) e1, (long[]) e2); 649 } else if (e1 instanceof byte[]) { 650 return Arrays.equals((byte[]) e1, (byte[]) e2); 651 } else if (e1 instanceof char[]) { 652 return Arrays.equals((char[]) e1, (char[]) e2); 653 } else if (e1 instanceof short[]) { 654 return Arrays.equals((short[]) e1, (short[]) e2); 655 } else if (e1 instanceof float[]) { 656 return Arrays.equals((float[]) e1, (float[]) e2); 657 } else if (e1 instanceof double[]) { 658 return Arrays.equals((double[]) e1, (double[]) e2); 659 } else if (e1 instanceof boolean[]) { 660 return Arrays.equals((boolean[]) e1, (boolean[]) e2); 661 } else { 662 throw shouldNotReachHere(); 663 } 664 } 665 666 private static boolean deepEquals(Object[] a1, Object[] a2) { 667 int length = a1.length; 668 if (a2.length != length) { 669 return false; 670 } 671 672 for (int i = 0; i < length; i++) { 673 if (!deepEquals0(a1[i], a2[i])) { 674 return false; 675 } 676 } 677 return true; 678 } 679 680 public boolean dataEquals(Node a, Node b) { 681 assert a.getClass() == b.getClass(); 682 for (int i = 0; i < data.getCount(); ++i) { 683 Class<?> type = data.getType(i); 684 if (type.isPrimitive()) { 685 if (type == Integer.TYPE) { 686 int aInt = data.getInt(a, i); 687 int bInt = data.getInt(b, i); 688 if (aInt != bInt) { 689 return false; 690 } 691 } else if (type == Boolean.TYPE) { 692 boolean aBoolean = data.getBoolean(a, i); 693 boolean bBoolean = data.getBoolean(b, i); 694 if (aBoolean != bBoolean) { 695 return false; 696 } 697 } else if (type == Long.TYPE) { 698 long aLong = data.getLong(a, i); 699 long bLong = data.getLong(b, i); 700 if (aLong != bLong) { 701 return false; 702 } 703 } else if (type == Float.TYPE) { 704 float aFloat = data.getFloat(a, i); 705 float bFloat = data.getFloat(b, i); 706 if (aFloat != bFloat) { 707 return false; 708 } 709 } else if (type == Double.TYPE) { 710 double aDouble = data.getDouble(a, i); 711 double bDouble = data.getDouble(b, i); 712 if (aDouble != bDouble) { 713 return false; 714 } 715 } else if (type == Short.TYPE) { 716 short aShort = data.getShort(a, i); 717 short bShort = data.getShort(b, i); 718 if (aShort != bShort) { 719 return false; 720 } 721 } else if (type == Character.TYPE) { 722 char aChar = data.getChar(a, i); 723 char bChar = data.getChar(b, i); 724 if (aChar != bChar) { 725 return false; 726 } 727 } else if (type == Byte.TYPE) { 728 byte aByte = data.getByte(a, i); 729 byte bByte = data.getByte(b, i); 730 if (aByte != bByte) { 731 return false; 732 } 733 } else { 734 assert false : "unhandled type: " + type; 735 } 736 } else { 737 Object objectA = data.getObject(a, i); 738 Object objectB = data.getObject(b, i); 739 if (objectA != objectB) { 740 if (objectA != null && objectB != null) { 741 if (!deepEquals0(objectA, objectB)) { 742 return false; 743 } 744 } else { 745 return false; 746 } 747 } 748 } 749 } 750 return true; 751 } 752 753 public boolean isValid(Position pos, NodeClass<?> from, Edges fromEdges) { 754 if (this == from) { 755 return true; 756 } 757 Edges toEdges = getEdges(fromEdges.type()); 758 if (pos.getIndex() >= toEdges.getCount()) { 759 return false; 760 } 761 if (pos.getIndex() >= fromEdges.getCount()) { 762 return false; 763 } 764 return toEdges.isSame(fromEdges, pos.getIndex()); 765 } 766 767 static void updateEdgesInPlace(Node node, InplaceUpdateClosure duplicationReplacement, Edges edges) { 768 int index = 0; 769 Type curType = edges.type(); 770 int directCount = edges.getDirectCount(); 771 final long[] curOffsets = edges.getOffsets(); 772 while (index < directCount) { 773 Node edge = Edges.getNode(node, curOffsets, index); 774 if (edge != null) { 775 Node newEdge = duplicationReplacement.replacement(edge, curType); 776 if (curType == Edges.Type.Inputs) { 777 node.updateUsages(null, newEdge); 778 } else { 779 node.updatePredecessor(null, newEdge); 780 } 781 edges.initializeNode(node, index, newEdge); 782 } 783 index++; 784 } 785 786 while (index < edges.getCount()) { 787 NodeList<Node> list = Edges.getNodeList(node, curOffsets, index); 788 if (list != null) { 789 edges.initializeList(node, index, updateEdgeListCopy(node, list, duplicationReplacement, curType)); 790 } 791 index++; 792 } 793 } 794 795 void updateInputSuccInPlace(Node node, InplaceUpdateClosure duplicationReplacement) { 796 updateEdgesInPlace(node, duplicationReplacement, inputs); 797 updateEdgesInPlace(node, duplicationReplacement, successors); 798 } 799 800 private static NodeList<Node> updateEdgeListCopy(Node node, NodeList<Node> list, InplaceUpdateClosure duplicationReplacement, Edges.Type type) { 801 NodeList<Node> result = type == Edges.Type.Inputs ? new NodeInputList<>(node, list.size()) : new NodeSuccessorList<>(node, list.size()); 802 803 for (int i = 0; i < list.count(); ++i) { 804 Node oldNode = list.get(i); 805 if (oldNode != null) { 806 Node newNode = duplicationReplacement.replacement(oldNode, type); 807 result.set(i, newNode); 808 } 809 } 810 return result; 811 } 812 813 /** 814 * Gets the input or successor edges defined by this node class. 815 */ 816 public Edges getEdges(Edges.Type type) { 817 return type == Edges.Type.Inputs ? inputs : successors; 818 } 819 820 public Edges getInputEdges() { 821 return inputs; 822 } 823 824 public Edges getSuccessorEdges() { 825 return successors; 826 } 827 828 /** 829 * Returns a newly allocated node for which no subclass-specific constructor has been called. 830 */ 831 @SuppressWarnings("unchecked") 832 public Node allocateInstance() { 833 try { 834 Node node = (Node) UNSAFE.allocateInstance(getJavaClass()); 835 node.init((NodeClass<? extends Node>) this); 836 return node; 837 } catch (InstantiationException ex) { 838 throw shouldNotReachHere(ex); 839 } 840 } 841 842 public Class<T> getJavaClass() { 843 return getClazz(); 844 } 845 846 /** 847 * The template used to build the {@link Verbosity#Name} version. Variable parts are specified 848 * using {i#inputName} or {p#propertyName}. If no 849 * {@link NodeInfo#nameTemplate() template} is specified, it uses {@link NodeInfo#shortName()}. 850 * If none of the two is specified, it returns an empty string. 851 */ 852 public String getNameTemplate() { 853 return nameTemplate; 854 } 855 856 interface InplaceUpdateClosure { 857 858 Node replacement(Node node, Edges.Type type); 859 } 860 861 static EconomicMap<Node, Node> addGraphDuplicate(final Graph graph, final Graph oldGraph, int estimatedNodeCount, Iterable<? extends Node> nodes, final DuplicationReplacement replacements) { 862 final EconomicMap<Node, Node> newNodes; 863 int denseThreshold = oldGraph.getNodeCount() + oldGraph.getNodesDeletedSinceLastCompression() >> 4; 864 if (estimatedNodeCount > denseThreshold) { 865 // Use dense map 866 newNodes = new NodeMap<>(oldGraph); 867 } else { 868 // Use sparse map 869 newNodes = EconomicMap.create(Equivalence.IDENTITY); 870 } 871 createNodeDuplicates(graph, nodes, replacements, newNodes); 872 873 InplaceUpdateClosure replacementClosure = new InplaceUpdateClosure() { 874 875 @Override 876 public Node replacement(Node node, Edges.Type type) { 877 Node target = newNodes.get(node); 878 if (target == null) { 879 Node replacement = node; 880 if (replacements != null) { 881 replacement = replacements.replacement(node); 882 } 883 if (replacement != node) { 884 target = replacement; 885 } else if (node.graph() == graph && type == Edges.Type.Inputs) { 886 // patch to the outer world 887 target = node; 888 } 889 890 } 891 return target; 892 } 893 894 }; 895 896 // re-wire inputs 897 for (Node oldNode : nodes) { 898 Node node = newNodes.get(oldNode); 899 NodeClass<?> nodeClass = node.getNodeClass(); 900 if (replacements == null || replacements.replacement(oldNode) == oldNode) { 901 nodeClass.updateInputSuccInPlace(node, replacementClosure); 902 } else { 903 transferEdgesDifferentNodeClass(graph, replacements, newNodes, oldNode, node); 904 } 905 } 906 907 return newNodes; 908 } 909 910 private static void createNodeDuplicates(final Graph graph, Iterable<? extends Node> nodes, final DuplicationReplacement replacements, final EconomicMap<Node, Node> newNodes) { 911 for (Node node : nodes) { 912 if (node != null) { 913 assert !node.isDeleted() : "trying to duplicate deleted node: " + node; 914 Node replacement = node; 915 if (replacements != null) { 916 replacement = replacements.replacement(node); 917 } 918 if (replacement != node) { 919 assert replacement != null; 920 newNodes.put(node, replacement); 921 } else { 922 Node newNode = node.clone(graph, WithAllEdges); 923 assert newNode.getNodeClass().isLeafNode() || newNode.hasNoUsages(); 924 assert newNode.getClass() == node.getClass(); 925 newNodes.put(node, newNode); 926 } 927 } 928 } 929 } 930 931 private static void transferEdgesDifferentNodeClass(final Graph graph, final DuplicationReplacement replacements, final EconomicMap<Node, Node> newNodes, Node oldNode, Node node) { 932 transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Inputs); 933 transferEdges(graph, replacements, newNodes, oldNode, node, Edges.Type.Successors); 934 } 935 936 private static void transferEdges(final Graph graph, final DuplicationReplacement replacements, final EconomicMap<Node, Node> newNodes, Node oldNode, Node node, Edges.Type type) { 937 NodeClass<?> nodeClass = node.getNodeClass(); 938 NodeClass<?> oldNodeClass = oldNode.getNodeClass(); 939 Edges oldEdges = oldNodeClass.getEdges(type); 940 for (Position pos : oldEdges.getPositionsIterable(oldNode)) { 941 if (!nodeClass.isValid(pos, oldNodeClass, oldEdges)) { 942 continue; 943 } 944 Node oldEdge = pos.get(oldNode); 945 if (oldEdge != null) { 946 Node target = newNodes.get(oldEdge); 947 if (target == null) { 948 Node replacement = oldEdge; 949 if (replacements != null) { 950 replacement = replacements.replacement(oldEdge); 951 } 952 if (replacement != oldEdge) { 953 target = replacement; 954 } else if (type == Edges.Type.Inputs && oldEdge.graph() == graph) { 955 // patch to the outer world 956 target = oldEdge; 957 } 958 } 959 pos.set(node, target); 960 } 961 } 962 } 963 964 /** 965 * @return true if the node has no inputs and no successors 966 */ 967 public boolean isLeafNode() { 968 return isLeafNode; 969 } 970 971 public int getLeafId() { 972 return this.leafId; 973 } 974 975 public NodeClass<? super T> getSuperNodeClass() { 976 return superNodeClass; 977 } 978 979 public long inputsIteration() { 980 return inputsIteration; 981 } 982 983 /** 984 * An iterator that will iterate over edges. 985 * 986 * An iterator of this type will not return null values, unless edges are modified concurrently. 987 * Concurrent modifications are detected by an assertion on a best-effort basis. 988 */ 989 private static class RawEdgesIterator implements Iterator<Node> { 990 protected final Node node; 991 protected long mask; 992 protected Node nextValue; 993 994 RawEdgesIterator(Node node, long mask) { 995 this.node = node; 996 this.mask = mask; 997 } 998 999 @Override 1000 public boolean hasNext() { 1001 Node next = nextValue; 1002 if (next != null) { 1003 return true; 1004 } else { 1005 nextValue = forward(); 1006 return nextValue != null; 1007 } 1008 } 1009 1010 private Node forward() { 1011 while (mask != 0) { 1012 Node next = getInput(); 1013 mask = advanceInput(); 1014 if (next != null) { 1015 return next; 1016 } 1017 } 1018 return null; 1019 } 1020 1021 @Override 1022 public Node next() { 1023 Node next = nextValue; 1024 if (next == null) { 1025 next = forward(); 1026 if (next == null) { 1027 throw new NoSuchElementException(); 1028 } else { 1029 return next; 1030 } 1031 } else { 1032 nextValue = null; 1033 return next; 1034 } 1035 } 1036 1037 public final long advanceInput() { 1038 int state = (int) mask & 0x03; 1039 if (state == 0) { 1040 // Skip normal field. 1041 return mask >>> NEXT_EDGE; 1042 } else if (state == 1) { 1043 // We are iterating a node list. 1044 if ((mask & 0xFFFF00) != 0) { 1045 // Node list count is non-zero, decrease by 1. 1046 return mask - 0x100; 1047 } else { 1048 // Node list is finished => go to next input. 1049 return mask >>> 24; 1050 } 1051 } else { 1052 // Need to expand node list. 1053 NodeList<?> nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC); 1054 if (nodeList != null) { 1055 int size = nodeList.size(); 1056 if (size != 0) { 1057 // Set pointer to upper most index of node list. 1058 return ((mask >>> NEXT_EDGE) << 24) | (mask & 0xFD) | ((size - 1) << NEXT_EDGE); 1059 } 1060 } 1061 // Node list is empty or null => skip. 1062 return mask >>> NEXT_EDGE; 1063 } 1064 } 1065 1066 public Node getInput() { 1067 int state = (int) mask & 0x03; 1068 if (state == 0) { 1069 return Edges.getNodeUnsafe(node, mask & 0xFC); 1070 } else if (state == 1) { 1071 // We are iterating a node list. 1072 NodeList<?> nodeList = Edges.getNodeListUnsafe(node, mask & 0xFC); 1073 return nodeList.nodes[nodeList.size() - 1 - (int) ((mask >>> NEXT_EDGE) & 0xFFFF)]; 1074 } else { 1075 // Node list needs to expand first. 1076 return null; 1077 } 1078 } 1079 1080 @Override 1081 public void remove() { 1082 throw new UnsupportedOperationException(); 1083 } 1084 1085 public Position nextPosition() { 1086 return null; 1087 } 1088 } 1089 1090 private static final class RawEdgesWithModCountIterator extends RawEdgesIterator { 1091 private final int modCount; 1092 1093 private RawEdgesWithModCountIterator(Node node, long mask) { 1094 super(node, mask); 1095 assert isModificationCountsEnabled(); 1096 this.modCount = node.modCount(); 1097 } 1098 1099 @Override 1100 public boolean hasNext() { 1101 try { 1102 return super.hasNext(); 1103 } finally { 1104 assert modCount == node.modCount() : "must not be modified"; 1105 } 1106 } 1107 1108 @Override 1109 public Node next() { 1110 try { 1111 return super.next(); 1112 } finally { 1113 assert modCount == node.modCount() : "must not be modified"; 1114 } 1115 } 1116 1117 @Override 1118 public Position nextPosition() { 1119 try { 1120 return super.nextPosition(); 1121 } finally { 1122 assert modCount == node.modCount(); 1123 } 1124 } 1125 } 1126 1127 public NodeIterable<Node> getSuccessorIterable(final Node node) { 1128 long mask = this.successorIteration; 1129 return new NodeIterable<Node>() { 1130 1131 @Override 1132 public Iterator<Node> iterator() { 1133 if (isModificationCountsEnabled()) { 1134 return new RawEdgesWithModCountIterator(node, mask); 1135 } else { 1136 return new RawEdgesIterator(node, mask); 1137 } 1138 } 1139 1140 @Override 1141 public String toString() { 1142 StringBuilder sb = new StringBuilder(); 1143 Iterator<Node> iterator = iterator(); 1144 boolean first = true; 1145 sb.append("succs="); 1146 sb.append('['); 1147 while (iterator.hasNext()) { 1148 Node input = iterator.next(); 1149 if (!first) { 1150 sb.append(", "); 1151 } 1152 sb.append(input); 1153 first = false; 1154 } 1155 sb.append(']'); 1156 return sb.toString(); 1157 } 1158 }; 1159 } 1160 1161 public NodeIterable<Node> getInputIterable(final Node node) { 1162 long mask = this.inputsIteration; 1163 return new NodeIterable<Node>() { 1164 1165 @Override 1166 public Iterator<Node> iterator() { 1167 if (isModificationCountsEnabled()) { 1168 return new RawEdgesWithModCountIterator(node, mask); 1169 } else { 1170 return new RawEdgesIterator(node, mask); 1171 } 1172 } 1173 1174 @Override 1175 public String toString() { 1176 StringBuilder sb = new StringBuilder(); 1177 Iterator<Node> iterator = iterator(); 1178 boolean first = true; 1179 sb.append("inputs="); 1180 sb.append('['); 1181 while (iterator.hasNext()) { 1182 Node input = iterator.next(); 1183 if (!first) { 1184 sb.append(", "); 1185 } 1186 sb.append(input); 1187 first = false; 1188 } 1189 sb.append(']'); 1190 return sb.toString(); 1191 } 1192 }; 1193 } 1194 1195 public boolean equalSuccessors(Node node, Node other) { 1196 return equalEdges(node, other, successorIteration); 1197 } 1198 1199 public boolean equalInputs(Node node, Node other) { 1200 return equalEdges(node, other, inputsIteration); 1201 } 1202 1203 private boolean equalEdges(Node node, Node other, long mask) { 1204 long myMask = mask; 1205 assert other.getNodeClass() == this; 1206 while (myMask != 0) { 1207 long offset = (myMask & OFFSET_MASK); 1208 if ((myMask & LIST_MASK) == 0) { 1209 Object v1 = Edges.getNodeUnsafe(node, offset); 1210 Object v2 = Edges.getNodeUnsafe(other, offset); 1211 if (v1 != v2) { 1212 return false; 1213 } 1214 } else { 1215 Object v1 = Edges.getNodeListUnsafe(node, offset); 1216 Object v2 = Edges.getNodeListUnsafe(other, offset); 1217 if (!Objects.equals(v1, v2)) { 1218 return false; 1219 } 1220 } 1221 myMask >>>= NEXT_EDGE; 1222 } 1223 return true; 1224 } 1225 1226 public void pushInputs(Node node, NodeStack stack) { 1227 long myMask = this.inputsIteration; 1228 while (myMask != 0) { 1229 long offset = (myMask & OFFSET_MASK); 1230 if ((myMask & LIST_MASK) == 0) { 1231 Node curNode = Edges.getNodeUnsafe(node, offset); 1232 if (curNode != null) { 1233 stack.push(curNode); 1234 } 1235 } else { 1236 pushAllHelper(stack, node, offset); 1237 } 1238 myMask >>>= NEXT_EDGE; 1239 } 1240 } 1241 1242 private static void pushAllHelper(NodeStack stack, Node node, long offset) { 1243 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1244 if (list != null) { 1245 for (int i = 0; i < list.size(); ++i) { 1246 Node curNode = list.get(i); 1247 if (curNode != null) { 1248 stack.push(curNode); 1249 } 1250 } 1251 } 1252 } 1253 1254 public void applySuccessors(Node node, EdgeVisitor consumer) { 1255 applyEdges(node, consumer, this.successorIteration); 1256 } 1257 1258 public void applyInputs(Node node, EdgeVisitor consumer) { 1259 applyEdges(node, consumer, this.inputsIteration); 1260 } 1261 1262 private static void applyEdges(Node node, EdgeVisitor consumer, long mask) { 1263 long myMask = mask; 1264 while (myMask != 0) { 1265 long offset = (myMask & OFFSET_MASK); 1266 if ((myMask & LIST_MASK) == 0) { 1267 Node curNode = Edges.getNodeUnsafe(node, offset); 1268 if (curNode != null) { 1269 Node newNode = consumer.apply(node, curNode); 1270 if (newNode != curNode) { 1271 Edges.putNodeUnsafe(node, offset, newNode); 1272 } 1273 } 1274 } else { 1275 applyHelper(node, consumer, offset); 1276 } 1277 myMask >>>= NEXT_EDGE; 1278 } 1279 } 1280 1281 private static void applyHelper(Node node, EdgeVisitor consumer, long offset) { 1282 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1283 if (list != null) { 1284 for (int i = 0; i < list.size(); ++i) { 1285 Node curNode = list.get(i); 1286 if (curNode != null) { 1287 Node newNode = consumer.apply(node, curNode); 1288 if (newNode != curNode) { 1289 list.initialize(i, newNode); 1290 } 1291 } 1292 } 1293 } 1294 } 1295 1296 public void unregisterAtSuccessorsAsPredecessor(Node node) { 1297 long myMask = this.successorIteration; 1298 while (myMask != 0) { 1299 long offset = (myMask & OFFSET_MASK); 1300 if ((myMask & LIST_MASK) == 0) { 1301 Node curNode = Edges.getNodeUnsafe(node, offset); 1302 if (curNode != null) { 1303 node.updatePredecessor(curNode, null); 1304 Edges.putNodeUnsafe(node, offset, null); 1305 } 1306 } else { 1307 unregisterAtSuccessorsAsPredecessorHelper(node, offset); 1308 } 1309 myMask >>>= NEXT_EDGE; 1310 } 1311 } 1312 1313 private static void unregisterAtSuccessorsAsPredecessorHelper(Node node, long offset) { 1314 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1315 if (list != null) { 1316 for (int i = 0; i < list.size(); ++i) { 1317 Node curNode = list.get(i); 1318 if (curNode != null) { 1319 node.updatePredecessor(curNode, null); 1320 } 1321 } 1322 list.clearWithoutUpdate(); 1323 } 1324 } 1325 1326 public void registerAtSuccessorsAsPredecessor(Node node) { 1327 long myMask = this.successorIteration; 1328 while (myMask != 0) { 1329 long offset = (myMask & OFFSET_MASK); 1330 if ((myMask & LIST_MASK) == 0) { 1331 Node curNode = Edges.getNodeUnsafe(node, offset); 1332 if (curNode != null) { 1333 assert curNode.isAlive() : "Successor not alive"; 1334 node.updatePredecessor(null, curNode); 1335 } 1336 } else { 1337 registerAtSuccessorsAsPredecessorHelper(node, offset); 1338 } 1339 myMask >>>= NEXT_EDGE; 1340 } 1341 } 1342 1343 private static void registerAtSuccessorsAsPredecessorHelper(Node node, long offset) { 1344 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1345 if (list != null) { 1346 for (int i = 0; i < list.size(); ++i) { 1347 Node curNode = list.get(i); 1348 if (curNode != null) { 1349 assert curNode.isAlive() : "Successor not alive"; 1350 node.updatePredecessor(null, curNode); 1351 } 1352 } 1353 } 1354 } 1355 1356 public boolean replaceFirstInput(Node node, Node key, Node replacement) { 1357 return replaceFirstEdge(node, key, replacement, this.inputsIteration); 1358 } 1359 1360 public boolean replaceFirstSuccessor(Node node, Node key, Node replacement) { 1361 return replaceFirstEdge(node, key, replacement, this.successorIteration); 1362 } 1363 1364 public static boolean replaceFirstEdge(Node node, Node key, Node replacement, long mask) { 1365 long myMask = mask; 1366 while (myMask != 0) { 1367 long offset = (myMask & OFFSET_MASK); 1368 if ((myMask & LIST_MASK) == 0) { 1369 Object curNode = Edges.getNodeUnsafe(node, offset); 1370 if (curNode == key) { 1371 Edges.putNodeUnsafe(node, offset, replacement); 1372 return true; 1373 } 1374 } else { 1375 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1376 if (list != null && list.replaceFirst(key, replacement)) { 1377 return true; 1378 } 1379 } 1380 myMask >>>= NEXT_EDGE; 1381 } 1382 return false; 1383 } 1384 1385 public void registerAtInputsAsUsage(Node node) { 1386 long myMask = this.inputsIteration; 1387 while (myMask != 0) { 1388 long offset = (myMask & OFFSET_MASK); 1389 if ((myMask & LIST_MASK) == 0) { 1390 Node curNode = Edges.getNodeUnsafe(node, offset); 1391 if (curNode != null) { 1392 assert curNode.isAlive() : "Input not alive " + curNode; 1393 curNode.addUsage(node); 1394 } 1395 } else { 1396 registerAtInputsAsUsageHelper(node, offset); 1397 } 1398 myMask >>>= NEXT_EDGE; 1399 } 1400 } 1401 1402 private static void registerAtInputsAsUsageHelper(Node node, long offset) { 1403 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1404 if (list != null) { 1405 for (int i = 0; i < list.size(); ++i) { 1406 Node curNode = list.get(i); 1407 if (curNode != null) { 1408 assert curNode.isAlive() : "Input not alive"; 1409 curNode.addUsage(node); 1410 } 1411 } 1412 } 1413 } 1414 1415 public void unregisterAtInputsAsUsage(Node node) { 1416 long myMask = this.inputsIteration; 1417 while (myMask != 0) { 1418 long offset = (myMask & OFFSET_MASK); 1419 if ((myMask & LIST_MASK) == 0) { 1420 Node curNode = Edges.getNodeUnsafe(node, offset); 1421 if (curNode != null) { 1422 node.removeThisFromUsages(curNode); 1423 if (curNode.hasNoUsages()) { 1424 node.maybeNotifyZeroUsages(curNode); 1425 } 1426 Edges.putNodeUnsafe(node, offset, null); 1427 } 1428 } else { 1429 unregisterAtInputsAsUsageHelper(node, offset); 1430 } 1431 myMask >>>= NEXT_EDGE; 1432 } 1433 } 1434 1435 private static void unregisterAtInputsAsUsageHelper(Node node, long offset) { 1436 NodeList<Node> list = Edges.getNodeListUnsafe(node, offset); 1437 if (list != null) { 1438 for (int i = 0; i < list.size(); ++i) { 1439 Node curNode = list.get(i); 1440 if (curNode != null) { 1441 node.removeThisFromUsages(curNode); 1442 if (curNode.hasNoUsages()) { 1443 node.maybeNotifyZeroUsages(curNode); 1444 } 1445 } 1446 } 1447 list.clearWithoutUpdate(); 1448 } 1449 } 1450 }