1 /* 2 * Copyright (c) 2012, 2017, 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.virtual.phases.ea; 26 27 import java.lang.reflect.Field; 28 import java.util.ArrayList; 29 import java.util.Arrays; 30 import java.util.Iterator; 31 32 import org.graalvm.compiler.debug.DebugContext; 33 import org.graalvm.compiler.debug.GraalError; 34 import org.graalvm.compiler.graph.Node; 35 import org.graalvm.compiler.nodes.StructuredGraph; 36 37 /** 38 * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a 39 * previous state by truncating the list. 40 */ 41 public class EffectList implements Iterable<EffectList.Effect> { 42 43 public interface Effect { isVisible()44 default boolean isVisible() { 45 return true; 46 } 47 isCfgKill()48 default boolean isCfgKill() { 49 return false; 50 } 51 apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes)52 void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes); 53 } 54 55 public interface SimpleEffect extends Effect { 56 @Override apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes)57 default void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { 58 apply(graph); 59 } 60 apply(StructuredGraph graph)61 void apply(StructuredGraph graph); 62 } 63 64 private static final Effect[] EMPTY_ARRAY = new Effect[0]; 65 private static final String[] EMPTY_STRING_ARRAY = new String[0]; 66 67 private final DebugContext debug; 68 private Effect[] effects = EMPTY_ARRAY; 69 private String[] names = EMPTY_STRING_ARRAY; 70 private int size; 71 EffectList(DebugContext debug)72 public EffectList(DebugContext debug) { 73 this.debug = debug; 74 } 75 enlarge(int elements)76 private void enlarge(int elements) { 77 int length = effects.length; 78 if (size + elements > length) { 79 while (size + elements > length) { 80 length = Math.max(length * 2, 4); 81 } 82 effects = Arrays.copyOf(effects, length); 83 if (debug.isLogEnabled()) { 84 names = Arrays.copyOf(names, length); 85 } 86 } 87 } 88 add(String name, SimpleEffect effect)89 public void add(String name, SimpleEffect effect) { 90 add(name, (Effect) effect); 91 } 92 add(String name, Effect effect)93 public void add(String name, Effect effect) { 94 assert effect != null; 95 enlarge(1); 96 if (debug.isLogEnabled()) { 97 names[size] = name; 98 } 99 effects[size++] = effect; 100 } 101 addAll(EffectList list)102 public void addAll(EffectList list) { 103 enlarge(list.size); 104 System.arraycopy(list.effects, 0, effects, size, list.size); 105 if (debug.isLogEnabled()) { 106 System.arraycopy(list.names, 0, names, size, list.size); 107 } 108 size += list.size; 109 } 110 insertAll(EffectList list, int position)111 public void insertAll(EffectList list, int position) { 112 assert position >= 0 && position <= size; 113 enlarge(list.size); 114 System.arraycopy(effects, position, effects, position + list.size, size - position); 115 System.arraycopy(list.effects, 0, effects, position, list.size); 116 if (debug.isLogEnabled()) { 117 System.arraycopy(names, position, names, position + list.size, size - position); 118 System.arraycopy(list.names, 0, names, position, list.size); 119 } 120 size += list.size; 121 } 122 checkpoint()123 public int checkpoint() { 124 return size; 125 } 126 size()127 public int size() { 128 return size; 129 } 130 backtrack(int checkpoint)131 public void backtrack(int checkpoint) { 132 assert checkpoint <= size; 133 size = checkpoint; 134 } 135 136 @Override iterator()137 public Iterator<Effect> iterator() { 138 return new Iterator<Effect>() { 139 140 int index; 141 final int listSize = EffectList.this.size; 142 143 @Override 144 public boolean hasNext() { 145 return index < listSize; 146 } 147 148 @Override 149 public Effect next() { 150 return effects[index++]; 151 } 152 153 @Override 154 public void remove() { 155 throw new UnsupportedOperationException(); 156 } 157 }; 158 } 159 get(int index)160 public Effect get(int index) { 161 if (index >= size) { 162 throw new IndexOutOfBoundsException(); 163 } 164 return effects[index]; 165 } 166 clear()167 public void clear() { 168 size = 0; 169 } 170 isEmpty()171 public boolean isEmpty() { 172 return size == 0; 173 } 174 apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes, boolean cfgKills)175 public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes, boolean cfgKills) { 176 boolean message = false; 177 for (int i = 0; i < size(); i++) { 178 Effect effect = effects[i]; 179 if (effect.isCfgKill() == cfgKills) { 180 if (!message) { 181 message = true; 182 debug.log(cfgKills ? " ==== cfg kill effects" : " ==== effects"); 183 } 184 try { 185 effect.apply(graph, obsoleteNodes); 186 } catch (Throwable t) { 187 StringBuilder str = new StringBuilder(); 188 toString(str, i); 189 throw new GraalError(t).addContext("effect", str); 190 } 191 if (effect.isVisible() && debug.isLogEnabled()) { 192 StringBuilder str = new StringBuilder(); 193 toString(str, i); 194 debug.log(" %s", str); 195 } 196 } 197 } 198 } 199 toString(StringBuilder str, int i)200 private void toString(StringBuilder str, int i) { 201 Effect effect = effects[i]; 202 str.append(getName(i)).append(" ["); 203 boolean first = true; 204 for (Field field : effect.getClass().getDeclaredFields()) { 205 try { 206 field.setAccessible(true); 207 Object object = field.get(effect); 208 if (object == this) { 209 // Inner classes could capture the EffectList itself. 210 continue; 211 } 212 str.append(first ? "" : ", ").append(field.getName()).append("=").append(format(object)); 213 first = false; 214 } catch (SecurityException | IllegalAccessException e) { 215 throw new RuntimeException(e); 216 } 217 } 218 str.append(']'); 219 } 220 format(Object object)221 private static String format(Object object) { 222 if (object != null && Object[].class.isAssignableFrom(object.getClass())) { 223 return Arrays.toString((Object[]) object); 224 } 225 return "" + object; 226 } 227 228 @Override toString()229 public String toString() { 230 StringBuilder str = new StringBuilder(); 231 for (int i = 0; i < size(); i++) { 232 Effect effect = get(i); 233 if (effect.isVisible()) { 234 toString(str, i); 235 str.append('\n'); 236 } 237 } 238 return str.toString(); 239 } 240 getName(int i)241 private String getName(int i) { 242 if (debug.isLogEnabled()) { 243 return names[i]; 244 } else { 245 return ""; 246 } 247 } 248 } 249