blob: ecaffd08cae54675a7c79a2093ed75e721c41db7 [file] [log] [blame]
/*
* Copyright (c) 2012, 2017, 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.DebugContext;
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<EffectList.Effect> {
public interface Effect {
default boolean isVisible() {
return true;
}
default boolean isCfgKill() {
return false;
}
void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes);
}
public interface SimpleEffect extends Effect {
@Override
default void apply(StructuredGraph graph, ArrayList<Node> 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 final DebugContext debug;
private Effect[] effects = EMPTY_ARRAY;
private String[] names = EMPTY_STRING_ARRAY;
private int size;
public EffectList(DebugContext debug) {
this.debug = debug;
}
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.isLogEnabled()) {
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.isLogEnabled()) {
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.isLogEnabled()) {
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.isLogEnabled()) {
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<Effect> iterator() {
return new Iterator<Effect>() {
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<Node> obsoleteNodes, boolean cfgKills) {
boolean message = false;
for (int i = 0; i < size(); i++) {
Effect effect = effects[i];
if (effect.isCfgKill() == cfgKills) {
if (!message) {
message = true;
debug.log(cfgKills ? " ==== cfg kill effects" : " ==== effects");
}
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(field.getName()).append("=").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.isLogEnabled()) {
return names[i];
} else {
return "";
}
}
}