--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java 2016-12-09 00:57:24.218246556 -0800 @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.virtual.phases.ea; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; + +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.StructuredGraph; + +/** + * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a + * previous state by truncating the list. + */ +public class EffectList implements Iterable { + + public interface Effect { + default boolean isVisible() { + return true; + } + + default boolean isCfgKill() { + return false; + } + + void apply(StructuredGraph graph, ArrayList obsoleteNodes); + } + + public interface SimpleEffect extends Effect { + @Override + default void apply(StructuredGraph graph, ArrayList obsoleteNodes) { + apply(graph); + } + + void apply(StructuredGraph graph); + } + + private static final Effect[] EMPTY_ARRAY = new Effect[0]; + private static final String[] EMPTY_STRING_ARRAY = new String[0]; + + private Effect[] effects = EMPTY_ARRAY; + private String[] names = EMPTY_STRING_ARRAY; + private int size; + + private void enlarge(int elements) { + int length = effects.length; + if (size + elements > length) { + while (size + elements > length) { + length = Math.max(length * 2, 4); + } + effects = Arrays.copyOf(effects, length); + if (Debug.isEnabled()) { + names = Arrays.copyOf(names, length); + } + } + } + + public void add(String name, SimpleEffect effect) { + add(name, (Effect) effect); + } + + public void add(String name, Effect effect) { + assert effect != null; + enlarge(1); + if (Debug.isEnabled()) { + names[size] = name; + } + effects[size++] = effect; + } + + public void addAll(EffectList list) { + enlarge(list.size); + System.arraycopy(list.effects, 0, effects, size, list.size); + if (Debug.isEnabled()) { + System.arraycopy(list.names, 0, names, size, list.size); + } + size += list.size; + } + + public void insertAll(EffectList list, int position) { + assert position >= 0 && position <= size; + enlarge(list.size); + System.arraycopy(effects, position, effects, position + list.size, size - position); + System.arraycopy(list.effects, 0, effects, position, list.size); + if (Debug.isEnabled()) { + System.arraycopy(names, position, names, position + list.size, size - position); + System.arraycopy(list.names, 0, names, position, list.size); + } + size += list.size; + } + + public int checkpoint() { + return size; + } + + public int size() { + return size; + } + + public void backtrack(int checkpoint) { + assert checkpoint <= size; + size = checkpoint; + } + + @Override + public Iterator iterator() { + return new Iterator() { + + int index; + final int listSize = EffectList.this.size; + + @Override + public boolean hasNext() { + return index < listSize; + } + + @Override + public Effect next() { + return effects[index++]; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + public Effect get(int index) { + if (index >= size) { + throw new IndexOutOfBoundsException(); + } + return effects[index]; + } + + public void clear() { + size = 0; + } + + public boolean isEmpty() { + return size == 0; + } + + public void apply(StructuredGraph graph, ArrayList obsoleteNodes, boolean cfgKills) { + for (int i = 0; i < size(); i++) { + Effect effect = effects[i]; + if (effect.isCfgKill() == cfgKills) { + try { + effect.apply(graph, obsoleteNodes); + } catch (Throwable t) { + StringBuilder str = new StringBuilder(); + toString(str, i); + throw new GraalError(t).addContext("effect", str); + } + if (effect.isVisible() && Debug.isLogEnabled()) { + StringBuilder str = new StringBuilder(); + toString(str, i); + Debug.log(" %s", str); + } + } + } + } + + private void toString(StringBuilder str, int i) { + Effect effect = effects[i]; + str.append(getName(i)).append(" ["); + boolean first = true; + for (Field field : effect.getClass().getDeclaredFields()) { + try { + field.setAccessible(true); + Object object = field.get(effect); + if (object == this) { + // Inner classes could capture the EffectList itself. + continue; + } + str.append(first ? "" : ", ").append(format(object)); + first = false; + } catch (SecurityException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + str.append(']'); + } + + private static String format(Object object) { + if (object != null && Object[].class.isAssignableFrom(object.getClass())) { + return Arrays.toString((Object[]) object); + } + return "" + object; + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + for (int i = 0; i < size(); i++) { + Effect effect = get(i); + if (effect.isVisible()) { + toString(str, i); + str.append('\n'); + } + } + return str.toString(); + } + + private String getName(int i) { + if (Debug.isEnabled()) { + return names[i]; + } else { + return ""; + } + } +}