blob: c532d0cd3f88f2e98a5585e25ca81613cda93808 [file] [log] [blame]
/*
* Copyright (c) 2005, 2015, 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 jdk.test.lib.jittester;
// Production is base class for all elements of the IR-tree.
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import jdk.test.lib.jittester.loops.For;
import jdk.test.lib.jittester.loops.DoWhile;
import jdk.test.lib.jittester.loops.While;
import jdk.test.lib.jittester.types.TypeKlass;
import jdk.test.lib.jittester.visitors.Visitor;
public abstract class IRNode {
private IRNode parent;
private final List<IRNode> children = new ArrayList<>();
protected TypeKlass owner;
protected int level;
private final Type resultType;
protected IRNode(Type resultType) {
this.resultType = resultType;
}
public Type getResultType() {
return resultType;
}
//TODO
//private boolean isCFDeviation;
public abstract <T> T accept(Visitor<T> v);
public void setOwner(TypeKlass owner) {
this.owner = owner;
if (Objects.isNull(owner)) {
System.out.println(getClass().getName() + " null");
for (StackTraceElement s : Thread.currentThread().getStackTrace()) {
System.out.println(s.toString());
}
}
}
public void addChild(IRNode child) {
if (Objects.nonNull(child)) {
children.add(child);
child.parent = this;
}
}
public void addChildren(List<? extends IRNode> ch) {
if (Objects.nonNull(ch)) {
ch.stream()
.filter(c -> c != null)
.forEach(this::addChild);
}
}
public List<IRNode> getChildren() {
return children;
}
public IRNode getChild(int i) {
return i < children.size() ? children.get(i) : null;
}
public TypeKlass getOwner() {
return owner;
}
public IRNode getParent() {
return parent;
}
public void setChild(int index, IRNode child) {
children.set(index, child);
if (Objects.nonNull(child)) {
child.parent = this;
}
}
public boolean removeChild(IRNode l) {
return children.remove(l);
}
public boolean removeSelf() {
return parent.children.remove(this);
}
public void resizeUpChildren(int size) {
for (int i = children.size(); i < size; ++i) {
children.add(null);
}
}
public void removeAllChildren() {
children.clear();
}
public String getTreeTextView(int indent) {
StringBuilder sb = new StringBuilder();
if (level > 0) {
for (int i = 0; i < indent; ++i) {
sb.append("\t");
}
sb.append(getName())
.append(" [")
.append(level)
.append("]")
.append(System.lineSeparator());
}
children.stream()
.filter(ch -> !Objects.isNull(ch))
.forEach(ch -> sb.append(ch.getTreeTextView(indent + 1)));
return sb.toString();
}
protected IRNode evolve() {
throw new Error("Not implemented");
}
public int getLevel() {
return level;
}
public long complexity() {
return 0L;
}
@Override
public final String toString() {
return getName();
}
public String getName() {
return this.getClass().getName();
}
public static long countDepth(Collection<IRNode> input) {
return input.stream()
.filter(Objects::nonNull)
.mapToLong(IRNode::countDepth)
.max().orElse(0L);
}
public long countDepth() {
return IRNode.countDepth(children);
}
public List<IRNode> getStackableLeaves() {
List<IRNode> result = new ArrayList<>();
children.stream()
.filter(Objects::nonNull)
.forEach(c -> {
if (countDepth() == c.level && (c instanceof Block)) {
result.add(c);
} else {
result.addAll(c.getStackableLeaves());
}
});
return result;
}
public List<IRNode> getDeviantBlocks(long depth) {
List<IRNode> result = new ArrayList<>();
children.stream()
.filter(c -> !Objects.isNull(c))
.forEach(c -> {
if (depth == c.level && c.isCFDeviation()) {
result.add(c);
} else {
result.addAll(c.getDeviantBlocks(depth));
}
});
return result;
}
public static long getModifiableNodesCount(List<IRNode> nodes) {
return nodes.stream()
.map(IRNode::getStackableLeaves)
.mapToInt(List::size)
.filter(i -> i > 0)
.count();
}
public static boolean tryToReduceNodesDepth(List<IRNode> nodes, int maxDepth) {
boolean allSucceed = true;
for (IRNode child : nodes) {
for (IRNode leaf : child.getDeviantBlocks(Math.max(child.countDepth(), maxDepth + 1))) {
if (child.countDepth() > maxDepth) {
// doesn't remove control deviation block. Just some parts.
leaf.removeSelf();
boolean successfull = child.countDepth() > maxDepth;
allSucceed &= successfull;
} else {
break;
}
}
}
return allSucceed;
}
// TODO: add field instead this function
public boolean isCFDeviation() {
return this instanceof If || this instanceof Switch
|| this instanceof For || this instanceof While
|| this instanceof DoWhile
|| (this instanceof Block && this.parent instanceof Block);
}
}