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