/* * 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 ""; } } }