--- /dev/null 2017-01-22 10:16:57.869617664 -0800 +++ new/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceBuilderResult.java 2017-02-15 16:57:01.653491229 -0800 @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2016, 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.core.common.alloc; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; + +import org.graalvm.compiler.core.common.cfg.AbstractBlockBase; +import org.graalvm.compiler.debug.Debug; +import org.graalvm.compiler.debug.Indent; + +public final class TraceBuilderResult { + + public abstract static class TrivialTracePredicate { + public abstract boolean isTrivialTrace(Trace trace); + } + + private final ArrayList traces; + private final Trace[] blockToTrace; + + static TraceBuilderResult create(AbstractBlockBase[] blocks, ArrayList traces, Trace[] blockToTrace, TrivialTracePredicate pred) { + connect(traces, blockToTrace); + ArrayList newTraces = reorderTraces(traces, pred); + TraceBuilderResult traceBuilderResult = new TraceBuilderResult(newTraces, blockToTrace); + traceBuilderResult.numberTraces(); + assert verify(traceBuilderResult, blocks.length); + return traceBuilderResult; + } + + private TraceBuilderResult(ArrayList traces, Trace[] blockToTrace) { + this.traces = traces; + this.blockToTrace = blockToTrace; + } + + public Trace getTraceForBlock(AbstractBlockBase block) { + return blockToTrace[block.getId()]; + } + + public ArrayList getTraces() { + return traces; + } + + public boolean incomingEdges(Trace trace) { + return incomingEdges(trace.getId(), trace.getBlocks(), 0); + } + + public boolean incomingSideEdges(Trace trace) { + AbstractBlockBase[] traceArr = trace.getBlocks(); + if (traceArr.length <= 0) { + return false; + } + return incomingEdges(trace.getId(), traceArr, 1); + } + + private boolean incomingEdges(int traceNr, AbstractBlockBase[] trace, int index) { + /* TODO (je): not efficient. find better solution. */ + for (int i = index; i < trace.length; i++) { + AbstractBlockBase block = trace[1]; + for (AbstractBlockBase pred : block.getPredecessors()) { + if (getTraceForBlock(pred).getId() != traceNr) { + return true; + } + } + } + return false; + } + + public static boolean verify(TraceBuilderResult traceBuilderResult, int expectedLength) { + ArrayList traces = traceBuilderResult.getTraces(); + assert verifyAllBlocksScheduled(traceBuilderResult, expectedLength) : "Not all blocks assigned to traces!"; + for (int i = 0; i < traces.size(); i++) { + Trace trace = traces.get(i); + assert trace.getId() == i : "Trace number mismatch: " + trace.getId() + " vs. " + i; + + BitSet suxTraces = new BitSet(traces.size()); + for (Trace suxTrace : trace.getSuccessors()) { + assert !suxTraces.get(suxTrace.getId()) : "Trace twice successors " + suxTrace; + suxTraces.set(suxTrace.getId()); + } + + AbstractBlockBase last = null; + int blockNumber = 0; + for (AbstractBlockBase current : trace.getBlocks()) { + AbstractBlockBase block = current; + assert traceBuilderResult.getTraceForBlock(block).getId() == i : "Trace number mismatch for block " + block + ": " + traceBuilderResult.getTraceForBlock(block) + " vs. " + i; + assert last == null || Arrays.asList(current.getPredecessors()).contains(last) : "Last block (" + last + ") not a predecessor of " + current; + assert current.getLinearScanNumber() == blockNumber : "Blocks not numbered correctly: " + current.getLinearScanNumber() + " vs. " + blockNumber; + last = current; + blockNumber++; + for (AbstractBlockBase sux : block.getSuccessors()) { + Trace suxTrace = traceBuilderResult.getTraceForBlock(sux); + assert suxTraces.get(suxTrace.getId()) : "Successor Trace " + suxTrace + " for block " + sux + " not in successor traces of " + trace; + } + } + } + return true; + } + + private static boolean verifyAllBlocksScheduled(TraceBuilderResult traceBuilderResult, int expectedLength) { + ArrayList traces = traceBuilderResult.getTraces(); + BitSet handled = new BitSet(expectedLength); + for (Trace trace : traces) { + for (AbstractBlockBase block : trace.getBlocks()) { + assert !handled.get(block.getId()) : "Block added twice: " + block; + handled.set(block.getId()); + } + } + return handled.cardinality() == expectedLength; + } + + private void numberTraces() { + for (int i = 0; i < traces.size(); i++) { + Trace trace = traces.get(i); + trace.setId(i); + } + } + + private static void connect(ArrayList traces, Trace[] blockToTrace) { + int numTraces = traces.size(); + for (Trace trace : traces) { + BitSet added = new BitSet(numTraces); + ArrayList successors = trace.getSuccessors(); + assert successors.size() == 0 : "Can only connect traces once!"; + + for (AbstractBlockBase block : trace.getBlocks()) { + for (AbstractBlockBase succ : block.getSuccessors()) { + Trace succTrace = blockToTrace[succ.getId()]; + int succId = succTrace.getId(); + if (!added.get(succId)) { + added.set(succId); + successors.add(succTrace); + } + } + } + } + } + + @SuppressWarnings("try") + private static ArrayList reorderTraces(ArrayList oldTraces, TrivialTracePredicate pred) { + if (pred == null) { + return oldTraces; + } + try (Indent indent = Debug.logAndIndent("ReorderTrace")) { + ArrayList newTraces = new ArrayList<>(oldTraces.size()); + for (int oldTraceIdx = 0; oldTraceIdx < oldTraces.size(); oldTraceIdx++) { + Trace currentTrace = oldTraces.get(oldTraceIdx); + if (!alreadyProcessed(newTraces, currentTrace)) { + assert currentTrace.getId() == oldTraceIdx : "Index mismatch"; + // add current trace + addTrace(newTraces, currentTrace); + for (Trace succTrace : currentTrace.getSuccessors()) { + if (pred.isTrivialTrace(succTrace) && !alreadyProcessed(newTraces, succTrace)) { + Debug.log("Moving trivial trace from %d to %d", succTrace.getId(), newTraces.size()); + // add trivial successor trace + addTrace(newTraces, succTrace); + } + } + } + } + assert newTraces.size() == oldTraces.size() : "Lost traces? " + oldTraces.size() + " vs. " + newTraces.size(); + return newTraces; + } + } + + private static boolean alreadyProcessed(ArrayList newTraces, Trace currentTrace) { + int currentTraceId = currentTrace.getId(); + return currentTraceId < newTraces.size() && currentTrace == newTraces.get(currentTraceId); + } + + private static void addTrace(ArrayList newTraces, Trace currentTrace) { + currentTrace.setId(newTraces.size()); + newTraces.add(currentTrace); + } + +}