1 /* 2 * Copyright (c) 2011, 2020, 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 java.util.AbstractList; 28 import java.util.Arrays; 29 import java.util.Collection; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.RandomAccess; 33 34 import org.graalvm.compiler.core.common.PermanentBailoutException; 35 import org.graalvm.compiler.graph.iterators.NodeIterable; 36 37 public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess { 38 39 /** 40 * This constant limits the maximum number of entries in a node list. The reason for the 41 * limitations is the constraints of the code iterating over a node's inputs and successors. It 42 * uses a bit data structure where only 16 bits are available for the current index into the 43 * list. See the methods {@link NodeClass#getSuccessorIterable(Node)} and 44 * {@link NodeClass#getInputIterable(Node)}. 45 */ 46 private static final int MAX_ENTRIES = 65536; 47 48 protected static final Node[] EMPTY_NODE_ARRAY = new Node[0]; 49 50 protected final Node self; 51 protected Node[] nodes; 52 private int size; 53 protected final int initialSize; 54 NodeList(Node self)55 protected NodeList(Node self) { 56 this.self = self; 57 this.nodes = EMPTY_NODE_ARRAY; 58 this.initialSize = 0; 59 } 60 NodeList(Node self, int initialSize)61 protected NodeList(Node self, int initialSize) { 62 this.self = self; 63 checkMaxSize(initialSize); 64 this.size = initialSize; 65 this.initialSize = initialSize; 66 this.nodes = new Node[initialSize]; 67 } 68 NodeList(Node self, T[] elements)69 protected NodeList(Node self, T[] elements) { 70 this.self = self; 71 if (elements == null || elements.length == 0) { 72 this.size = 0; 73 this.nodes = EMPTY_NODE_ARRAY; 74 this.initialSize = 0; 75 } else { 76 checkMaxSize(elements.length); 77 this.size = elements.length; 78 this.initialSize = this.size; 79 this.nodes = new Node[elements.length]; 80 for (int i = 0; i < elements.length; i++) { 81 this.nodes[i] = elements[i]; 82 assert this.nodes[i] == null || !this.nodes[i].isDeleted() : "Initializing nodelist with deleted element : " + nodes[i]; 83 } 84 } 85 } 86 NodeList(Node self, List<? extends T> elements)87 protected NodeList(Node self, List<? extends T> elements) { 88 this.self = self; 89 if (elements == null || elements.isEmpty()) { 90 this.size = 0; 91 this.nodes = EMPTY_NODE_ARRAY; 92 this.initialSize = 0; 93 } else { 94 int newSize = elements.size(); 95 checkMaxSize(newSize); 96 this.size = newSize; 97 this.initialSize = newSize; 98 this.nodes = new Node[elements.size()]; 99 for (int i = 0; i < elements.size(); i++) { 100 this.nodes[i] = elements.get(i); 101 assert this.nodes[i] == null || !this.nodes[i].isDeleted(); 102 } 103 } 104 } 105 checkMaxSize(int value)106 private static void checkMaxSize(int value) { 107 if (value > MAX_ENTRIES) { 108 throw new PermanentBailoutException("Number of elements in a node list too high: %d", value); 109 } 110 } 111 NodeList(Node self, Collection<? extends NodeInterface> elements)112 protected NodeList(Node self, Collection<? extends NodeInterface> elements) { 113 this.self = self; 114 if (elements == null || elements.isEmpty()) { 115 this.size = 0; 116 this.nodes = EMPTY_NODE_ARRAY; 117 this.initialSize = 0; 118 } else { 119 int newSize = elements.size(); 120 checkMaxSize(newSize); 121 this.size = newSize; 122 this.initialSize = newSize; 123 this.nodes = new Node[elements.size()]; 124 int i = 0; 125 for (NodeInterface n : elements) { 126 this.nodes[i] = n.asNode(); 127 assert this.nodes[i] == null || !this.nodes[i].isDeleted(); 128 i++; 129 } 130 } 131 } 132 133 /** 134 * Removes {@code null} values from the list. 135 */ trim()136 public void trim() { 137 int newSize = 0; 138 for (int i = 0; i < nodes.length; ++i) { 139 if (nodes[i] != null) { 140 nodes[newSize] = nodes[i]; 141 newSize++; 142 } 143 } 144 size = newSize; 145 } 146 update(T oldNode, T newNode)147 protected abstract void update(T oldNode, T newNode); 148 getEdgesType()149 public abstract Edges.Type getEdgesType(); 150 151 @Override size()152 public final int size() { 153 return size; 154 } 155 156 @Override isEmpty()157 public final boolean isEmpty() { 158 return size == 0; 159 } 160 161 @Override isNotEmpty()162 public boolean isNotEmpty() { 163 return size > 0; 164 } 165 166 @Override count()167 public int count() { 168 return size; 169 } 170 incModCount()171 protected final void incModCount() { 172 modCount++; 173 } 174 175 /** 176 * Adds a new node to the list. The total number of nodes in the list must not exceed 177 * {@link #MAX_ENTRIES}, otherwise a {@link PermanentBailoutException} is thrown. 178 */ 179 @SuppressWarnings("unchecked") 180 @Override add(Node node)181 public boolean add(Node node) { 182 assert node == null || !node.isDeleted() : node; 183 checkMaxSize(size + 1); 184 self.incModCount(); 185 incModCount(); 186 int length = nodes.length; 187 if (length == 0) { 188 nodes = new Node[2]; 189 } else if (size == length) { 190 Node[] newNodes = new Node[nodes.length * 2 + 1]; 191 System.arraycopy(nodes, 0, newNodes, 0, length); 192 nodes = newNodes; 193 } 194 nodes[size++] = node; 195 update(null, (T) node); 196 return true; 197 } 198 199 /** 200 * Get a node from the list given an {@code index}. 201 */ 202 @Override 203 @SuppressWarnings("unchecked") get(int index)204 public T get(int index) { 205 assert assertInRange(index); 206 return (T) nodes[index]; 207 } 208 assertInRange(int index)209 private boolean assertInRange(int index) { 210 assert index >= 0 && index < size() : index + " < " + size(); 211 return true; 212 } 213 214 public T last() { 215 return get(size() - 1); 216 } 217 218 /** 219 * Set the node of the list at the given {@code index} to a new value. 220 */ 221 @Override 222 @SuppressWarnings("unchecked") 223 public T set(int index, Node node) { 224 incModCount(); 225 T oldValue = (T) nodes[index]; 226 assert assertInRange(index); 227 update((T) nodes[index], (T) node); 228 nodes[index] = node; 229 return oldValue; 230 } 231 232 public void initialize(int index, Node node) { 233 incModCount(); 234 assert index < size(); 235 nodes[index] = node; 236 } 237 238 void copy(NodeList<? extends Node> other) { 239 self.incModCount(); 240 incModCount(); 241 Node[] newNodes = new Node[other.size]; 242 System.arraycopy(other.nodes, 0, newNodes, 0, newNodes.length); 243 nodes = newNodes; 244 size = other.size; 245 } 246 247 @Override 248 public boolean equals(Object other) { 249 if (other == this) { 250 return true; 251 } 252 if (other instanceof List<?>) { 253 List<?> otherList = (List<?>) other; 254 if (size != otherList.size()) { 255 return false; 256 } 257 for (int i = 0; i < size; i++) { 258 if (nodes[i] != otherList.get(i)) { 259 return false; 260 } 261 } 262 return true; 263 } 264 return false; 265 } 266 267 @SuppressWarnings("unchecked") 268 @Override 269 public void clear() { 270 self.incModCount(); 271 incModCount(); 272 for (int i = 0; i < size; i++) { 273 update((T) nodes[i], null); 274 } 275 clearWithoutUpdate(); 276 } 277 278 void clearWithoutUpdate() { 279 nodes = EMPTY_NODE_ARRAY; 280 size = 0; 281 } 282 283 @Override 284 @SuppressWarnings("unchecked") 285 public boolean remove(Object node) { 286 self.incModCount(); 287 int i = 0; 288 incModCount(); 289 while (i < size && nodes[i] != node) { 290 i++; 291 } 292 if (i < size) { 293 T oldValue = (T) nodes[i]; 294 i++; 295 while (i < size) { 296 nodes[i - 1] = nodes[i]; 297 i++; 298 } 299 nodes[--size] = null; 300 update(oldValue, null); 301 return true; 302 } else { 303 return false; 304 } 305 } 306 307 @Override 308 @SuppressWarnings("unchecked") 309 public T remove(int index) { 310 self.incModCount(); 311 T oldValue = (T) nodes[index]; 312 int i = index + 1; 313 incModCount(); 314 while (i < size) { 315 nodes[i - 1] = nodes[i]; 316 i++; 317 } 318 nodes[--size] = null; 319 update(oldValue, null); 320 return oldValue; 321 } 322 323 boolean replaceFirst(Node node, Node other) { 324 for (int i = 0; i < size; i++) { 325 if (nodes[i] == node) { 326 nodes[i] = other; 327 return true; 328 } 329 } 330 return false; 331 } 332 333 @Override 334 public Iterator<T> iterator() { 335 return new NodeListIterator<>(this, 0); 336 } 337 338 @Override 339 public boolean contains(T other) { 340 for (int i = 0; i < size; i++) { 341 if (nodes[i] == other) { 342 return true; 343 } 344 } 345 return false; 346 } 347 348 @SuppressWarnings("unchecked") 349 @Override 350 public List<T> snapshot() { 351 return (List<T>) Arrays.asList(Arrays.copyOf(this.nodes, this.size)); 352 } 353 354 @Override 355 public void snapshotTo(Collection<? super T> to) { 356 for (int i = 0; i < size; i++) { 357 to.add(get(i)); 358 } 359 } 360 361 @SuppressWarnings("unchecked") 362 public void setAll(NodeList<T> values) { 363 self.incModCount(); 364 incModCount(); 365 for (int i = 0; i < size(); i++) { 366 update((T) nodes[i], null); 367 } 368 nodes = Arrays.copyOf(values.nodes, values.size()); 369 size = values.size(); 370 371 for (int i = 0; i < size(); i++) { 372 update(null, (T) nodes[i]); 373 } 374 } 375 376 @Override 377 @SuppressWarnings("unchecked") 378 public <A> A[] toArray(A[] a) { 379 if (a.length >= size) { 380 System.arraycopy(nodes, 0, a, 0, size); 381 return a; 382 } 383 return (A[]) Arrays.copyOf(nodes, size, a.getClass()); 384 } 385 386 @Override 387 public Object[] toArray() { 388 return Arrays.copyOf(nodes, size); 389 } 390 391 protected void replace(T node, T other) { 392 incModCount(); 393 for (int i = 0; i < size(); i++) { 394 if (nodes[i] == node) { 395 nodes[i] = other; 396 update(node, other); 397 } 398 } 399 } 400 401 @Override 402 public int indexOf(Object node) { 403 for (int i = 0; i < size; i++) { 404 if (nodes[i] == node) { 405 return i; 406 } 407 } 408 return -1; 409 } 410 411 @Override 412 public boolean contains(Object o) { 413 return indexOf(o) != -1; 414 } 415 416 @Override 417 public boolean containsAll(Collection<?> c) { 418 throw new UnsupportedOperationException("not implemented"); 419 } 420 421 @Override 422 public boolean addAll(Collection<? extends T> c) { 423 for (T e : c) { 424 add(e); 425 } 426 return true; 427 } 428 429 public boolean addAll(T[] c) { 430 for (T e : c) { 431 add(e); 432 } 433 return true; 434 } 435 436 @Override 437 public String toString() { 438 StringBuilder sb = new StringBuilder(); 439 sb.append('['); 440 for (int i = 0; i < size; i++) { 441 if (i != 0) { 442 sb.append(", "); 443 } 444 sb.append(nodes[i]); 445 } 446 sb.append(']'); 447 return sb.toString(); 448 } 449 450 @Override 451 public T first() { 452 if (size() > 0) { 453 return get(0); 454 } 455 return null; 456 } 457 458 public SubList<T> subList(int startIndex) { 459 assert assertInRange(startIndex); 460 return new SubList<>(this, startIndex); 461 } 462 463 public static final class SubList<R extends Node> extends AbstractList<R> implements NodeIterable<R>, RandomAccess { 464 private final NodeList<R> list; 465 private final int offset; 466 467 private SubList(NodeList<R> list, int offset) { 468 this.list = list; 469 this.offset = offset; 470 } 471 472 @Override 473 public R get(int index) { 474 assert index >= 0 : index; 475 return list.get(offset + index); 476 } 477 478 @Override 479 public int size() { 480 return list.size() - offset; 481 } 482 483 public SubList<R> subList(int startIndex) { 484 assert startIndex >= 0 && startIndex < size() : startIndex; 485 return new SubList<>(this.list, startIndex + offset); 486 } 487 488 @Override 489 public Iterator<R> iterator() { 490 return new NodeListIterator<>(list, offset); 491 } 492 } 493 494 private static final class NodeListIterator<R extends Node> implements Iterator<R> { 495 private final NodeList<R> list; 496 private final int expectedModCount; 497 private int index; 498 499 private NodeListIterator(NodeList<R> list, int startIndex) { 500 this.list = list; 501 this.expectedModCount = list.modCount; 502 this.index = startIndex; 503 } 504 505 @Override 506 public boolean hasNext() { 507 assert expectedModCount == list.modCount; 508 return index < list.size; 509 } 510 511 @SuppressWarnings("unchecked") 512 @Override 513 public R next() { 514 assert expectedModCount == list.modCount; 515 return (R) list.nodes[index++]; 516 } 517 518 @Override 519 public void remove() { 520 throw new UnsupportedOperationException(); 521 } 522 } 523 } 524