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