1/*
2 * Copyright (c) 2005, 2015, 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
24package jdk.test.lib.jittester;
25
26// Production is base class for all elements of the IR-tree.
27import java.util.ArrayList;
28import java.util.Collection;
29import java.util.List;
30import java.util.Objects;
31import jdk.test.lib.jittester.loops.For;
32import jdk.test.lib.jittester.loops.DoWhile;
33import jdk.test.lib.jittester.loops.While;
34import jdk.test.lib.jittester.types.TypeKlass;
35import jdk.test.lib.jittester.visitors.Visitor;
36
37public abstract class IRNode {
38    private IRNode parent;
39    private final List<IRNode> children = new ArrayList<>();
40    protected TypeKlass owner;
41    protected int level;
42    private final Type resultType;
43
44    protected IRNode(Type resultType) {
45        this.resultType = resultType;
46    }
47
48    public Type getResultType() {
49        return resultType;
50    }
51
52    //TODO
53    //private boolean isCFDeviation;
54
55    public abstract <T> T accept(Visitor<T> v);
56
57    public void setOwner(TypeKlass owner) {
58        this.owner = owner;
59        if (Objects.isNull(owner)) {
60            System.out.println(getClass().getName() + " null");
61            for (StackTraceElement s : Thread.currentThread().getStackTrace()) {
62                System.out.println(s.toString());
63            }
64        }
65    }
66
67    public void addChild(IRNode child) {
68        if (Objects.nonNull(child)) {
69            children.add(child);
70            child.parent = this;
71        }
72    }
73
74    public void addChildren(List<? extends IRNode> ch) {
75        if (Objects.nonNull(ch)) {
76            ch.stream()
77                .filter(c -> c != null)
78                .forEach(this::addChild);
79        }
80    }
81
82    public List<IRNode> getChildren() {
83        return children;
84    }
85
86    public IRNode getChild(int i) {
87        return i < children.size() ? children.get(i) : null;
88    }
89
90    public TypeKlass getOwner() {
91        return owner;
92    }
93
94    public IRNode getParent() {
95        return parent;
96    }
97
98    public void setChild(int index, IRNode child) {
99        children.set(index, child);
100        if (Objects.nonNull(child)) {
101            child.parent = this;
102        }
103    }
104
105    public boolean removeChild(IRNode l) {
106        return children.remove(l);
107    }
108
109    public boolean removeSelf() {
110        return parent.children.remove(this);
111    }
112
113    public void resizeUpChildren(int size) {
114        for (int i = children.size(); i < size; ++i) {
115            children.add(null);
116        }
117    }
118
119    public void removeAllChildren() {
120        children.clear();
121    }
122
123    public String getTreeTextView(int indent) {
124        StringBuilder sb = new StringBuilder();
125        if (level > 0) {
126        for (int i = 0; i < indent; ++i) {
127            sb.append("\t");
128        }
129        sb.append(getName())
130                .append(" [")
131                .append(level)
132                .append("]")
133                    .append(System.lineSeparator());
134        }
135        children.stream()
136                .filter(ch -> !Objects.isNull(ch))
137                .forEach(ch -> sb.append(ch.getTreeTextView(indent + 1)));
138        return sb.toString();
139    }
140
141    protected IRNode evolve() {
142        throw new Error("Not implemented");
143    }
144
145    public int getLevel() {
146        return level;
147    }
148
149    public long complexity() {
150        return 0L;
151    }
152
153    @Override
154    public final String toString() {
155        return getName();
156    }
157
158    public String getName() {
159        return this.getClass().getName();
160    }
161
162    public static long countDepth(Collection<IRNode> input) {
163        return input.stream()
164                .filter(Objects::nonNull)
165                .mapToLong(IRNode::countDepth)
166                .max().orElse(0L);
167    }
168
169    public long countDepth() {
170        return IRNode.countDepth(children);
171    }
172
173    public List<IRNode> getStackableLeaves() {
174        List<IRNode> result = new ArrayList<>();
175        children.stream()
176                .filter(Objects::nonNull)
177                .forEach(c -> {
178                    if (countDepth() == c.level && (c instanceof Block)) {
179                        result.add(c);
180                    } else {
181                        result.addAll(c.getStackableLeaves());
182                    }
183                });
184        return result;
185    }
186
187    public List<IRNode> getDeviantBlocks(long depth) {
188        List<IRNode> result = new ArrayList<>();
189        children.stream()
190                .filter(c -> !Objects.isNull(c))
191                .forEach(c -> {
192            if (depth == c.level && c.isCFDeviation()) {
193                        result.add(c);
194                    } else {
195                        result.addAll(c.getDeviantBlocks(depth));
196                    }
197                });
198        return result;
199    }
200
201    public static long getModifiableNodesCount(List<IRNode> nodes) {
202        return nodes.stream()
203                .map(IRNode::getStackableLeaves)
204                .mapToInt(List::size)
205                .filter(i -> i > 0)
206                .count();
207    }
208
209    public static boolean tryToReduceNodesDepth(List<IRNode> nodes, int maxDepth) {
210        boolean allSucceed = true;
211        for (IRNode child : nodes) {
212            for (IRNode leaf : child.getDeviantBlocks(Math.max(child.countDepth(), maxDepth + 1))) {
213                if (child.countDepth() > maxDepth) {
214                    // doesn't remove control deviation block. Just some parts.
215                    leaf.removeSelf();
216                    boolean successfull = child.countDepth() > maxDepth;
217                    allSucceed &= successfull;
218                } else {
219                    break;
220                }
221            }
222        }
223        return allSucceed;
224    }
225
226    // TODO: add field instead this function
227    public boolean isCFDeviation() {
228        return this instanceof If || this instanceof Switch
229            || this instanceof For || this instanceof While
230            || this instanceof DoWhile
231            || (this instanceof Block && this.parent instanceof Block);
232    }
233}
234