001/*
002 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.virtual.phases.ea;
024
025import java.lang.reflect.*;
026import java.util.*;
027
028import jdk.internal.jvmci.common.*;
029import com.oracle.graal.debug.*;
030
031import com.oracle.graal.graph.*;
032import com.oracle.graal.nodes.*;
033
034/**
035 * An {@link EffectList} can be used to maintain a list of {@link Effect}s and backtrack to a
036 * previous state by truncating the list.
037 */
038public class EffectList implements Iterable<EffectList.Effect> {
039
040    public interface Effect {
041        default boolean isVisible() {
042            return true;
043        }
044
045        default boolean isCfgKill() {
046            return false;
047        }
048
049        void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes);
050    }
051
052    public interface SimpleEffect extends Effect {
053        default void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) {
054            apply(graph);
055        }
056
057        void apply(StructuredGraph graph);
058    }
059
060    private static final Effect[] EMPTY_ARRAY = new Effect[0];
061    private static final String[] EMPTY_STRING_ARRAY = new String[0];
062
063    private Effect[] effects = EMPTY_ARRAY;
064    private String[] names = EMPTY_STRING_ARRAY;
065    private int size;
066
067    private void enlarge(int elements) {
068        int length = effects.length;
069        if (size + elements > length) {
070            while (size + elements > length) {
071                length = Math.max(length * 2, 4);
072            }
073            effects = Arrays.copyOf(effects, length);
074            if (Debug.isEnabled()) {
075                names = Arrays.copyOf(names, length);
076            }
077        }
078    }
079
080    public void add(String name, SimpleEffect effect) {
081        add(name, (Effect) effect);
082    }
083
084    public void add(String name, Effect effect) {
085        assert effect != null;
086        enlarge(1);
087        if (Debug.isEnabled()) {
088            names[size] = name;
089        }
090        effects[size++] = effect;
091    }
092
093    public void addAll(EffectList list) {
094        enlarge(list.size);
095        System.arraycopy(list.effects, 0, effects, size, list.size);
096        if (Debug.isEnabled()) {
097            System.arraycopy(list.names, 0, names, size, list.size);
098        }
099        size += list.size;
100    }
101
102    public void insertAll(EffectList list, int position) {
103        assert position >= 0 && position <= size;
104        enlarge(list.size);
105        System.arraycopy(effects, position, effects, position + list.size, size - position);
106        System.arraycopy(list.effects, 0, effects, position, list.size);
107        if (Debug.isEnabled()) {
108            System.arraycopy(names, position, names, position + list.size, size - position);
109            System.arraycopy(list.names, 0, names, position, list.size);
110        }
111        size += list.size;
112    }
113
114    public int checkpoint() {
115        return size;
116    }
117
118    public int size() {
119        return size;
120    }
121
122    public void backtrack(int checkpoint) {
123        assert checkpoint <= size;
124        size = checkpoint;
125    }
126
127    @Override
128    public Iterator<Effect> iterator() {
129        return new Iterator<Effect>() {
130
131            int index;
132            final int listSize = EffectList.this.size;
133
134            @Override
135            public boolean hasNext() {
136                return index < listSize;
137            }
138
139            @Override
140            public Effect next() {
141                return effects[index++];
142            }
143
144            @Override
145            public void remove() {
146                throw new UnsupportedOperationException();
147            }
148        };
149    }
150
151    public Effect get(int index) {
152        if (index >= size) {
153            throw new IndexOutOfBoundsException();
154        }
155        return effects[index];
156    }
157
158    public void clear() {
159        size = 0;
160    }
161
162    public boolean isEmpty() {
163        return size == 0;
164    }
165
166    public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes, boolean cfgKills) {
167        for (int i = 0; i < size(); i++) {
168            Effect effect = effects[i];
169            if (effect.isCfgKill() == cfgKills) {
170                try {
171                    effect.apply(graph, obsoleteNodes);
172                } catch (Throwable t) {
173                    StringBuilder str = new StringBuilder();
174                    toString(str, i);
175                    throw new JVMCIError(t).addContext("effect", str);
176                }
177                if (effect.isVisible() && Debug.isLogEnabled()) {
178                    StringBuilder str = new StringBuilder();
179                    toString(str, i);
180                    Debug.log("    %s", str);
181                }
182            }
183        }
184    }
185
186    private void toString(StringBuilder str, int i) {
187        Effect effect = effects[i];
188        str.append(getName(i)).append(" [");
189        boolean first = true;
190        for (Field field : effect.getClass().getDeclaredFields()) {
191            try {
192                field.setAccessible(true);
193                Object object = field.get(effect);
194                if (object == this) {
195                    // Inner classes could capture the EffectList itself.
196                    continue;
197                }
198                str.append(first ? "" : ", ").append(format(object));
199                first = false;
200            } catch (SecurityException | IllegalAccessException e) {
201                throw new RuntimeException(e);
202            }
203        }
204        str.append(']');
205    }
206
207    private static String format(Object object) {
208        if (object != null && Object[].class.isAssignableFrom(object.getClass())) {
209            return Arrays.toString((Object[]) object);
210        }
211        return "" + object;
212    }
213
214    @Override
215    public String toString() {
216        StringBuilder str = new StringBuilder();
217        for (int i = 0; i < size(); i++) {
218            Effect effect = get(i);
219            if (effect.isVisible()) {
220                toString(str, i);
221                str.append('\n');
222            }
223        }
224        return str.toString();
225    }
226
227    private String getName(int i) {
228        if (Debug.isEnabled()) {
229            return names[i];
230        } else {
231            return "";
232        }
233    }
234}