# HG changeset patch
# User Thomas Wuerthinger
# Date 1399146395 -7200
# Node ID ff5cacf47b68317e23b495eda21b1f3f6fed11eb
# Parent 5ecbed00da232caa1add3b89e9a909986badbb71# Parent d370d87e528fe6fe31ddb53249eb0409dd670e0a
Merge.
diff -r 5ecbed00da23 -r ff5cacf47b68 CHANGELOG.md
--- a/CHANGELOG.md Fri May 02 02:45:26 2014 +0200
+++ b/CHANGELOG.md Sat May 03 21:46:35 2014 +0200
@@ -12,13 +12,14 @@
* ...
### Truffle
-* The method CallTarget#call takes now a variable number of Object arguments.
+* The method `CallTarget#call` takes now a variable number of Object arguments.
* Support for collecting stack traces and for accessing the current frame in slow paths.
-* Renamed CallNode to DirectCallNode.
-* Renamed TruffleRuntime#createCallNode to TruffleRuntime#createDirectCallNode.
-* Added IndirectCallNode for calls with a changing CallTarget.
-* Added TruffleRuntime#createIndirectCallNode to create an IndirectCallNode.
-* DirectCallNode#inline was renamed to DirectCallNode#forceInlining().
+* Renamed `CallNode` to `DirectCallNode`.
+* Renamed `TruffleRuntime#createCallNode` to `TruffleRuntime#createDirectCallNode`.
+* Added `IndirectCallNode` for calls with a changing `CallTarget`.
+* Added `TruffleRuntime#createIndirectCallNode` to create an `IndirectCallNode`.
+* `DirectCallNode#inline` was renamed to `DirectCallNode#forceInlining()`.
+* Removed deprecated `Node#adoptChild`.
* ...
## Version 0.2
@@ -45,7 +46,7 @@
* New API to declare the cost of a Node for use in runtime environment specific heuristics. See `NodeCost`, `Node#getCost` and `NodeInfo#cost`.
* Removed old API for `NodeInfo#Kind` and `NodeInfo#kind`. As a replacement the new `NodeCost` API can be used.
* Changed `Node#replace` reason parameter type to `CharSequence` (to enable lazy string building)
-* Deprecated `Node#adoptChild` and `Node#adoptChild`, no longer needed in node constructor
+* Deprecated `Node#adoptChild` and `Node#adoptChildren`, no longer needed in node constructor
* New `Node#insert` method for inserting new nodes into the tree (formerly `adoptChild`)
* New `Node#adoptChildren` helper method that adopts all (direct and indirect) children of a node
* New API `Node#atomic` for atomic tree operations
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java
--- a/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.alloc/src/com/oracle/graal/alloc/ComputeBlockOrder.java Sat May 03 21:46:35 2014 +0200
@@ -26,7 +26,6 @@
import java.util.*;
import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.nodes.cfg.*;
/**
* Computes an ordering of the block that can be used by the linear scan register allocator and the
@@ -67,11 +66,11 @@
*
* @return sorted list of blocks
*/
- public static > List computeLinearScanOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) {
+ public static > List computeLinearScanOrder(int blockCount, T startBlock) {
List order = new ArrayList<>();
BitSet visitedBlocks = new BitSet(blockCount);
- PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
- computeLinearScanOrder(order, worklist, visitedBlocks, blockProbabilities);
+ PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks);
+ computeLinearScanOrder(order, worklist, visitedBlocks);
assert checkOrder(order, blockCount);
return order;
}
@@ -81,11 +80,11 @@
*
* @return sorted list of blocks
*/
- public static > List computeCodeEmittingOrder(int blockCount, T startBlock, BlocksToDoubles blockProbabilities) {
+ public static > List computeCodeEmittingOrder(int blockCount, T startBlock) {
List order = new ArrayList<>();
BitSet visitedBlocks = new BitSet(blockCount);
- PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks, blockProbabilities);
- computeCodeEmittingOrder(order, worklist, visitedBlocks, blockProbabilities);
+ PriorityQueue worklist = initializeWorklist(startBlock, visitedBlocks);
+ computeCodeEmittingOrder(order, worklist, visitedBlocks);
assert checkOrder(order, blockCount);
return order;
}
@@ -93,28 +92,28 @@
/**
* Iteratively adds paths to the code emission block order.
*/
- private static > void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+ private static > void computeCodeEmittingOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) {
while (!worklist.isEmpty()) {
T nextImportantPath = worklist.poll();
- addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
+ addPathToCodeEmittingOrder(nextImportantPath, order, worklist, visitedBlocks);
}
}
/**
* Iteratively adds paths to the linear scan block order.
*/
- private static > void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+ private static > void computeLinearScanOrder(List order, PriorityQueue worklist, BitSet visitedBlocks) {
while (!worklist.isEmpty()) {
T nextImportantPath = worklist.poll();
- addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks, blockProbabilities);
+ addPathToLinearScanOrder(nextImportantPath, order, worklist, visitedBlocks);
}
}
/**
* Initializes the priority queue used for the work list of blocks and adds the start block.
*/
- private static > PriorityQueue initializeWorklist(T startBlock, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
- PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator(blockProbabilities));
+ private static > PriorityQueue initializeWorklist(T startBlock, BitSet visitedBlocks) {
+ PriorityQueue result = new PriorityQueue<>(INITIAL_WORKLIST_CAPACITY, new BlockOrderComparator<>());
result.add(startBlock);
visitedBlocks.set(startBlock.getId());
return result;
@@ -123,10 +122,10 @@
/**
* Add a linear path to the linear scan order greedily following the most likely successor.
*/
- private static > void addPathToLinearScanOrder(T block, List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+ private static > void addPathToLinearScanOrder(T block, List order, PriorityQueue worklist, BitSet visitedBlocks) {
block.setLinearScanNumber(order.size());
order.add(block);
- T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
+ T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
enqueueSuccessors(block, worklist, visitedBlocks);
if (mostLikelySuccessor != null) {
if (!mostLikelySuccessor.isLoopHeader() && mostLikelySuccessor.getPredecessorCount() > 1) {
@@ -135,24 +134,24 @@
double unscheduledSum = 0.0;
for (T pred : mostLikelySuccessor.getPredecessors()) {
if (pred.getLinearScanNumber() == -1) {
- unscheduledSum += blockProbabilities.get(pred);
+ unscheduledSum += pred.probability();
}
}
- if (unscheduledSum > blockProbabilities.get(block) / PENALTY_VERSUS_UNSCHEDULED) {
+ if (unscheduledSum > block.probability() / PENALTY_VERSUS_UNSCHEDULED) {
// Add this merge only after at least one additional predecessor gets scheduled.
visitedBlocks.clear(mostLikelySuccessor.getId());
return;
}
}
- addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks, blockProbabilities);
+ addPathToLinearScanOrder(mostLikelySuccessor, order, worklist, visitedBlocks);
}
}
/**
* Add a linear path to the code emission order greedily following the most likely successor.
*/
- private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+ private static > void addPathToCodeEmittingOrder(T initialBlock, List order, PriorityQueue worklist, BitSet visitedBlocks) {
T block = initialBlock;
while (block != null) {
// Skip loop headers if there is only a single loop end block to
@@ -183,7 +182,7 @@
}
}
- T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks, blockProbabilities);
+ T mostLikelySuccessor = findAndMarkMostLikelySuccessor(block, visitedBlocks);
enqueueSuccessors(block, worklist, visitedBlocks);
block = mostLikelySuccessor;
}
@@ -200,11 +199,11 @@
/**
* Find the highest likely unvisited successor block of a given block.
*/
- private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks, BlocksToDoubles blockProbabilities) {
+ private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) {
T result = null;
for (T successor : block.getSuccessors()) {
- assert blockProbabilities.get(successor) >= 0.0 : "Probabilities must be positive";
- if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || blockProbabilities.get(successor) >= blockProbabilities.get(result))) {
+ assert successor.probability() >= 0.0 : "Probabilities must be positive";
+ if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) {
result = successor;
}
}
@@ -247,12 +246,6 @@
*/
private static class BlockOrderComparator> implements Comparator {
- private final BlocksToDoubles probabilities;
-
- public BlockOrderComparator(BlocksToDoubles probabilities) {
- this.probabilities = probabilities;
- }
-
@Override
public int compare(T a, T b) {
// Loop blocks before any loop exit block.
@@ -262,7 +255,7 @@
}
// Blocks with high probability before blocks with low probability.
- if (probabilities.get(a) > probabilities.get(b)) {
+ if (a.probability() > b.probability()) {
return -1;
} else {
return 1;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodHandleAccessProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.replacements/src/com/oracle/graal/api/replacements/MethodHandleAccessProvider.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2014, 2014, 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 com.oracle.graal.api.replacements;
+
+import java.lang.invoke.*;
+
+import com.oracle.graal.api.meta.*;
+
+/**
+ * Interface to access the internals of the {@link MethodHandle} implementation of the VM. An
+ * implementation of this interface is usually required to access non-public classes, methods, and
+ * fields of {@link MethodHandle}, i.e., data that is not standardized by the Java specification.
+ */
+public interface MethodHandleAccessProvider {
+
+ /**
+ * Identification for methods defined on the class {@link MethodHandle} that are processed by
+ * the {@link MethodHandleAccessProvider}.
+ */
+ public enum IntrinsicMethod {
+ /** The method {@code MethodHandle.invokeBasic}. */
+ INVOKE_BASIC,
+ /** The method {@code MethodHandle.linkToStatic}. */
+ LINK_TO_STATIC,
+ /** The method {@code MethodHandle.linkToSpecial}. */
+ LINK_TO_SPECIAL,
+ /** The method {@code MethodHandle.linkToVirtual}. */
+ LINK_TO_VIRTUAL,
+ /** The method {@code MethodHandle.linkToInterface}. */
+ LINK_TO_INTERFACE
+ }
+
+ /**
+ * Returns the method handle method intrinsic identifier for the provided method, or
+ * {@code null} if the method is not an intrinsic processed by this interface.
+ */
+ IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method);
+
+ /**
+ * Resolves the invocation target for an invocation of {@link IntrinsicMethod#INVOKE_BASIC
+ * MethodHandle.invokeBasic} with the given constant receiver {@link MethodHandle}. Returns
+ * {@code null} if the invocation target is not available at this time.
+ *
+ * The first invocations of a method handle can use an interpreter to lookup the actual invoked
+ * method; frequently executed method handles can use Java bytecode generation to avoid the
+ * interpreter overhead. If the parameter forceBytecodeGeneration is set to true, the VM should
+ * try to generate bytecodes before this method returns.
+ */
+ ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration);
+
+ /**
+ * Resolves the invocation target for an invocation of a {@code MethodHandle.linkTo*} method
+ * with the given constant member name. The member name is the last parameter of the
+ * {@code linkTo*} method. Returns {@code null} if the invocation target is not available at
+ * this time.
+ */
+ ResolvedJavaMethod resolveLinkToTarget(Constant memberName);
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java
--- a/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.asm.hsail/src/com/oracle/graal/asm/hsail/HSAILAssembler.java Sat May 03 21:46:35 2014 +0200
@@ -190,16 +190,9 @@
emitString("st_spill_" + getArgTypeFromKind(kind) + " " + HSAIL.mapRegister(src) + ", " + mapStackSlot(dest, getArgSizeFromKind(kind)) + ";");
}
- /**
- * The mapping to stack slots is always relative to the beginning of the spillseg.
- * HSAIL.getStackOffset returns the positive version of the originally negative offset. Then we
- * back up from that by the argSize in bytes. This ensures that slots of different size do not
- * overlap, even though we have converted from negative to positive offsets.
- */
public static String mapStackSlot(Value reg, int argSize) {
- long offset = HSAIL.getStackOffset(reg);
- int argSizeBytes = argSize / 8;
- return "[%spillseg]" + "[" + (offset - argSizeBytes) + "]";
+ long startOffset = HSAIL.getStackOffsetStart(reg, argSize);
+ return "[%spillseg]" + "[" + startOffset + "]";
}
public void cbr(String target1) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java
--- a/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.baseline/src/com/oracle/graal/baseline/BaselineBytecodeParser.java Sat May 03 21:46:35 2014 +0200
@@ -45,7 +45,6 @@
import com.oracle.graal.lir.*;
import com.oracle.graal.lir.StandardOp.BlockEndOp;
import com.oracle.graal.lir.gen.*;
-import com.oracle.graal.nodes.cfg.*;
import com.oracle.graal.phases.*;
public class BaselineBytecodeParser extends AbstractBytecodeParser implements BytecodeParserTool {
@@ -123,14 +122,9 @@
// create the control flow graph
BaselineControlFlowGraph cfg = new BaselineControlFlowGraph(blockMap);
- BlocksToDoubles blockProbabilities = new BlocksToDoubles(blockMap.blocks.size());
- for (BciBlock b : blockMap.blocks) {
- blockProbabilities.put(b, 1);
- }
-
// create the LIR
- List extends AbstractBlock>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities);
- List extends AbstractBlock>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.blocks.size(), blockMap.startBlock, blockProbabilities);
+ List extends AbstractBlock>> linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blockMap.blocks.size(), blockMap.startBlock);
+ List extends AbstractBlock>> codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blockMap.blocks.size(), blockMap.startBlock);
LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder);
FrameMap frameMap = backend.newFrameMap(null);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/cfg/AbstractBlock.java Sat May 03 21:46:35 2014 +0200
@@ -55,4 +55,6 @@
void setAlign(boolean align);
T getDominator();
+
+ double probability();
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/ForceDeoptSubstitutions.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/ForceDeoptSubstitutions.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.compiler.hsail.test.infra;
+
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.api.meta.*;
+
+@ClassSubstitution(GraalKernelTester.class)
+class ForceDeoptSubstitutions {
+
+ /**
+ * Allows us to force a non-exception throwing deopt from java code.
+ */
+ @MethodSubstitution
+ public static int forceDeopt(int x) {
+ DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+ // will never get here but keep the compiler happy
+ return x * x;
+ }
+
+ @MethodSubstitution
+ public static double forceDeopt(double x) {
+ DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+ // will never get here but keep the compiler happy
+ return x * x;
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java
--- a/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test.infra/src/com/oracle/graal/compiler/hsail/test/infra/GraalKernelTester.java Sat May 03 21:46:35 2014 +0200
@@ -50,8 +50,18 @@
public abstract class GraalKernelTester extends KernelTester {
+ private static boolean substitutionsInstalled;
+
+ private static synchronized void installSubstitutions() {
+ if (!substitutionsInstalled) {
+ getHSAILBackend().getProviders().getReplacements().registerSubstitutions(ForceDeoptSubstitutions.class);
+ substitutionsInstalled = true;
+ }
+ }
+
public GraalKernelTester() {
super(getHSAILBackend().isDeviceInitialized());
+ installSubstitutions();
}
protected static HSAILHotSpotBackend getHSAILBackend() {
@@ -193,4 +203,14 @@
super.testGeneratedHsailUsingLambdaMethod();
}
}
+
+ // used for forcing a deoptimization
+ public static int forceDeopt(int x) {
+ return x * x;
+ }
+
+ public static double forceDeopt(double x) {
+ return x * x;
+ }
+
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/DVec3.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/DVec3.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+/**
+ * A simple 3 element Vector object used in some junit tests.
+ */
+public class DVec3 {
+
+ public DVec3(double x, double y, double z) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ }
+
+ public double x;
+ public double y;
+ public double z;
+
+ public static DVec3 add(DVec3 a, DVec3 b) {
+ return new DVec3(a.x + b.x, a.y + b.y, a.z + b.z);
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof DVec3)) {
+ return false;
+ }
+ DVec3 oth = (DVec3) other;
+ return (oth.x == x && oth.y == y && oth.z == z);
+ }
+
+ @Override
+ public String toString() {
+ return ("DVec3[" + x + ", " + y + ", " + z + "]");
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (x + y + z);
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptBase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptBase.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Base class for testing deopt when objects are in stack slots.
+ */
+public abstract class ObjSpillDeoptBase extends GraalKernelTester {
+
+ abstract int getSize();
+
+ int loopcount = 5;
+ int objcount = 20;
+ @Result double[] out = new double[getSize()];
+ @Result double[] aux = new double[getSize()];
+ DVec3[] in = new DVec3[objcount];
+
+ public void doCompute(int gid, boolean causeDeopt) {
+ int idx = gid * 2 + 7;
+ DVec3 v0 = in[(idx++) % objcount];
+ DVec3 v1 = in[(idx++) % objcount];
+ DVec3 v2 = in[(idx++) % objcount];
+ DVec3 v3 = in[(idx++) % objcount];
+ DVec3 v4 = in[(idx++) % objcount];
+ DVec3 v5 = in[(idx++) % objcount];
+ DVec3 v6 = in[(idx++) % objcount];
+ DVec3 v7 = in[(idx++) % objcount];
+ DVec3 v8 = in[(idx++) % objcount];
+ DVec3 v9 = in[(idx++) % objcount];
+ idx += gid;
+ DVec3 v10 = in[(idx++) % objcount];
+ DVec3 v11 = in[(idx++) % objcount];
+ DVec3 v12 = in[(idx++) % objcount];
+ DVec3 v13 = in[(idx++) % objcount];
+ DVec3 v14 = in[(idx++) % objcount];
+ DVec3 v15 = in[(idx++) % objcount];
+ DVec3 v16 = in[(idx++) % objcount];
+ DVec3 v17 = in[(idx++) % objcount];
+ DVec3 v18 = in[(idx++) % objcount];
+ DVec3 v19 = in[(idx++) % objcount];
+ double sum = 0.0;
+ double sum1 = 0.0;
+ double sum2 = 0.0;
+ for (int i = 0; i < loopcount; i++) {
+ sum1 += v0.x + v1.y + v2.z + v3.x + v4.y + v5.z + v6.x + v7.y + v8.z + v9.x + i;
+ sum2 += v10.y + v11.z + v12.x + v13.y + v14.z + v15.x + v16.y + v17.z + v18.x + v19.y - i;
+ sum += sum1 - sum2 + i;
+ aux[gid] += sum1 + 1.2345;
+ }
+ if (causeDeopt) {
+ aux[gid] += forceDeopt(sum1);
+ }
+ out[gid] += sum;
+ }
+
+ @Override
+ public void runTest() {
+ Arrays.fill(out, -1.0);
+ for (int i = 0; i < objcount; i++) {
+ in[i] = new DVec3(i / 10f, (i + 1) / 10f, (i + 2) / 10f);
+ }
+ dispatchMethodKernel(getSize());
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany20000Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany20000Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany20000Test extends ObjSpillDeoptManyBase {
+
+ @Override
+ int getSize() {
+ return 20000;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany5000Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany5000Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany5000Test extends ObjSpillDeoptManyBase {
+
+ @Override
+ int getSize() {
+ return 5000;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany99999Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMany99999Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with many items deopting.
+ */
+public class ObjSpillDeoptMany99999Test extends ObjSpillDeoptManyBase {
+
+ @Override
+ int getSize() {
+ return 99999;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptManyBase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptManyBase.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+/**
+ * Base class for testing deopt with objects in stack slots, with many items deopting.
+ */
+public abstract class ObjSpillDeoptManyBase extends ObjSpillDeoptBase {
+
+ public void run(int gid) {
+ boolean causeDeopt = (gid < 4096 && gid % 512 == 1);
+ doCompute(gid, causeDeopt);
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost20000Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost20000Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost20000Test extends ObjSpillDeoptMostBase {
+
+ @Override
+ int getSize() {
+ return 20000;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost5000Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost5000Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost5000Test extends ObjSpillDeoptMostBase {
+
+ @Override
+ int getSize() {
+ return 5000;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost99999Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMost99999Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, with most items deopting.
+ */
+public class ObjSpillDeoptMost99999Test extends ObjSpillDeoptMostBase {
+
+ @Override
+ int getSize() {
+ return 99999;
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMostBase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptMostBase.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+/**
+ * Base class for testing deopt with objects in stack slots.
+ */
+public abstract class ObjSpillDeoptMostBase extends ObjSpillDeoptBase {
+
+ public void run(int gid) {
+ boolean causeDeopt = (gid % 500 != 1);
+ doCompute(gid, causeDeopt);
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptSingle100Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptSingle100Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, one item deopting.
+ */
+public class ObjSpillDeoptSingle100Test extends ObjSpillDeoptBase {
+
+ final int size = 100;
+
+ @Override
+ int getSize() {
+ return size;
+ }
+
+ public void run(int gid) {
+ boolean causeDeopt = (gid == size / 2);
+ doCompute(gid, causeDeopt);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptSingle20000Test.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/ObjSpillDeoptSingle20000Test.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import org.junit.*;
+
+/**
+ * Tests deopt with objects in stack slots, one item deopting.
+ */
+public class ObjSpillDeoptSingle20000Test extends ObjSpillDeoptBase {
+
+ final int size = 20000;
+
+ @Override
+ int getSize() {
+ return size;
+ }
+
+ public void run(int gid) {
+ boolean causeDeopt = (gid == size / 2);
+ doCompute(gid, causeDeopt);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillBoundsCatchOneTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillBoundsCatchOneTest.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests the spilling of double variables into memory with deopt
+ */
+public class StaticDoubleSpillBoundsCatchOneTest extends GraalKernelTester {
+
+ static final int size = 100;
+ private double[] in = new double[size * 400];
+ @Result public double[] out = new double[size * 400];
+ @Result public double[] aux = new double[2];
+
+ public static void run(double[] out, double[] in, double[] aux, int gid) {
+ int id = gid;
+ int step = 20;
+ double sum0;
+ double sum1;
+ double sum2;
+ double sum3;
+ double sum4;
+ double sum5;
+ double sum6;
+ double sum7;
+ double sum8;
+ double sum9;
+ double sum10;
+ double sum11;
+ double sum12;
+ double sum13;
+ double sum14;
+ double sum15;
+ double sum16;
+ double sum17;
+ double sum18;
+ double sum19;
+ sum0 = sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = sum7 = sum8 = sum9 = 0;
+ sum10 = sum11 = sum12 = sum13 = sum14 = sum15 = sum16 = sum17 = sum18 = sum19 = 0;
+ try {
+ for (int i = 0; i < size; i += step) {
+ sum0 += in[i + 0];
+ sum1 += in[i + 1];
+ sum2 += in[i + 2];
+ sum3 += in[i + 3];
+ sum4 += in[i + 4];
+ sum5 += in[i + 5];
+ sum6 += in[i + 6];
+ sum7 += in[i + 7];
+ sum8 += in[i + 8];
+ sum9 += in[i + 9];
+ sum10 += in[i + 0];
+ sum11 += in[i + 1];
+ sum12 += in[i + 2];
+ sum13 += in[i + 3];
+ sum14 += in[i + 4];
+ sum15 += in[i + 5];
+ sum16 += in[i + 6];
+ sum17 += in[i + 7];
+ sum18 += in[i + 8];
+ sum19 += in[i + 9];
+
+ if (id == size / 2) {
+ aux[id] = sum1 + sum2 + sum3 + sum4 + sum5 + sum6 + sum7 + sum8 + sum9 + sum10 + sum11 + sum12 + sum13 + sum14 + sum15 + sum16;
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ aux[0] += sum1 + sum2;
+ }
+
+ out[id * step + 0] = sum0;
+ out[id * step + 1] = sum1;
+ out[id * step + 2] = sum2;
+ out[id * step + 3] = sum3;
+ out[id * step + 4] = sum4;
+ out[id * step + 5] = sum5;
+ out[id * step + 6] = sum6;
+ out[id * step + 7] = sum7;
+ out[id * step + 8] = sum8;
+ out[id * step + 9] = sum9;
+ out[id * step + 10] = sum10;
+ out[id * step + 11] = sum11;
+ out[id * step + 12] = sum12;
+ out[id * step + 13] = sum13;
+ out[id * step + 14] = sum14;
+ out[id * step + 15] = sum15;
+ out[id * step + 16] = sum16;
+ out[id * step + 17] = sum17;
+ out[id * step + 18] = sum18;
+ out[id * step + 19] = sum19;
+ }
+
+ @Override
+ public void runTest() {
+ /**
+ * Call it for a range, specifying testmethod args (but not the fields it uses or the gid
+ * argument).
+ *
+ */
+ Arrays.fill(out, -1f);
+ for (int i = 0; i < size; i++) {
+ in[i] = i + 1;
+ }
+ dispatchMethodKernel(size, out, in, aux);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillBoundsCatchTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillBoundsCatchTest.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2009, 2012, 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 com.oracle.graal.compiler.hsail.test;
+
+import java.util.*;
+
+import org.junit.*;
+
+import com.oracle.graal.compiler.hsail.test.infra.*;
+
+/**
+ * Tests the spilling of double variables into memory with deopt
+ */
+public class StaticDoubleSpillBoundsCatchTest extends GraalKernelTester {
+
+ static final int size = 100;
+ private double[] in = new double[size * 400];
+ @Result public double[] out = new double[size * 400];
+ @Result public double[] aux = new double[size];
+
+ public static void run(double[] out, double[] in, double[] aux, int gid) {
+ int id = gid;
+ int step = 20;
+ double sum0;
+ double sum1;
+ double sum2;
+ double sum3;
+ double sum4;
+ double sum5;
+ double sum6;
+ double sum7;
+ double sum8;
+ double sum9;
+ double sum10;
+ double sum11;
+ double sum12;
+ double sum13;
+ double sum14;
+ double sum15;
+ double sum16;
+ double sum17;
+ double sum18;
+ double sum19;
+ sum0 = sum1 = sum2 = sum3 = sum4 = sum5 = sum6 = sum7 = sum8 = sum9 = 0;
+ sum10 = sum11 = sum12 = sum13 = sum14 = sum15 = sum16 = sum17 = sum18 = sum19 = 0;
+ try {
+ for (int i = 0; i < size; i += step) {
+ sum0 += in[i + 0];
+ sum1 += in[i + 1];
+ sum2 += in[i + 2];
+ sum3 += in[i + 3];
+ sum4 += in[i + 4];
+ sum5 += in[i + 5];
+ sum6 += in[i + 6];
+ sum7 += in[i + 7];
+ sum8 += in[i + 8];
+ sum9 += in[i + 9];
+ sum10 += in[i + 0];
+ sum11 += in[i + 1];
+ sum12 += in[i + 2];
+ sum13 += in[i + 3];
+ sum14 += in[i + 4];
+ sum15 += in[i + 5];
+ sum16 += in[i + 6];
+ sum17 += in[i + 7];
+ sum18 += in[i + 8];
+ sum19 += in[i + 9];
+
+ if (id > size / 2) {
+ aux[id + 10] += sum1 + sum2;
+ // + sum3 + sum4 + sum5 + sum6 + sum7 + sum8 + sum9 + sum10 + sum11 + sum12 +
+ // sum13 + sum14 + sum15 + sum16;
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ aux[id] += sum1 + sum2;
+ }
+
+ out[id * step + 0] = sum0;
+ out[id * step + 1] = sum1;
+ out[id * step + 2] = sum2;
+ out[id * step + 3] = sum3;
+ out[id * step + 4] = sum4;
+ out[id * step + 5] = sum5;
+ out[id * step + 6] = sum6;
+ out[id * step + 7] = sum7;
+ out[id * step + 8] = sum8;
+ out[id * step + 9] = sum9;
+ out[id * step + 10] = sum10;
+ out[id * step + 11] = sum11;
+ out[id * step + 12] = sum12;
+ out[id * step + 13] = sum13;
+ out[id * step + 14] = sum14;
+ out[id * step + 15] = sum15;
+ out[id * step + 16] = sum16;
+ out[id * step + 17] = sum17;
+ out[id * step + 18] = sum18;
+ out[id * step + 19] = sum19;
+ }
+
+ @Override
+ public void runTest() {
+ /**
+ * Call it for a range, specifying testmethod args (but not the fields it uses or the gid
+ * argument).
+ *
+ */
+ Arrays.fill(out, -1f);
+ Arrays.fill(aux, 0f);
+ for (int i = 0; i < size; i++) {
+ in[i] = i + 1;
+ }
+ dispatchMethodKernel(size, out, in, aux);
+ }
+
+ @Test
+ public void test() {
+ testGeneratedHsail();
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticDoubleSpillTest.java Sat May 03 21:46:35 2014 +0200
@@ -113,13 +113,14 @@
* argument).
*
*/
- Arrays.fill(out, 0f);
- Arrays.fill(in, 0f);
+ Arrays.fill(out, -1f);
+ for (int i = 0; i < size; i++) {
+ in[i] = i + 1;
+ }
dispatchMethodKernel(size, out, in);
}
@Test
- @Ignore("until stack slots are supported in deopt")
public void test() {
testGeneratedHsail();
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/StaticIntSpillTest.java Sat May 03 21:46:35 2014 +0200
@@ -88,7 +88,6 @@
}
@Test
- @Ignore("until stack slots are supported in deopt")
public void test() {
testGeneratedHsail();
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java
--- a/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail.test/src/com/oracle/graal/compiler/hsail/test/lambda/ArrayListGetTest.java Sat May 03 21:46:35 2014 +0200
@@ -25,12 +25,12 @@
import static com.oracle.graal.debug.Debug.*;
-import com.oracle.graal.compiler.hsail.test.infra.GraalKernelTester;
-import com.oracle.graal.debug.*;
+import java.util.*;
-import org.junit.Test;
+import org.junit.*;
-import java.util.ArrayList;
+import com.oracle.graal.compiler.hsail.test.infra.*;
+import com.oracle.graal.debug.*;
/**
* Tests calling ArrayList.get().
@@ -60,6 +60,7 @@
// NYI emitForeignCall charAlignedDisjointArraycopy
@Test(expected = com.oracle.graal.compiler.common.GraalInternalError.class)
+ @Ignore
public void testUsingLambdaMethod() {
try (DebugConfigScope s = disableIntercept()) {
testGeneratedHsailUsingLambdaMethod();
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java
--- a/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.hsail/src/com/oracle/graal/compiler/hsail/HSAILLIRGenerator.java Sat May 03 21:46:35 2014 +0200
@@ -37,20 +37,10 @@
import com.oracle.graal.lir.StandardOp.JumpOp;
import com.oracle.graal.lir.gen.*;
import com.oracle.graal.lir.hsail.*;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.ConvertOp;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Stack;
+import com.oracle.graal.lir.hsail.HSAILArithmetic.Op1Reg;
import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Reg;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.Op2Stack;
-import com.oracle.graal.lir.hsail.HSAILArithmetic.ShiftOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.CompareBranchOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.CondMoveOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.FloatCondMoveOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.ReturnOp;
-import com.oracle.graal.lir.hsail.HSAILControlFlow.StrategySwitchOp;
-import com.oracle.graal.lir.hsail.HSAILMove.LeaOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MembarOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MoveFromRegOp;
-import com.oracle.graal.lir.hsail.HSAILMove.MoveToRegOp;
+import com.oracle.graal.lir.hsail.HSAILControlFlow.*;
+import com.oracle.graal.lir.hsail.HSAILMove.*;
import com.oracle.graal.phases.util.*;
/**
@@ -262,16 +252,16 @@
case Int:
// Note: The Int case also handles the negation of shorts, bytes, and chars because
// Java treats these types as ints at the bytecode level.
- append(new Op1Stack(INEG, result, input));
+ append(new Op1Reg(INEG, result, input));
break;
case Long:
- append(new Op1Stack(LNEG, result, input));
+ append(new Op1Reg(LNEG, result, input));
break;
case Double:
- append(new Op1Stack(DNEG, result, input));
+ append(new Op1Reg(DNEG, result, input));
break;
case Float:
- append(new Op1Stack(FNEG, result, input));
+ append(new Op1Reg(FNEG, result, input));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -293,10 +283,10 @@
case Int:
// Note: The Int case also covers other primitive integral types smaller than an int
// (char, byte, short) because Java treats these types as ints.
- append(new Op1Stack(INOT, result, input));
+ append(new Op1Reg(INOT, result, input));
break;
case Long:
- append(new Op1Stack(LNOT, result, input));
+ append(new Op1Reg(LNOT, result, input));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -309,16 +299,16 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(IADD, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(LADD, result, a, loadNonConst(b)));
break;
case Float:
- append(new Op2Stack(FADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(FADD, result, a, loadNonConst(b)));
break;
case Double:
- append(new Op2Stack(DADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(DADD, result, a, loadNonConst(b)));
break;
case Object:
throw GraalInternalError.shouldNotReachHere();
@@ -334,19 +324,19 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(IADD, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(LADD, result, a, loadNonConst(b)));
break;
case Float:
- append(new Op2Stack(FADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(FADD, result, a, loadNonConst(b)));
break;
case Double:
- append(new Op2Stack(DADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(DADD, result, a, loadNonConst(b)));
break;
case Object:
- append(new Op2Stack(OADD, result, a, loadNonConst(b)));
+ append(new Op2Reg(OADD, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -359,16 +349,16 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(ISUB, result, a, loadNonConst(b)));
+ append(new Op2Reg(ISUB, result, a, loadNonConst(b)));
break;
case Float:
- append(new Op2Stack(FSUB, result, a, loadNonConst(b)));
+ append(new Op2Reg(FSUB, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LSUB, result, a, loadNonConst(b)));
+ append(new Op2Reg(LSUB, result, a, loadNonConst(b)));
break;
case Double:
- append(new Op2Stack(DSUB, result, a, loadNonConst(b)));
+ append(new Op2Reg(DSUB, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -418,16 +408,16 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IDIV, result, a, loadNonConst(b)));
+ append(new Op2Reg(IDIV, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LDIV, result, a, loadNonConst(b)));
+ append(new Op2Reg(LDIV, result, a, loadNonConst(b)));
break;
case Float:
- append(new Op2Stack(FDIV, result, a, loadNonConst(b)));
+ append(new Op2Reg(FDIV, result, a, loadNonConst(b)));
break;
case Double:
- append(new Op2Stack(DDIV, result, a, loadNonConst(b)));
+ append(new Op2Reg(DDIV, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -441,16 +431,16 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IREM, result, a, loadNonConst(b)));
+ append(new Op2Reg(IREM, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LREM, result, a, loadNonConst(b)));
+ append(new Op2Reg(LREM, result, a, loadNonConst(b)));
break;
case Float:
- append(new Op2Stack(FREM, result, a, loadNonConst(b)));
+ append(new Op2Reg(FREM, result, a, loadNonConst(b)));
break;
case Double:
- append(new Op2Stack(DREM, result, a, loadNonConst(b)));
+ append(new Op2Reg(DREM, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -473,10 +463,10 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IAND, result, a, loadNonConst(b)));
+ append(new Op2Reg(IAND, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LAND, result, a, loadNonConst(b)));
+ append(new Op2Reg(LAND, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -489,10 +479,10 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IOR, result, a, loadNonConst(b)));
+ append(new Op2Reg(IOR, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LOR, result, a, loadNonConst(b)));
+ append(new Op2Reg(LOR, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -505,10 +495,10 @@
Variable result = newVariable(a.getKind());
switch (a.getKind()) {
case Int:
- append(new Op2Stack(IXOR, result, a, loadNonConst(b)));
+ append(new Op2Reg(IXOR, result, a, loadNonConst(b)));
break;
case Long:
- append(new Op2Stack(LXOR, result, a, loadNonConst(b)));
+ append(new Op2Reg(LXOR, result, a, loadNonConst(b)));
break;
default:
throw GraalInternalError.shouldNotReachHere();
@@ -720,7 +710,7 @@
@Override
public Value emitMathAbs(Value input) {
Variable result = newVariable(input.getPlatformKind());
- append(new Op1Stack(ABS, result, input));
+ append(new Op1Reg(ABS, result, input));
return result;
}
@@ -732,7 +722,7 @@
*/
public Value emitMathCeil(Value input) {
Variable result = newVariable(input.getPlatformKind());
- append(new Op1Stack(CEIL, result, input));
+ append(new Op1Reg(CEIL, result, input));
return result;
}
@@ -744,7 +734,7 @@
*/
public Value emitMathFloor(Value input) {
Variable result = newVariable(input.getPlatformKind());
- append(new Op1Stack(FLOOR, result, input));
+ append(new Op1Reg(FLOOR, result, input));
return result;
}
@@ -756,7 +746,7 @@
*/
public Value emitMathRint(Value input) {
Variable result = newVariable(input.getPlatformKind());
- append(new Op1Stack(RINT, result, input));
+ append(new Op1Reg(RINT, result, input));
return result;
}
@@ -769,7 +759,7 @@
@Override
public Value emitMathSqrt(Value input) {
Variable result = newVariable(input.getPlatformKind());
- append(new Op1Stack(SQRT, result, input));
+ append(new Op1Reg(SQRT, result, input));
return result;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/BoxingEliminationTest.java Sat May 03 21:46:35 2014 +0200
@@ -29,6 +29,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/DegeneratedLoopsTest.java Sat May 03 21:46:35 2014 +0200
@@ -30,6 +30,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
/**
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/FinalizableSubclassTest.java Sat May 03 21:46:35 2014 +0200
@@ -38,6 +38,7 @@
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class FinalizableSubclassTest extends GraalCompilerTest {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeExceptionTest.java Sat May 03 21:46:35 2014 +0200
@@ -30,6 +30,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class InvokeExceptionTest extends GraalCompilerTest {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/InvokeHintsTest.java Sat May 03 21:46:35 2014 +0200
@@ -30,6 +30,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class InvokeHintsTest extends GraalCompilerTest {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/LockEliminationTest.java Sat May 03 21:46:35 2014 +0200
@@ -32,6 +32,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class LockEliminationTest extends GraalCompilerTest {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MemoryScheduleTest.java Sat May 03 21:46:35 2014 +0200
@@ -24,7 +24,6 @@
import static com.oracle.graal.compiler.common.GraalOptions.*;
import static org.junit.Assert.*;
-
import java.util.*;
import org.junit.*;
@@ -43,6 +42,7 @@
import com.oracle.graal.options.OptionValue.OverrideScope;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.schedule.*;
import com.oracle.graal.phases.schedule.SchedulePhase.MemoryScheduling;
import com.oracle.graal.phases.schedule.SchedulePhase.SchedulingStrategy;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/MonitorGraphTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.compiler.test;
import static com.oracle.graal.graph.iterators.NodePredicates.*;
-
import java.util.*;
import org.junit.*;
@@ -35,6 +34,7 @@
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
/**
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EATestBase.java Sat May 03 21:46:35 2014 +0200
@@ -37,6 +37,7 @@
import com.oracle.graal.nodes.virtual.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
@@ -126,7 +127,7 @@
/**
* Runs Escape Analysis on the given snippet and makes sure that no allocations remain in the
* graph.
- *
+ *
* @param snippet the name of the method whose graph should be processed
* @param expectedConstantResult if this is non-null, the resulting graph needs to have the
* given constant return value
@@ -156,7 +157,7 @@
new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
new DeadCodeEliminationPhase().apply(graph);
new CanonicalizerPhase(true).apply(graph, context);
- new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true)).apply(graph, context);
+ new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(true), null).apply(graph, context);
returnNodes = graph.getNodes(ReturnNode.class).snapshot();
} catch (Throwable e) {
throw Debug.handle(e);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/EarlyReadEliminationTest.java Sat May 03 21:46:35 2014 +0200
@@ -27,6 +27,7 @@
import com.oracle.graal.api.code.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PEAReadEliminationTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.compiler.test.ea;
import static org.junit.Assert.*;
-
import java.util.*;
import org.junit.*;
@@ -34,6 +33,7 @@
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
@@ -247,6 +247,6 @@
Assumptions assumptions = new Assumptions(false);
HighTierContext context = new HighTierContext(getProviders(), assumptions, null, getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL);
new InliningPhase(new CanonicalizerPhase(true)).apply(graph, context);
- new PartialEscapePhase(false, true, new CanonicalizerPhase(true)).apply(graph, context);
+ new PartialEscapePhase(false, true, new CanonicalizerPhase(true), null).apply(graph, context);
}
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PartialEscapeAnalysisTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.compiler.test.ea;
import java.lang.ref.*;
+import java.util.function.*;
import org.junit.*;
@@ -30,7 +31,6 @@
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.nodes.virtual.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.graph.*;
@@ -186,11 +186,11 @@
Assert.assertTrue("partial escape analysis should have removed all NewInstanceNode allocations", graph.getNodes().filter(NewInstanceNode.class).isEmpty());
Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty());
- NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+ ToDoubleFunction nodeProbabilities = new FixedNodeProbabilityCache();
double probabilitySum = 0;
int materializeCount = 0;
for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) {
- probabilitySum += nodeProbabilities.get(materialize) * materialize.getVirtualObjects().size();
+ probabilitySum += nodeProbabilities.applyAsDouble(materialize) * materialize.getVirtualObjects().size();
materializeCount += materialize.getVirtualObjects().size();
}
Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/ea/PoorMansEATest.java Sat May 03 21:46:35 2014 +0200
@@ -34,6 +34,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
/**
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/inlining/InliningTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.compiler.test.inlining;
import static org.junit.Assert.*;
-
import java.lang.reflect.*;
import org.junit.*;
@@ -37,6 +36,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class InliningTest extends GraalCompilerTest {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java Sat May 03 21:46:35 2014 +0200
@@ -45,11 +45,9 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.cfg.*;
import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.options.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.graph.*;
import com.oracle.graal.phases.schedule.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
@@ -230,10 +228,8 @@
List linearScanOrder = null;
try (Scope ds = Debug.scope("MidEnd")) {
try (Scope s = Debug.scope("ComputeLinearScanOrder")) {
- NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
- BlocksToDoubles blockProbabilities = BlocksToDoubles.createFromNodeProbability(nodeProbabilities, schedule.getCFG());
- codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock, blockProbabilities);
- linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock, blockProbabilities);
+ codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock);
+ linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock);
lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder);
Debug.dump(lir, "After linear scan order");
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/phases/HighTier.java Sat May 03 21:46:35 2014 +0200
@@ -24,13 +24,13 @@
import static com.oracle.graal.compiler.common.GraalOptions.*;
import static com.oracle.graal.compiler.phases.HighTier.Options.*;
-
import com.oracle.graal.loop.phases.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.options.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.virtual.phases.ea.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java
--- a/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.gpu/src/com/oracle/graal/gpu/ExternalCompilationResult.java Sat May 03 21:46:35 2014 +0200
@@ -43,6 +43,8 @@
private long entryPoint;
private StructuredGraph hostGraph;
+ private int[] oopMapArray;
+
/**
* Set the address for the point of entry to the external compilation result.
*
@@ -75,4 +77,13 @@
public StructuredGraph getHostGraph() {
return hostGraph;
}
+
+ public void setOopMapArray(int[] arr) {
+ oopMapArray = arr;
+ }
+
+ public int[] getOopMapArray() {
+ return oopMapArray;
+ }
+
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java
--- a/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.amd64/src/com/oracle/graal/hotspot/amd64/AMD64HotSpotBackendFactory.java Sat May 03 21:46:35 2014 +0200
@@ -113,7 +113,9 @@
Replacements replacements = createReplacements(runtime, assumptions, p, snippetReflection);
HotSpotDisassemblerProvider disassembler = createDisassembler(runtime);
HotSpotSuitesProvider suites = createSuites(runtime);
- HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+ HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+ HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+ methodHandleAccess);
return createBackend(runtime, providers);
}
@@ -189,15 +191,15 @@
} else {
/*
* System V Application Binary Interface, AMD64 Architecture Processor Supplement
- *
+ *
* Draft Version 0.96
- *
+ *
* http://www.uclibc.org/docs/psABI-x86_64.pdf
- *
+ *
* 3.2.1
- *
+ *
* ...
- *
+ *
* This subsection discusses usage of each register. Registers %rbp, %rbx and %r12
* through %r15 "belong" to the calling function and the called function is required to
* preserve their values. In other words, a called function must preserve these
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackend.java Sat May 03 21:46:35 2014 +0200
@@ -66,7 +66,6 @@
import com.oracle.graal.lir.hsail.HSAILMove.AtomicReadAndAddOp;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.StructuredGraph.GuardsStage;
-import com.oracle.graal.nodes.calc.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
@@ -145,7 +144,21 @@
*/
public HotSpotNmethod compileAndInstallKernel(Method method) {
ResolvedJavaMethod javaMethod = getProviders().getMetaAccess().lookupJavaMethod(method);
- return installKernel(javaMethod, compileKernel(javaMethod, true));
+ HotSpotNmethod nm = installKernel(javaMethod, compileKernel(javaMethod, true));
+ try (Scope s = Debug.scope("HostCodeGen")) {
+ if (Debug.isLogEnabled()) {
+ DisassemblerProvider dis = getRuntime().getHostBackend().getDisassembler();
+ if (dis != null) {
+ String disasm = dis.disassemble(nm);
+ Debug.log("host code generated for %s%n%s", javaMethod, disasm);
+ } else {
+ Debug.log("host code disassembler is null");
+ }
+ }
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ return nm;
}
/**
@@ -274,7 +287,8 @@
}
}
- HotSpotNmethod code = new HotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
+ HSAILHotSpotNmethod code = new HSAILHotSpotNmethod(javaMethod, hsailCode.getName(), false, true);
+ code.setOopMapArray(hsailCode.getOopMapArray());
HotSpotCompiledNmethod compiled = new HotSpotCompiledNmethod(getTarget(), javaMethod, compilationResult);
CodeInstallResult result = getRuntime().getCompilerToVM().installCode(compiled, code, null);
if (result != CodeInstallResult.OK) {
@@ -359,11 +373,16 @@
if (!deviceInitialized) {
throw new GraalInternalError("Cannot execute GPU kernel if device is not initialized");
}
- Object[] oopsSaveArea = new Object[maxDeoptIndex * 16];
- return executeKernel0(kernel, jobSize, args, oopsSaveArea, donorThreadPool.get().getThreads(), HsailAllocBytesPerWorkitem.getValue());
+ int[] oopMapArray = ((HSAILHotSpotNmethod) kernel).getOopMapArray();
+ int saveAreaCounts = OopMapArrayBuilder.getSaveAreaCounts(oopMapArray);
+ int numDRegs = (saveAreaCounts >> 8) & 0xff;
+ int numStackSlots = (saveAreaCounts >> 16);
+ // pessimistically assume that any of the DRegs or stackslots could be oops
+ Object[] oopsSaveArea = new Object[maxDeoptIndex * (numDRegs + numStackSlots)];
+ return executeKernel0(kernel, jobSize, args, oopsSaveArea, donorThreadPool.get().getThreads(), HsailAllocBytesPerWorkitem.getValue(), oopMapArray);
}
- private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave, Thread[] donorThreads, int allocBytesPerWorkitem)
+ private static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args, Object[] oopsSave, Thread[] donorThreads, int allocBytesPerWorkitem, int[] oopMapArray)
throws InvalidInstalledCodeException;
/**
@@ -419,6 +438,22 @@
}
}
+ static class HSAILHotSpotNmethod extends HotSpotNmethod {
+ private int[] oopMapArray;
+
+ HSAILHotSpotNmethod(HotSpotResolvedJavaMethod method, String name, boolean isDefault, boolean isExternal) {
+ super(method, name, isDefault, isExternal);
+ }
+
+ void setOopMapArray(int[] array) {
+ oopMapArray = array;
+ }
+
+ int[] getOopMapArray() {
+ return oopMapArray;
+ }
+ }
+
@Override
protected Assembler createAssembler(FrameMap frameMap) {
return new HSAILHotSpotAssembler(getTarget());
@@ -686,10 +721,54 @@
asm.emitString(spillsegStringFinal, spillsegDeclarationPosition);
// Emit the epilogue.
- // TODO: keep track of whether we need it
+ int numSRegs = 0;
+ int numDRegs = 0;
+ int numStackSlotBytes = 0;
if (useHSAILDeoptimization) {
+ // get the union of registers and stack slots needed to be saved at the infopoints
+ // while doing this compute the highest register in each category
+ HSAILHotSpotRegisterConfig hsailRegConfig = (HSAILHotSpotRegisterConfig) regConfig;
+ Set infoUsedRegs = new TreeSet<>();
+ Set infoUsedStackSlots = new HashSet<>();
+ List infoList = crb.compilationResult.getInfopoints();
+ for (Infopoint info : infoList) {
+ BytecodeFrame frame = info.debugInfo.frame();
+ while (frame != null) {
+ for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
+ Value val = frame.values[i];
+ if (isLegal(val)) {
+ if (isRegister(val)) {
+ Register reg = asRegister(val);
+ infoUsedRegs.add(reg);
+ if (hsailRegConfig.isAllocatableSReg(reg)) {
+ numSRegs = Math.max(numSRegs, reg.encoding + 1);
+ } else if (hsailRegConfig.isAllocatableDReg(reg)) {
+ numDRegs = Math.max(numDRegs, reg.encoding + 1);
+ }
+ } else if (isStackSlot(val)) {
+ StackSlot slot = asStackSlot(val);
+ Kind slotKind = slot.getKind();
+ int slotSizeBytes = (slotKind.isObject() ? 8 : slotKind.getByteCount());
+ int slotOffsetMax = HSAIL.getStackOffsetStart(slot, slotSizeBytes * 8) + slotSizeBytes;
+ numStackSlotBytes = Math.max(numStackSlotBytes, slotOffsetMax);
+ infoUsedStackSlots.add(slot);
+ }
+ }
+ }
+ frame = frame.caller();
+ }
+ }
+
+ // round up numSRegs to even number so dregs start on aligned boundary
+ numSRegs += (numSRegs & 1);
+
+ // numStackSlots is the number of 8-byte locations used for stack variables
+ int numStackSlots = (numStackSlotBytes + 7) / 8;
+
final int offsetToDeoptSaveStates = config.hsailSaveStatesOffset0;
- final int sizeofKernelDeopt = config.hsailSaveStatesOffset1 - config.hsailSaveStatesOffset0;
+ final int sizeofKernelDeoptHeader = config.hsailKernelDeoptimizationHeaderSize;
+ final int bytesPerSaveArea = 4 * numSRegs + 8 * numDRegs + 8 * numStackSlots;
+ final int sizeofKernelDeopt = sizeofKernelDeoptHeader + bytesPerSaveArea;
final int offsetToNeverRanArray = config.hsailNeverRanArrayOffset;
final int offsetToDeoptNextIndex = config.hsailDeoptNextIndexOffset;
final int offsetToDeoptimizationWorkItem = config.hsailDeoptimizationWorkItem;
@@ -708,7 +787,6 @@
AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
AllocatableValue scratch32 = HSAIL.s34.asValue(Kind.Int);
AllocatableValue workidreg = HSAIL.s35.asValue(Kind.Int);
- AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
HSAILAddress deoptNextIndexAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToDeoptNextIndex).toAddress();
HSAILAddress neverRanArrayAddr = new HSAILAddressValue(Kind.Int, scratch64, offsetToNeverRanArray).toAddress();
@@ -769,8 +847,6 @@
// Now scratch64 is the _deopt_info._first_frame
HSAILAddress pcStoreAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToFramePc).toAddress();
HSAILAddress regCountsAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves).toAddress();
- HSAILAddress dregOopMapAddr = new HSAILAddressValue(Kind.Int, waveMathScratch1, offsetToNumSaves + 2).toAddress();
-
asm.emitComment("// store deopting workitem");
asm.emitWorkItemAbsId(scratch32);
asm.emitStore(Kind.Int, scratch32, workItemAddr);
@@ -778,58 +854,61 @@
asm.emitStore(Kind.Int, actionAndReasonReg, actionReasonStoreAddr);
asm.emitComment("// store PC");
asm.emitStore(Kind.Int, codeBufferOffsetReg, pcStoreAddr);
- asm.emitComment("// store regCounts");
- asm.emitStore(Kind.Short, Constant.forInt(32 + (16 << 8) + (0 << 16)), regCountsAddr);
- asm.emitComment("// store dreg ref map bits");
- asm.emitStore(Kind.Short, dregOopMapReg, dregOopMapAddr);
+
+ asm.emitComment("// store regCounts (" + numSRegs + " $s registers and " + numDRegs + " $d registers" + numStackSlots + " stack slots)");
+ asm.emitStore(Kind.Int, Constant.forInt(numSRegs + (numDRegs << 8) + (numStackSlots << 16)), regCountsAddr);
- // get the union of registers needed to be saved at the infopoints
- boolean[] infoUsedRegs = new boolean[HSAIL.threadRegister.number + 1];
- List infoList = crb.compilationResult.getInfopoints();
- for (Infopoint info : infoList) {
- BytecodeFrame frame = info.debugInfo.frame();
- for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
- Value val = frame.values[i];
- if (isLegal(val) && isRegister(val)) {
- Register reg = asRegister(val);
- infoUsedRegs[reg.number] = true;
- }
+ // loop thru the usedValues storing each of the registers that are used.
+ // we always store in a fixed location, even if some registers are skipped
+ asm.emitComment("// store used regs");
+ for (Register reg : infoUsedRegs) {
+ if (hsailRegConfig.isAllocatableSReg(reg)) {
+ // 32 bit registers
+ Kind kind = Kind.Int;
+ int ofst = offsetToSaveArea + reg.encoding * 4;
+ HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+ AllocatableValue regValue = reg.asValue(kind);
+ asm.emitStore(kind, regValue, addr);
+ } else if (hsailRegConfig.isAllocatableDReg(reg)) {
+ // 64 bit registers
+ Kind kind = Kind.Long;
+ // d reg ofst starts past the 32 sregs
+ int ofst = offsetToSaveArea + (numSRegs * 4) + reg.encoding * 8;
+ HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
+ AllocatableValue regValue = reg.asValue(kind);
+ asm.emitStore(kind, regValue, addr);
+ } else {
+ throw GraalInternalError.unimplemented();
}
}
- // loop storing each of the 32 s registers that are used by infopoints
- // we always store in a fixed location, even if some registers are not stored
- asm.emitComment("// store used s regs");
- int ofst = offsetToSaveArea;
- for (Register sreg : HSAIL.sRegisters) {
- if (infoUsedRegs[sreg.number]) {
- Kind kind = Kind.Int;
+ // loop thru the usedStackSlots creating instructions to save in the save area
+ if (numStackSlotBytes > 0) {
+ asm.emitComment("// store stack slots (uses " + numStackSlotBytes + " bytes)");
+ for (StackSlot slot : infoUsedStackSlots) {
+ asm.emitComment("// store " + slot);
+ Kind kind = slot.getKind();
+ int sizeInBits = (kind.isObject() || kind.getByteCount() == 8 ? 64 : 32);
+ int ofst = offsetToSaveArea + (numSRegs * 4) + (numDRegs * 8) + HSAIL.getStackOffsetStart(slot, sizeInBits);
HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
- AllocatableValue sregValue = sreg.asValue(kind);
- asm.emitStore(kind, sregValue, addr);
+ if (sizeInBits == 64) {
+ asm.emitSpillLoad(kind, scratch64, slot);
+ asm.emitStore(kind, scratch64, addr);
+ } else {
+ asm.emitSpillLoad(kind, scratch32, slot);
+ asm.emitStore(kind, scratch32, addr);
+ }
}
- ofst += 4;
}
- // loop storing each of the 16 d registers that are used by infopoints
- asm.emitComment("// store used d regs");
- for (Register dreg : HSAIL.dRegisters) {
- if (infoUsedRegs[dreg.number]) {
- Kind kind = Kind.Long;
- HSAILAddress addr = new HSAILAddressValue(kind, waveMathScratch1, ofst).toAddress();
- AllocatableValue dregValue = dreg.asValue(kind);
- asm.emitStore(kind, dregValue, addr);
- }
- ofst += 8;
- }
-
- // for now, ignore saving the spill variables but that would come here
-
asm.emitString0(labelExit + ":\n");
// and emit the return
crb.frameContext.leave(crb);
asm.exit();
+ // build the oopMap Array
+ int[] oopMapArray = new OopMapArrayBuilder().build(infoList, numSRegs, numDRegs, numStackSlots, hsailRegConfig);
+ ((ExternalCompilationResult) crb.compilationResult).setOopMapArray(oopMapArray);
} else {
// Deoptimization is explicitly off, so emit simple return
asm.emitString0(asm.getDeoptLabelName() + ":\n");
@@ -841,10 +920,115 @@
ExternalCompilationResult compilationResult = (ExternalCompilationResult) crb.compilationResult;
HSAILHotSpotLIRGenerationResult lirGenRes = ((HSAILCompilationResultBuilder) crb).lirGenRes;
- compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config));
+ compilationResult.setHostGraph(prepareHostGraph(method, lirGenRes.getDeopts(), getProviders(), config, numSRegs, numDRegs));
}
- private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List deopts, HotSpotProviders providers, HotSpotVMConfig config) {
+ private static class OopMapArrayBuilder {
+ // oopMapArray struct
+ // int bytesPerSaveArea; (not strictly part of oopsmap but convenient to put here)
+ // int intsPerInfopoint;
+ static final int SAVEAREACOUNTS_OFST = 0;
+ static final int INTSPERINFOPOINT_OFST = 1;
+ static final int HEADERSIZE = 2;
+ // for each infopoint:
+ // int deoptId
+ // one or more ints of bits for the oopmap
+
+ private int[] array;
+ private int intsPerInfopoint;
+
+ int[] build(List infoList, int numSRegs, int numDRegs, int numStackSlots, HSAILHotSpotRegisterConfig hsailRegConfig) {
+ // we are told that infoList is always sorted
+ // each infoPoint can have a different oopMap
+
+ // since numStackSlots is the number of 8-byte stack slots used, it is an upper limit on
+ // the number of oop stack slots
+ int bitsPerInfopoint = numDRegs + numStackSlots;
+ int intsForBits = (bitsPerInfopoint + 31) / 32;
+ int numInfopoints = infoList.size();
+ intsPerInfopoint = intsForBits + 1; // +1 for the pcoffset
+ int arraySize = HEADERSIZE + (numInfopoints * intsPerInfopoint);
+ array = new int[arraySize];
+ array[INTSPERINFOPOINT_OFST] = intsPerInfopoint;
+ // compute saveAreaCounts
+ int saveAreaCounts = (numSRegs & 0xff) + (numDRegs << 8) + (numStackSlots << 16);
+ array[SAVEAREACOUNTS_OFST] = saveAreaCounts;
+
+ // loop thru the infoList
+ int infoIndex = 0;
+ for (Infopoint info : infoList) {
+ setOopMapPcOffset(infoIndex, info.pcOffset);
+ BytecodeFrame frame = info.debugInfo.frame();
+ while (frame != null) {
+ for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
+ Value val = frame.values[i];
+ if (isLegal(val)) {
+ if (isRegister(val)) {
+ Register reg = asRegister(val);
+ if (val.getKind().isObject()) {
+ assert (hsailRegConfig.isAllocatableDReg(reg));
+ int bitIndex = reg.encoding();
+ setOopMapBit(infoIndex, bitIndex);
+ }
+ } else if (isStackSlot(val)) {
+ StackSlot slot = asStackSlot(val);
+ if (val.getKind().isObject()) {
+ assert (HSAIL.getStackOffsetStart(slot, 64) % 8 == 0);
+ int bitIndex = numDRegs + HSAIL.getStackOffsetStart(slot, 64) / 8;
+ setOopMapBit(infoIndex, bitIndex);
+ }
+ }
+ }
+ }
+ frame = frame.caller();
+ }
+ infoIndex++;
+ }
+ try (Scope s = Debug.scope("CodeGen")) {
+ if (Debug.isLogEnabled()) {
+ Debug.log("numSRegs=%d, numDRegs=%d, numStackSlots=%d", numSRegs, numDRegs, numStackSlots);
+ // show infopoint oopmap details
+ for (infoIndex = 0; infoIndex < infoList.size(); infoIndex++) {
+ String infoString = "Infopoint " + infoIndex + ", pcOffset=" + getOopMapPcOffset(infoIndex) + ", oopmap=";
+ for (int i = 0; i < intsForBits; i++) {
+ infoString += (i != 0 ? ", " : "") + Integer.toHexString(getOopMapBitsAsInt(infoIndex, i));
+ }
+ Debug.log(infoString);
+ }
+ }
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+
+ return array;
+ }
+
+ private void setOopMapPcOffset(int infoIndex, int pcOffset) {
+ int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint;
+ array[arrIndex] = pcOffset;
+ }
+
+ private int getOopMapPcOffset(int infoIndex) {
+ int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint;
+ return array[arrIndex];
+ }
+
+ private void setOopMapBit(int infoIndex, int bitIndex) {
+ int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint + 1 + bitIndex / 32;
+ array[arrIndex] |= (1 << (bitIndex % 32));
+ }
+
+ private int getOopMapBitsAsInt(int infoIndex, int intIndex) {
+ int arrIndex = HEADERSIZE + infoIndex * intsPerInfopoint + 1 + intIndex;
+ return array[arrIndex];
+ }
+
+ public static int getSaveAreaCounts(int[] array) {
+ return array[SAVEAREACOUNTS_OFST];
+ }
+ }
+
+ private static StructuredGraph prepareHostGraph(ResolvedJavaMethod method, List deopts, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
if (deopts.isEmpty()) {
return null;
}
@@ -868,7 +1052,7 @@
keyProbabilities[i] = 1.0 / deopts.size();
keys[i] = deopt.getCodeBufferPos();
assert keys[i] >= 0;
- branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config);
+ branches[i] = createHostDeoptBranch(deopt, hsailFrame, reasonAndAction, speculation, providers, config, numSRegs, numDRegs);
i++;
}
@@ -892,34 +1076,35 @@
return BeginNode.begin(vmError);
}
- private static BeginNode createHostDeoptBranch(DeoptimizingOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers, HotSpotVMConfig config) {
+ private static BeginNode createHostDeoptBranch(DeoptimizingOp deopt, ParameterNode hsailFrame, ValueNode reasonAndAction, ValueNode speculation, HotSpotProviders providers,
+ HotSpotVMConfig config, int numSRegs, int numDRegs) {
BeginNode branch = hsailFrame.graph().add(new BeginNode());
DynamicDeoptimizeNode deoptimization = hsailFrame.graph().add(new DynamicDeoptimizeNode(reasonAndAction, speculation));
- deoptimization.setStateBefore(createFrameState(deopt.getFrameState().topFrame, hsailFrame, providers, config));
+ deoptimization.setStateBefore(createFrameState(deopt.getFrameState().topFrame, hsailFrame, providers, config, numSRegs, numDRegs));
branch.setNext(deoptimization);
return branch;
}
- private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config) {
+ private static FrameState createFrameState(BytecodeFrame lowLevelFrame, ParameterNode hsailFrame, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs, int numDRegs) {
StructuredGraph hostGraph = hsailFrame.graph();
ValueNode[] locals = new ValueNode[lowLevelFrame.numLocals];
for (int i = 0; i < lowLevelFrame.numLocals; i++) {
- locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config);
+ locals[i] = getNodeForValueFromFrame(lowLevelFrame.getLocalValue(i), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
}
List stack = new ArrayList<>(lowLevelFrame.numStack);
for (int i = 0; i < lowLevelFrame.numStack; i++) {
- stack.add(getNodeForValueFromFrame(lowLevelFrame.getStackValue(i), hsailFrame, hostGraph, providers, config));
+ stack.add(getNodeForValueFromFrame(lowLevelFrame.getStackValue(i), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs));
}
ValueNode[] locks = new ValueNode[lowLevelFrame.numLocks];
MonitorIdNode[] monitorIds = new MonitorIdNode[lowLevelFrame.numLocks];
for (int i = 0; i < lowLevelFrame.numLocks; i++) {
HotSpotMonitorValue lockValue = (HotSpotMonitorValue) lowLevelFrame.getLockValue(i);
- locks[i] = getNodeForValueFromFrame(lockValue, hsailFrame, hostGraph, providers, config);
+ locks[i] = getNodeForValueFromFrame(lockValue, hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
monitorIds[i] = getMonitorIdForHotSpotMonitorValueFromFrame(lockValue, hsailFrame, hostGraph);
}
FrameState frameState = hostGraph.add(new FrameState(lowLevelFrame.getMethod(), lowLevelFrame.getBCI(), locals, stack, locks, monitorIds, lowLevelFrame.rethrowException, false));
if (lowLevelFrame.caller() != null) {
- frameState.setOuterFrameState(createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config));
+ frameState.setOuterFrameState(createFrameState(lowLevelFrame.caller(), hsailFrame, providers, config, numSRegs, numDRegs));
}
return frameState;
}
@@ -932,21 +1117,23 @@
throw GraalInternalError.unimplemented();
}
- private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+ private static ValueNode getNodeForValueFromFrame(Value localValue, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config, int numSRegs,
+ int numDRegs) {
ValueNode valueNode;
if (localValue instanceof Constant) {
valueNode = ConstantNode.forConstant((Constant) localValue, providers.getMetaAccess(), hostGraph);
} else if (localValue instanceof VirtualObject) {
throw GraalInternalError.unimplemented();
} else if (localValue instanceof StackSlot) {
- throw GraalInternalError.unimplemented();
+ StackSlot slot = (StackSlot) localValue;
+ valueNode = getNodeForStackSlotFromFrame(slot, localValue.getKind(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
} else if (localValue instanceof HotSpotMonitorValue) {
HotSpotMonitorValue hotSpotMonitorValue = (HotSpotMonitorValue) localValue;
- return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config);
+ return getNodeForValueFromFrame(hotSpotMonitorValue.getOwner(), hsailFrame, hostGraph, providers, config, numSRegs, numDRegs);
} else if (localValue instanceof RegisterValue) {
RegisterValue registerValue = (RegisterValue) localValue;
int regNumber = registerValue.getRegister().number;
- valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config);
+ valueNode = getNodeForRegisterFromFrame(regNumber, localValue.getKind(), hsailFrame, hostGraph, providers, config, numSRegs);
} else if (Value.ILLEGAL.equals(localValue)) {
valueNode = null;
} else {
@@ -955,20 +1142,18 @@
return valueNode;
}
- private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config) {
+ private static ValueNode getNodeForRegisterFromFrame(int regNumber, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config,
+ int numSRegs) {
ValueNode valueNode;
LocationNode location;
+ int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
+ int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
if (regNumber >= HSAIL.s0.number && regNumber <= HSAIL.s31.number) {
- int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
long offset = config.hsailFrameSaveAreaOffset + intSize * (regNumber - HSAIL.s0.number);
location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
} else if (regNumber >= HSAIL.d0.number && regNumber <= HSAIL.d15.number) {
- int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
- long offset = config.hsailFrameSaveAreaOffset + longSize * (regNumber - HSAIL.d0.number);
- LocationNode numSRegsLocation = ConstantLocationNode.create(FINAL_LOCATION, Kind.Byte, config.hsailFrameNumSRegOffset, hostGraph);
- ValueNode numSRegs = hostGraph.unique(new FloatingReadNode(hsailFrame, numSRegsLocation, null, StampFactory.forInteger(8)));
- numSRegs = SignExtendNode.convert(numSRegs, StampFactory.forKind(Kind.Byte));
- location = IndexedLocationNode.create(FINAL_LOCATION, valueKind, offset, numSRegs, hostGraph, 4);
+ long offset = config.hsailFrameSaveAreaOffset + intSize * numSRegs + longSize * (regNumber - HSAIL.d0.number);
+ location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
} else {
throw GraalInternalError.shouldNotReachHere("unknown hsail register: " + regNumber);
}
@@ -976,4 +1161,18 @@
return valueNode;
}
+ private static ValueNode getNodeForStackSlotFromFrame(StackSlot slot, Kind valueKind, ParameterNode hsailFrame, StructuredGraph hostGraph, HotSpotProviders providers, HotSpotVMConfig config,
+ int numSRegs, int numDRegs) {
+ int slotSizeInBits = (valueKind == Kind.Object ? 64 : valueKind.getByteCount() * 8);
+ if ((slotSizeInBits == 32) || (slotSizeInBits == 64)) {
+ int longSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Long);
+ int intSize = providers.getCodeCache().getTarget().arch.getSizeInBytes(Kind.Int);
+ long offset = config.hsailFrameSaveAreaOffset + (intSize * numSRegs) + (longSize * numDRegs) + HSAIL.getStackOffsetStart(slot, slotSizeInBits);
+ LocationNode location = ConstantLocationNode.create(FINAL_LOCATION, valueKind, offset, hostGraph);
+ ValueNode valueNode = hostGraph.unique(new FloatingReadNode(hsailFrame, location, null, StampFactory.forKind(valueKind)));
+ return valueNode;
+ } else {
+ throw GraalInternalError.shouldNotReachHere("unsupported stack slot kind: " + valueKind);
+ }
+ }
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotBackendFactory.java Sat May 03 21:46:35 2014 +0200
@@ -57,7 +57,8 @@
Replacements replacements = new HSAILHotSpotReplacementsImpl(p, host.getSnippetReflection(), assumptions, codeCache.getTarget(), host.getReplacements());
HotSpotDisassemblerProvider disassembler = host.getDisassembler();
SuitesProvider suites = new HotSpotSuitesProvider(runtime);
- HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
+ HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+ host.getMethodHandleAccess());
// pass registers info down to ReplacementsUtil (maybe a better way to do this?)
HSAILHotSpotReplacementsUtil.initialize(providers.getRegisters());
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotRegisterConfig.java Sat May 03 21:46:35 2014 +0200
@@ -194,6 +194,14 @@
throw new UnsupportedOperationException();
}
+ public boolean isAllocatableSReg(Register reg) {
+ return (reg.number >= HSAIL.s0.number && reg.number <= HSAIL.s31.number);
+ }
+
+ public boolean isAllocatableDReg(Register reg) {
+ return (reg.number >= HSAIL.d0.number && reg.number <= HSAIL.d15.number);
+ }
+
public HSAILHotSpotRegisterConfig() {
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java
--- a/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.hsail/src/com/oracle/graal/hotspot/hsail/HSAILHotSpotSafepointOp.java Sat May 03 21:46:35 2014 +0200
@@ -22,8 +22,6 @@
*/
package com.oracle.graal.hotspot.hsail;
-import static com.oracle.graal.api.code.ValueUtil.*;
-
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.asm.hsail.*;
@@ -42,7 +40,6 @@
private Constant actionAndReason;
@State protected LIRFrameState frameState;
protected int codeBufferPos = -1;
- protected int dregOopMap = 0;
final int offsetToNoticeSafepoints;
public HSAILHotSpotSafepointOp(LIRFrameState state, HotSpotVMConfig config, NodeLIRBuilderTool tool) {
@@ -77,23 +74,10 @@
masm.emitCompare(Kind.Int, scratch32, Constant.forInt(0), "eq", false, false);
masm.cbr(afterSafepointLabel);
- BytecodeFrame frame = frameState.debugInfo().frame();
- for (int i = 0; i < frame.numLocals + frame.numStack; i++) {
- Value val = frame.values[i];
- if (isLegal(val) && isRegister(val)) {
- Register reg = asRegister(val);
- if (val.getKind() == Kind.Object) {
- dregOopMap |= 1 << (reg.encoding());
- }
- }
- }
-
AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
- AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
- masm.emitMov(Kind.Int, dregOopMapReg, Constant.forInt(dregOopMap));
masm.emitJumpToLabelName(masm.getDeoptLabelName());
masm.emitString0(afterSafepointLabel + ":\n");
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java
--- a/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.ptx/src/com/oracle/graal/hotspot/ptx/PTXHotSpotBackendFactory.java Sat May 03 21:46:35 2014 +0200
@@ -47,7 +47,8 @@
HotSpotDisassemblerProvider disassembler = host.getDisassembler();
SuitesProvider suites = new DefaultSuitesProvider();
HotSpotRegistersProvider registers = new HotSpotRegisters(PTX.tid, Register.None, Register.None);
- HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection());
+ HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, host.getSnippetReflection(),
+ host.getMethodHandleAccess());
return new PTXHotSpotBackend(runtime, providers);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java
--- a/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.sparc/src/com/oracle/graal/hotspot/sparc/SPARCHotSpotBackendFactory.java Sat May 03 21:46:35 2014 +0200
@@ -64,7 +64,9 @@
HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(p, snippetReflection, runtime.getConfig(), assumptions, target);
HotSpotDisassemblerProvider disassembler = new HotSpotDisassemblerProvider(runtime);
HotSpotSuitesProvider suites = new HotSpotSuitesProvider(runtime);
- HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection);
+ HotSpotMethodHandleAccessProvider methodHandleAccess = new HotSpotMethodHandleAccessProvider();
+ HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements, disassembler, suites, registers, snippetReflection,
+ methodHandleAccess);
return new SPARCHotSpotBackend(runtime, providers);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierAdditionTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.hotspot.test;
import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
-
import java.lang.ref.*;
import java.lang.reflect.*;
@@ -44,6 +43,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.runtime.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java
--- a/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot.test/src/com/oracle/graal/hotspot/test/WriteBarrierVerificationTest.java Sat May 03 21:46:35 2014 +0200
@@ -40,6 +40,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.graph.*;
import com.oracle.graal.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
import com.oracle.graal.phases.tiers.*;
@@ -693,7 +694,7 @@
DebugConfig debugConfig = DebugScope.getConfig();
DebugConfig fixedConfig = Debug.fixedConfig(false, false, false, false, debugConfig.dumpHandlers(), debugConfig.output());
try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
- ReentrantNodeIterator.apply(closure, graph.start(), false, null);
+ ReentrantNodeIterator.apply(closure, graph.start(), false);
new WriteBarrierVerificationPhase().apply(graph);
} catch (AssertionError error) {
/*
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/CompilationTask.java Sat May 03 21:46:35 2014 +0200
@@ -29,7 +29,7 @@
import static com.oracle.graal.compiler.common.UnsafeAccess.*;
import static com.oracle.graal.hotspot.bridge.VMToCompilerImpl.*;
import static com.oracle.graal.nodes.StructuredGraph.*;
-import static com.oracle.graal.phases.common.InliningUtil.*;
+import static com.oracle.graal.phases.common.inlining.InliningUtil.*;
import java.io.*;
import java.lang.management.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotGraalRuntime.java Sat May 03 21:46:35 2014 +0200
@@ -368,6 +368,8 @@
return (T) this;
} else if (clazz == SnippetReflectionProvider.class) {
return (T) getHostProviders().getSnippetReflection();
+ } else if (clazz == MethodHandleAccessProvider.class) {
+ return (T) getHostProviders().getMethodHandleAccess();
}
return null;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotOptions.java Sat May 03 21:46:35 2014 +0200
@@ -37,7 +37,7 @@
import com.oracle.graal.debug.*;
import com.oracle.graal.hotspot.logging.*;
import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
/**
* Called from {@code graalCompiler.cpp} to parse any Graal specific options. Such options are
@@ -113,7 +113,7 @@
/**
* Parses a given option value specification.
- *
+ *
* @param option the specification of an option and its value
* @param setter the object to notify of the parsed option and value. If null, the
* {@link OptionValue#setValue(Object)} method of the specified option is called
@@ -213,7 +213,7 @@
*
* This method verifies that the named field exists and is of an expected type. However, it does
* not verify that the timer or metric created has the same name of the field.
- *
+ *
* @param c the class in which the field is declared
* @param name the name of the field
*/
@@ -239,7 +239,7 @@
/**
* Called from VM code once all Graal command line options have been processed by
* {@link #setOption(String)}.
- *
+ *
* @param timeCompilations true if the CITime or CITimeEach HotSpot VM options are set
*/
public static void finalizeOptions(boolean timeCompilations) {
@@ -255,7 +255,7 @@
/**
* Wraps some given text to one or more lines of a given maximum width.
- *
+ *
* @param text text to wrap
* @param width maximum width of an output line, exception for words in {@code text} longer than
* this value
@@ -314,7 +314,7 @@
/**
* Compute string similarity based on Dice's coefficient.
- *
+ *
* Ported from str_similar() in globals.cpp.
*/
static float stringSimiliarity(String str1, String str2) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotReplacementsImpl.java Sat May 03 21:46:35 2014 +0200
@@ -86,16 +86,14 @@
HotSpotResolvedJavaMethod hsMethod = (HotSpotResolvedJavaMethod) method;
int intrinsicId = hsMethod.intrinsicId();
if (intrinsicId != 0) {
- if (intrinsicId == config.vmIntrinsicInvokeBasic) {
- return MethodHandleInvokeBasicNode.class;
- } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
- return MethodHandleLinkToInterfaceNode.class;
- } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
- return MethodHandleLinkToSpecialNode.class;
- } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
- return MethodHandleLinkToStaticNode.class;
- } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
- return MethodHandleLinkToVirtualNode.class;
+ /*
+ * The methods of MethodHandle that need substitution are signature-polymorphic, i.e.,
+ * the VM replicates them for every signature that they are actually used for.
+ * Therefore, we cannot use the usual annotation-driven mechanism to define the
+ * substitution.
+ */
+ if (MethodHandleNode.lookupMethodHandleIntrinsic(method) != null) {
+ return MethodHandleNode.class;
}
}
return super.getMacroSubstitution(method);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/HotSpotVMConfig.java Sat May 03 21:46:35 2014 +0200
@@ -1022,8 +1022,6 @@
* exceptions from Hsail back to C++ runtime.
*/
@HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_notice_safepoints", type = "jint*", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNoticeSafepointsOffset;
- @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[0]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset0;
- @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[1]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset1;
@HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_occurred", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptOccurredOffset;
@HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_never_ran_array", type = "jboolean *", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailNeverRanArrayOffset;
@HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_next_index", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailDeoptNextIndexOffset;
@@ -1035,7 +1033,10 @@
@HotSpotVMField(name = "HSAILFrame::_pc_offset", type = "jint", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFramePcOffset;
@HotSpotVMField(name = "HSAILFrame::_num_s_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumSRegOffset;
- @HotSpotVMField(name = "HSAILFrame::_save_area[0]", type = "jlong", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameSaveAreaOffset;
+ @HotSpotVMField(name = "HSAILFrame::_num_d_regs", type = "jbyte", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailFrameNumDRegOffset;
+ @HotSpotVMConstant(name = "sizeof(HSAILFrame)") @Stable public int hsailFrameSaveAreaOffset;
+ @HotSpotVMConstant(name = "sizeof(Hsail::HSAILKernelDeoptimization)") @Stable public int hsailKernelDeoptimizationHeaderSize;
+ @HotSpotVMField(name = "Hsail::HSAILDeoptimizationInfo::_deopt_save_states[0]", type = "Hsail::HSAILKernelDeoptimization", get = HotSpotVMField.Type.OFFSET) @Stable public int hsailSaveStatesOffset0;
/**
* Mark word right shift to get identity hash code.
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotMethodHandleAccessProvider.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2014, 2014, 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 com.oracle.graal.hotspot.meta;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.hotspot.*;
+
+public class HotSpotMethodHandleAccessProvider implements MethodHandleAccessProvider {
+
+ /**
+ * Lazy initialization to break class initialization cycle. Field and method lookup is only
+ * possible after the {@link HotSpotGraalRuntime} is fully initialized.
+ */
+ static class LazyInitialization {
+ static final ResolvedJavaField methodHandleFormField;
+ static final ResolvedJavaField lambdaFormVmentryField;
+ static final ResolvedJavaMethod lambdaFormCompileToBytecodeMethod;
+ static final ResolvedJavaField memberNameVmtargetField;
+
+ /**
+ * Search for an instance field with the given name in a class.
+ *
+ * @param className name of the class to search in
+ * @param fieldName name of the field to be searched
+ * @return resolved java field
+ * @throws ClassNotFoundException
+ */
+ private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
+ Class> clazz = Class.forName(className);
+ ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+ ResolvedJavaField[] fields = type.getInstanceFields(false);
+ for (ResolvedJavaField field : fields) {
+ if (field.getName().equals(fieldName)) {
+ return field;
+ }
+ }
+ return null;
+ }
+
+ private static ResolvedJavaMethod findMethodInClass(String className, String methodName) throws ClassNotFoundException {
+ Class> clazz = Class.forName(className);
+ ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
+ ResolvedJavaMethod result = null;
+ for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
+ if (method.getName().equals(methodName)) {
+ assert result == null : "more than one method found: " + className + "." + methodName;
+ result = method;
+ }
+ }
+ assert result != null : "method not found: " + className + "." + methodName;
+ return result;
+ }
+
+ static {
+ try {
+ methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
+ lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
+ lambdaFormCompileToBytecodeMethod = findMethodInClass("java.lang.invoke.LambdaForm", "compileToBytecode");
+ memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
+ } catch (Throwable ex) {
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ }
+ }
+
+ @Override
+ public IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+ int intrinsicId = ((HotSpotResolvedJavaMethod) method).intrinsicId();
+ if (intrinsicId != 0) {
+ HotSpotVMConfig config = runtime().getConfig();
+ if (intrinsicId == config.vmIntrinsicInvokeBasic) {
+ return IntrinsicMethod.INVOKE_BASIC;
+ } else if (intrinsicId == config.vmIntrinsicLinkToInterface) {
+ return IntrinsicMethod.LINK_TO_INTERFACE;
+ } else if (intrinsicId == config.vmIntrinsicLinkToSpecial) {
+ return IntrinsicMethod.LINK_TO_SPECIAL;
+ } else if (intrinsicId == config.vmIntrinsicLinkToStatic) {
+ return IntrinsicMethod.LINK_TO_STATIC;
+ } else if (intrinsicId == config.vmIntrinsicLinkToVirtual) {
+ return IntrinsicMethod.LINK_TO_VIRTUAL;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ResolvedJavaMethod resolveInvokeBasicTarget(Constant methodHandle, boolean forceBytecodeGeneration) {
+ if (methodHandle.isNull()) {
+ return null;
+ }
+
+ /* Load non-public field: LambdaForm MethodHandle.form */
+ Constant lambdaForm = LazyInitialization.methodHandleFormField.readValue(methodHandle);
+ if (lambdaForm.isNull()) {
+ return null;
+ }
+
+ Constant memberName;
+ if (forceBytecodeGeneration) {
+ /* Invoke non-public method: MemberName LambdaForm.compileToBytecode() */
+ memberName = LazyInitialization.lambdaFormCompileToBytecodeMethod.invoke(lambdaForm, new Constant[0]);
+ } else {
+ /* Load non-public field: MemberName LambdaForm.vmentry */
+ memberName = LazyInitialization.lambdaFormVmentryField.readValue(lambdaForm);
+ }
+ return getTargetMethod(memberName);
+ }
+
+ @Override
+ public ResolvedJavaMethod resolveLinkToTarget(Constant memberName) {
+ return getTargetMethod(memberName);
+ }
+
+ /**
+ * Returns the {@link ResolvedJavaMethod} for the vmtarget of a java.lang.invoke.MemberName.
+ */
+ private static ResolvedJavaMethod getTargetMethod(Constant memberName) {
+ if (memberName.isNull()) {
+ return null;
+ }
+
+ /* Load injected field: JVM_Method* MemberName.vmtarget */
+ Constant vmtarget = LazyInitialization.memberNameVmtargetField.readValue(memberName);
+ /* Create a method from the vmtarget method pointer. */
+ return HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotNmethod.java Sat May 03 21:46:35 2014 +0200
@@ -36,7 +36,7 @@
* instance to be anything but weak. This is due to the fact that HotSpot does not treat nmethods as
* strong GC roots.
*/
-public final class HotSpotNmethod extends HotSpotInstalledCode {
+public class HotSpotNmethod extends HotSpotInstalledCode {
/**
* This (indirect) Method* reference is safe since class redefinition preserves all methods
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotProviders.java Sat May 03 21:46:35 2014 +0200
@@ -38,15 +38,17 @@
private final SuitesProvider suites;
private final HotSpotRegistersProvider registers;
private final SnippetReflectionProvider snippetReflection;
+ private final HotSpotMethodHandleAccessProvider methodHandleAccess;
public HotSpotProviders(HotSpotMetaAccessProvider metaAccess, HotSpotCodeCacheProvider codeCache, ConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls,
LoweringProvider lowerer, Replacements replacements, HotSpotDisassemblerProvider disassembler, SuitesProvider suites, HotSpotRegistersProvider registers,
- SnippetReflectionProvider snippetReflection) {
+ SnippetReflectionProvider snippetReflection, HotSpotMethodHandleAccessProvider methodHandleAccess) {
super(metaAccess, codeCache, constantReflection, foreignCalls, lowerer, replacements);
this.disassembler = disassembler;
this.suites = suites;
this.registers = registers;
this.snippetReflection = snippetReflection;
+ this.methodHandleAccess = methodHandleAccess;
}
@Override
@@ -79,4 +81,8 @@
public SnippetReflectionProvider getSnippetReflection() {
return snippetReflection;
}
+
+ public HotSpotMethodHandleAccessProvider getMethodHandleAccess() {
+ return methodHandleAccess;
+ }
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/phases/AheadOfTimeVerificationPhase.java Sat May 03 21:46:35 2014 +0200
@@ -46,7 +46,7 @@
protected boolean verify(StructuredGraph graph, PhaseContext context) {
for (ConstantNode node : getConstantNodes(graph)) {
if (node.recordsUsages() || !node.gatherUsages(graph).isEmpty()) {
- if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node)) {
+ if (isObject(node) && !isNullReference(node) && !isInternedString(node) && !isDirectMethodHandle(node) && !isBoundMethodHandle(node)) {
throw new VerificationError("illegal object constant: " + node);
}
}
@@ -69,6 +69,13 @@
return "Ljava/lang/invoke/DirectMethodHandle;".equals(StampTool.typeOrNull(node).getName());
}
+ private static boolean isBoundMethodHandle(ConstantNode node) {
+ if (!isObject(node)) {
+ return false;
+ }
+ return StampTool.typeOrNull(node).getName().startsWith("Ljava/lang/invoke/BoundMethodHandle");
+ }
+
@SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want")
private static boolean isInternedString(ConstantNode node) {
if (!isObject(node)) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/AbstractMethodHandleNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.util.*;
-
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.hotspot.meta.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.replacements.nodes.*;
-
-/**
- * Common base class for method handle invoke nodes.
- */
-public abstract class AbstractMethodHandleNode extends MacroNode implements Canonicalizable {
-
- private static final ResolvedJavaField methodHandleFormField;
- private static final ResolvedJavaField lambdaFormVmentryField;
- private static final ResolvedJavaField memberNameClazzField;
- private static final ResolvedJavaField memberNameVmtargetField;
-
- // Replacement method data
- private ResolvedJavaMethod replacementTargetMethod;
- private JavaType replacementReturnType;
- @Input private final NodeInputList replacementArguments;
-
- /**
- * Search for an instance field with the given name in a class.
- *
- * @param className name of the class to search in
- * @param fieldName name of the field to be searched
- * @return resolved java field
- * @throws ClassNotFoundException
- */
- private static ResolvedJavaField findFieldInClass(String className, String fieldName) throws ClassNotFoundException {
- Class> clazz = Class.forName(className);
- ResolvedJavaType type = HotSpotResolvedObjectType.fromClass(clazz);
- ResolvedJavaField[] fields = type.getInstanceFields(false);
- for (ResolvedJavaField field : fields) {
- if (field.getName().equals(fieldName)) {
- return field;
- }
- }
- return null;
- }
-
- static {
- try {
- methodHandleFormField = findFieldInClass("java.lang.invoke.MethodHandle", "form");
- lambdaFormVmentryField = findFieldInClass("java.lang.invoke.LambdaForm", "vmentry");
- memberNameClazzField = findFieldInClass("java.lang.invoke.MemberName", "clazz");
- memberNameVmtargetField = findFieldInClass("java.lang.invoke.MemberName", "vmtarget");
- } catch (ClassNotFoundException | SecurityException ex) {
- throw GraalInternalError.shouldNotReachHere();
- }
- }
-
- public AbstractMethodHandleNode(Invoke invoke) {
- super(invoke);
-
- // See if we need to save some replacement method data.
- CallTargetNode callTarget = invoke.callTarget();
- if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
- SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
- replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
- replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
- replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
- } else {
- // NodeInputList can't be null.
- replacementArguments = new NodeInputList<>(this);
- }
- }
-
- /**
- * Get the receiver of a MethodHandle.invokeBasic call.
- *
- * @return the receiver argument node
- */
- private ValueNode getReceiver() {
- return arguments.first();
- }
-
- /**
- * Get the MemberName argument of a MethodHandle.linkTo* call.
- *
- * @return the MemberName argument node (which is the last argument)
- */
- private ValueNode getMemberName() {
- return arguments.last();
- }
-
- /**
- * Used from {@link MethodHandleInvokeBasicNode} to get the target {@link InvokeNode} if the
- * method handle receiver is constant.
- *
- * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
- */
- protected InvokeNode getInvokeBasicTarget() {
- ValueNode methodHandleNode = getReceiver();
- if (methodHandleNode.isConstant() && !methodHandleNode.isNullConstant()) {
- // Get the data we need from MethodHandle.LambdaForm.MemberName
- Constant methodHandle = methodHandleNode.asConstant();
- Constant lambdaForm = methodHandleFormField.readValue(methodHandle);
- Constant memberName = lambdaFormVmentryField.readValue(lambdaForm);
- return getTargetInvokeNode(memberName);
- }
- return null;
- }
-
- /**
- * Used from {@link MethodHandleLinkToStaticNode}, {@link MethodHandleLinkToSpecialNode},
- * {@link MethodHandleLinkToVirtualNode}, and {@link MethodHandleLinkToInterfaceNode} to get the
- * target {@link InvokeNode} if the member name argument is constant.
- *
- * @return invoke node for the member name target
- */
- protected InvokeNode getLinkToTarget() {
- ValueNode memberNameNode = getMemberName();
- if (memberNameNode.isConstant() && !memberNameNode.isNullConstant()) {
- Constant memberName = memberNameNode.asConstant();
- return getTargetInvokeNode(memberName);
- }
- return null;
- }
-
- /**
- * Helper function to get the {@link InvokeNode} for the vmtarget of a
- * java.lang.invoke.MemberName.
- *
- * @param memberName constant member name node
- * @return invoke node for the member name target
- */
- private InvokeNode getTargetInvokeNode(Constant memberName) {
- // Get the data we need from MemberName
- Constant clazz = memberNameClazzField.readValue(memberName);
- Constant vmtarget = memberNameVmtargetField.readValue(memberName);
-
- // Create a method from the vmtarget pointer
- Class> c = (Class>) HotSpotObjectConstant.asObject(clazz);
- HotSpotResolvedObjectType holderClass = (HotSpotResolvedObjectType) HotSpotResolvedObjectType.fromClass(c);
- HotSpotResolvedJavaMethod targetMethod = HotSpotResolvedJavaMethod.fromMetaspace(vmtarget.asLong());
-
- // In lambda forms we erase signature types to avoid resolving issues
- // involving class loaders. When we optimize a method handle invoke
- // to a direct call we must cast the receiver and arguments to its
- // actual types.
- HotSpotSignature signature = targetMethod.getSignature();
- final boolean isStatic = targetMethod.isStatic();
- final int receiverSkip = isStatic ? 0 : 1;
-
- // Cast receiver to its type.
- if (!isStatic) {
- JavaType receiverType = holderClass;
- maybeCastArgument(0, receiverType);
- }
-
- // Cast reference arguments to its type.
- for (int index = 0; index < signature.getParameterCount(false); index++) {
- JavaType parameterType = signature.getParameterType(index, holderClass);
- maybeCastArgument(receiverSkip + index, parameterType);
- }
-
- // Try to get the most accurate receiver type
- if (this instanceof MethodHandleLinkToVirtualNode || this instanceof MethodHandleLinkToInterfaceNode) {
- ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
- if (receiverType != null) {
- ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
- if (concreteMethod != null) {
- return createTargetInvokeNode(concreteMethod);
- }
- }
- }
-
- if (targetMethod.canBeStaticallyBound()) {
- return createTargetInvokeNode(targetMethod);
- }
-
- ResolvedJavaMethod concreteMethod = targetMethod.uniqueConcreteMethod();
- if (concreteMethod != null) {
- return createTargetInvokeNode(concreteMethod);
- }
-
- return null;
- }
-
- /**
- * Inserts a node to cast the argument at index to the given type if the given type is more
- * concrete than the argument type.
- *
- * @param index of the argument to be cast
- * @param type the type the argument should be cast to
- */
- private void maybeCastArgument(int index, JavaType type) {
- if (type instanceof ResolvedJavaType) {
- ResolvedJavaType targetType = (ResolvedJavaType) type;
- if (!targetType.isPrimitive()) {
- ValueNode argument = arguments.get(index);
- ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
- if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
- PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
- arguments.set(index, piNode);
- }
- }
- }
- }
-
- /**
- * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
- * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
- *
- * @param targetMethod the method the be called
- * @return invoke node for the member name target
- */
- private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
- InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
- JavaType returnType = targetMethod.getSignature().getReturnType(null);
-
- // MethodHandleLinkTo* nodes have a trailing MemberName argument which
- // needs to be popped.
- ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
- ValueNode[] targetArguments;
- if (this instanceof MethodHandleInvokeBasicNode) {
- targetArguments = originalArguments;
- } else {
- assert this instanceof MethodHandleLinkToStaticNode || this instanceof MethodHandleLinkToSpecialNode || this instanceof MethodHandleLinkToVirtualNode ||
- this instanceof MethodHandleLinkToInterfaceNode : this;
- targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
- }
-
- // If there is already replacement information, use that instead.
- MethodCallTargetNode callTarget;
- if (replacementTargetMethod == null) {
- callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
- } else {
- ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
- callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
- }
- graph().add(callTarget);
-
- // The call target can have a different return type than the invoker,
- // e.g. the target returns an Object but the invoker void. In this case
- // we need to use the stamp of the invoker. Note: always using the
- // invoker's stamp would be wrong because it's a less concrete type
- // (usually java.lang.Object).
- InvokeNode invoke;
- if (stamp() == StampFactory.forVoid()) {
- invoke = new InvokeNode(callTarget, getBci(), stamp());
- } else {
- invoke = new InvokeNode(callTarget, getBci());
- }
- graph().add(invoke);
- invoke.setStateAfter(stateAfter());
- return invoke;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleInvokeBasicNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .invokeBasic(Object...)}.
- */
-public class MethodHandleInvokeBasicNode extends AbstractMethodHandleNode {
-
- public MethodHandleInvokeBasicNode(Invoke invoke) {
- super(invoke);
- }
-
- @Override
- public Node canonical(CanonicalizerTool tool) {
- InvokeNode invoke = getInvokeBasicTarget();
- if (invoke != null) {
- return invoke;
- }
- return this;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToInterfaceNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToInterface(Object...)}.
- */
-public class MethodHandleLinkToInterfaceNode extends AbstractMethodHandleNode {
-
- public MethodHandleLinkToInterfaceNode(Invoke invoke) {
- super(invoke);
- }
-
- @Override
- public Node canonical(CanonicalizerTool tool) {
- InvokeNode invoke = getLinkToTarget();
- if (invoke != null) {
- return invoke;
- }
- return this;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToSpecialNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToSpecial(Object...)}.
- */
-public class MethodHandleLinkToSpecialNode extends AbstractMethodHandleNode {
-
- public MethodHandleLinkToSpecialNode(Invoke invoke) {
- super(invoke);
- }
-
- @Override
- public Node canonical(CanonicalizerTool tool) {
- InvokeNode invoke = getLinkToTarget();
- if (invoke != null) {
- return invoke;
- }
- return this;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToStaticNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToStatic(Object...)}.
- */
-public class MethodHandleLinkToStaticNode extends AbstractMethodHandleNode {
-
- public MethodHandleLinkToStaticNode(Invoke invoke) {
- super(invoke);
- }
-
- @Override
- public Node canonical(CanonicalizerTool tool) {
- InvokeNode invoke = getLinkToTarget();
- if (invoke != null) {
- return invoke;
- }
- return this;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleLinkToVirtualNode.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
-
-import java.lang.invoke.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.spi.*;
-import com.oracle.graal.nodes.*;
-
-/**
- * Macro node for {@link MethodHandle}{@code .linkToVirtual(Object...)}.
- */
-public class MethodHandleLinkToVirtualNode extends AbstractMethodHandleNode {
-
- public MethodHandleLinkToVirtualNode(Invoke invoke) {
- super(invoke);
- }
-
- @Override
- public Node canonical(CanonicalizerTool tool) {
- InvokeNode invoke = getLinkToTarget();
- if (invoke != null) {
- return invoke;
- }
- return this;
- }
-
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MethodHandleNode.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.hotspot.replacements;
+
+import static com.oracle.graal.hotspot.HotSpotGraalRuntime.*;
+
+import java.lang.invoke.*;
+import java.util.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.replacements.*;
+import com.oracle.graal.api.replacements.MethodHandleAccessProvider.IntrinsicMethod;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.spi.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.replacements.nodes.*;
+
+/**
+ * Node for invocation methods defined on the class {@link MethodHandle}.
+ */
+public class MethodHandleNode extends MacroNode implements Canonicalizable {
+
+ /** The method that this node is representing. */
+ private final IntrinsicMethod intrinsicMethod;
+
+ // Replacement method data
+ private ResolvedJavaMethod replacementTargetMethod;
+ private JavaType replacementReturnType;
+ @Input private final NodeInputList replacementArguments;
+
+ public MethodHandleNode(Invoke invoke) {
+ super(invoke);
+
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ intrinsicMethod = lookupMethodHandleIntrinsic(callTarget.targetMethod());
+ assert intrinsicMethod != null;
+
+ // See if we need to save some replacement method data.
+ if (callTarget instanceof SelfReplacingMethodCallTargetNode) {
+ SelfReplacingMethodCallTargetNode selfReplacingMethodCallTargetNode = (SelfReplacingMethodCallTargetNode) callTarget;
+ replacementTargetMethod = selfReplacingMethodCallTargetNode.replacementTargetMethod();
+ replacementReturnType = selfReplacingMethodCallTargetNode.replacementReturnType();
+ replacementArguments = selfReplacingMethodCallTargetNode.replacementArguments();
+ } else {
+ // NodeInputList can't be null.
+ replacementArguments = new NodeInputList<>(this);
+ }
+ }
+
+ /**
+ * Returns the method handle method intrinsic identifier for the provided method, or
+ * {@code null} if the method is not a method that can be handled by this class.
+ */
+ public static IntrinsicMethod lookupMethodHandleIntrinsic(ResolvedJavaMethod method) {
+ return methodHandleAccess().lookupMethodHandleIntrinsic(method);
+ }
+
+ @Override
+ public Node canonical(CanonicalizerTool tool) {
+ InvokeNode invoke;
+ switch (intrinsicMethod) {
+ case INVOKE_BASIC:
+ invoke = getInvokeBasicTarget();
+ break;
+ case LINK_TO_STATIC:
+ case LINK_TO_SPECIAL:
+ case LINK_TO_VIRTUAL:
+ case LINK_TO_INTERFACE:
+ invoke = getLinkToTarget();
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+ if (invoke != null) {
+ return invoke;
+ }
+ return this;
+ }
+
+ /**
+ * Get the receiver of a MethodHandle.invokeBasic call.
+ *
+ * @return the receiver argument node
+ */
+ private ValueNode getReceiver() {
+ return arguments.first();
+ }
+
+ /**
+ * Get the MemberName argument of a MethodHandle.linkTo* call.
+ *
+ * @return the MemberName argument node (which is the last argument)
+ */
+ private ValueNode getMemberName() {
+ return arguments.last();
+ }
+
+ /**
+ * Returns the {@link MethodHandleAccessProvider} that provides introspection of internal
+ * {@link MethodHandle} data.
+ */
+ private static MethodHandleAccessProvider methodHandleAccess() {
+ return runtime().getHostProviders().getMethodHandleAccess();
+ }
+
+ /**
+ * Used for the MethodHandle.invokeBasic method (the {@link IntrinsicMethod#INVOKE_BASIC }
+ * method) to get the target {@link InvokeNode} if the method handle receiver is constant.
+ *
+ * @return invoke node for the {@link java.lang.invoke.MethodHandle} target
+ */
+ protected InvokeNode getInvokeBasicTarget() {
+ ValueNode methodHandleNode = getReceiver();
+ if (methodHandleNode.isConstant()) {
+ return getTargetInvokeNode(methodHandleAccess().resolveInvokeBasicTarget(methodHandleNode.asConstant(), false));
+ }
+ return null;
+ }
+
+ /**
+ * Used for the MethodHandle.linkTo* methods (the {@link IntrinsicMethod#LINK_TO_STATIC},
+ * {@link IntrinsicMethod#LINK_TO_SPECIAL}, {@link IntrinsicMethod#LINK_TO_VIRTUAL}, and
+ * {@link IntrinsicMethod#LINK_TO_INTERFACE} methods) to get the target {@link InvokeNode} if
+ * the member name argument is constant.
+ *
+ * @return invoke node for the member name target
+ */
+ protected InvokeNode getLinkToTarget() {
+ ValueNode memberNameNode = getMemberName();
+ if (memberNameNode.isConstant()) {
+ return getTargetInvokeNode(methodHandleAccess().resolveLinkToTarget(memberNameNode.asConstant()));
+ }
+ return null;
+ }
+
+ /**
+ * Helper function to get the {@link InvokeNode} for the targetMethod of a
+ * java.lang.invoke.MemberName.
+ *
+ * @param targetMethod the target, already loaded from the member name node
+ * @return invoke node for the member name target
+ */
+ private InvokeNode getTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+ if (targetMethod == null) {
+ return null;
+ }
+
+ // In lambda forms we erase signature types to avoid resolving issues
+ // involving class loaders. When we optimize a method handle invoke
+ // to a direct call we must cast the receiver and arguments to its
+ // actual types.
+ Signature signature = targetMethod.getSignature();
+ final boolean isStatic = targetMethod.isStatic();
+ final int receiverSkip = isStatic ? 0 : 1;
+
+ // Cast receiver to its type.
+ if (!isStatic) {
+ JavaType receiverType = targetMethod.getDeclaringClass();
+ maybeCastArgument(0, receiverType);
+ }
+
+ // Cast reference arguments to its type.
+ for (int index = 0; index < signature.getParameterCount(false); index++) {
+ JavaType parameterType = signature.getParameterType(index, targetMethod.getDeclaringClass());
+ maybeCastArgument(receiverSkip + index, parameterType);
+ }
+
+ // Try to get the most accurate receiver type
+ if (intrinsicMethod == IntrinsicMethod.LINK_TO_VIRTUAL || intrinsicMethod == IntrinsicMethod.LINK_TO_INTERFACE) {
+ ResolvedJavaType receiverType = StampTool.typeOrNull(getReceiver().stamp());
+ if (receiverType != null) {
+ ResolvedJavaMethod concreteMethod = receiverType.findUniqueConcreteMethod(targetMethod);
+ if (concreteMethod != null) {
+ return createTargetInvokeNode(concreteMethod);
+ }
+ }
+ }
+
+ if (targetMethod.canBeStaticallyBound()) {
+ return createTargetInvokeNode(targetMethod);
+ }
+
+ ResolvedJavaMethod concreteMethod = targetMethod.getDeclaringClass().findUniqueConcreteMethod(targetMethod);
+ if (concreteMethod != null) {
+ return createTargetInvokeNode(concreteMethod);
+ }
+
+ return null;
+ }
+
+ /**
+ * Inserts a node to cast the argument at index to the given type if the given type is more
+ * concrete than the argument type.
+ *
+ * @param index of the argument to be cast
+ * @param type the type the argument should be cast to
+ */
+ private void maybeCastArgument(int index, JavaType type) {
+ if (type instanceof ResolvedJavaType) {
+ ResolvedJavaType targetType = (ResolvedJavaType) type;
+ if (!targetType.isPrimitive()) {
+ ValueNode argument = arguments.get(index);
+ ResolvedJavaType argumentType = StampTool.typeOrNull(argument.stamp());
+ if (argumentType == null || (argumentType.isAssignableFrom(targetType) && !argumentType.equals(targetType))) {
+ PiNode piNode = graph().unique(new PiNode(argument, StampFactory.declared(targetType)));
+ arguments.set(index, piNode);
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates an {@link InvokeNode} for the given target method. The {@link CallTargetNode} passed
+ * to the InvokeNode is in fact a {@link SelfReplacingMethodCallTargetNode}.
+ *
+ * @param targetMethod the method the be called
+ * @return invoke node for the member name target
+ */
+ private InvokeNode createTargetInvokeNode(ResolvedJavaMethod targetMethod) {
+ InvokeKind invokeKind = targetMethod.isStatic() ? InvokeKind.Static : InvokeKind.Special;
+ JavaType returnType = targetMethod.getSignature().getReturnType(null);
+
+ // MethodHandleLinkTo* nodes have a trailing MemberName argument which
+ // needs to be popped.
+ ValueNode[] originalArguments = arguments.toArray(new ValueNode[arguments.size()]);
+ ValueNode[] targetArguments;
+ switch (intrinsicMethod) {
+ case INVOKE_BASIC:
+ targetArguments = originalArguments;
+ break;
+ case LINK_TO_STATIC:
+ case LINK_TO_SPECIAL:
+ case LINK_TO_VIRTUAL:
+ case LINK_TO_INTERFACE:
+ targetArguments = Arrays.copyOfRange(originalArguments, 0, arguments.size() - 1);
+ break;
+ default:
+ throw GraalInternalError.shouldNotReachHere();
+ }
+
+ // If there is already replacement information, use that instead.
+ MethodCallTargetNode callTarget;
+ if (replacementTargetMethod == null) {
+ callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, getTargetMethod(), originalArguments, getReturnType());
+ } else {
+ ValueNode[] args = replacementArguments.toArray(new ValueNode[replacementArguments.size()]);
+ callTarget = new SelfReplacingMethodCallTargetNode(invokeKind, targetMethod, targetArguments, returnType, replacementTargetMethod, args, replacementReturnType);
+ }
+ graph().add(callTarget);
+
+ // The call target can have a different return type than the invoker,
+ // e.g. the target returns an Object but the invoker void. In this case
+ // we need to use the stamp of the invoker. Note: always using the
+ // invoker's stamp would be wrong because it's a less concrete type
+ // (usually java.lang.Object).
+ InvokeNode invoke;
+ if (stamp() == StampFactory.forVoid()) {
+ invoke = new InvokeNode(callTarget, getBci(), stamp());
+ } else {
+ invoke = new InvokeNode(callTarget, getBci());
+ }
+ graph().add(invoke);
+ invoke.setStateAfter(stateAfter());
+ return invoke;
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/MonitorSnippets.java Sat May 03 21:46:35 2014 +0200
@@ -47,7 +47,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.nodes.type.*;
import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.replacements.*;
import com.oracle.graal.replacements.Snippet.ConstantParameter;
import com.oracle.graal.replacements.Snippet.Fold;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java
--- a/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.hsail/src/com/oracle/graal/hsail/HSAIL.java Sat May 03 21:46:35 2014 +0200
@@ -136,7 +136,6 @@
public static final Register threadRegister = d20;
public static final Register actionAndReasonReg = s32;
public static final Register codeBufferOffsetReg = s33;
- public static final Register dregOopMapReg = s39;
// @formatter:off
public static final Register[] cRegisters = {
@@ -178,10 +177,16 @@
return -(((StackSlot) reg).getRawOffset());
}
- public static String mapStackSlot(Value reg) {
- StackSlot s = (StackSlot) reg;
- long offset = -s.getRawOffset();
- return "[%spillseg]" + "[" + offset + "]";
+ /**
+ * The mapping to stack slots is always relative to the beginning of the spillseg.
+ * {@link #getStackOffset(Value)} returns the positive version of the originally negative
+ * offset. Then we back up from that by {@code argSize} in bytes. This ensures that slots of
+ * different size do not overlap, even though we have converted from negative to positive
+ * offsets.
+ */
+ public static int getStackOffsetStart(Value reg, int argSize) {
+ int argSizeInBytes = argSize / 8;
+ return getStackOffset(reg) - argSizeInBytes;
}
public static String mapRegister(Value arg) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/BciBlockMapping.java Sat May 03 21:46:35 2014 +0200
@@ -177,6 +177,10 @@
public BciBlock getPredecessor(int index) {
return predecessors.get(index);
}
+
+ public double probability() {
+ return 1D;
+ }
}
public static class ExceptionDispatchBlock extends BciBlock {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/ComputeLoopFrequenciesClosure.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011, 2014, 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 com.oracle.graal.java;
+
+import java.util.*;
+import java.util.stream.*;
+
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.phases.graph.*;
+
+public class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure {
+
+ private static final double EPSILON = Double.MIN_NORMAL;
+ private static final ComputeLoopFrequenciesClosure INSTANCE = new ComputeLoopFrequenciesClosure();
+
+ private ComputeLoopFrequenciesClosure() {
+ // nothing to do
+ }
+
+ @Override
+ protected Double processNode(FixedNode node, Double currentState) {
+ // normal nodes never change the probability of a path
+ return currentState;
+ }
+
+ @Override
+ protected Double merge(MergeNode merge, List states) {
+ // a merge has the sum of all predecessor probabilities
+ return states.stream().collect(Collectors.summingDouble(d -> d));
+ }
+
+ @Override
+ protected Double afterSplit(BeginNode node, Double oldState) {
+ // a control split splits up the probability
+ ControlSplitNode split = (ControlSplitNode) node.predecessor();
+ return oldState * split.probability(node);
+ }
+
+ @Override
+ protected Map processLoop(LoopBeginNode loop, Double initialState) {
+ Map exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates;
+
+ double exitProbability = exitStates.values().stream().mapToDouble(d -> d).sum();
+ assert exitProbability <= 1D && exitProbability >= 0D;
+ if (exitProbability < EPSILON) {
+ exitProbability = EPSILON;
+ }
+ double loopFrequency = 1D / exitProbability;
+ loop.setLoopFrequency(loopFrequency);
+
+ double adjustmentFactor = initialState * loopFrequency;
+ exitStates.replaceAll((exitNode, probability) -> multiplySaturate(probability, adjustmentFactor));
+
+ return exitStates;
+ }
+
+ /**
+ * Multiplies a and b and saturates the result to 1/{@link Double#MIN_NORMAL}.
+ *
+ * @return a times b saturated to 1/{@link Double#MIN_NORMAL}
+ */
+ public static double multiplySaturate(double a, double b) {
+ double r = a * b;
+ if (r > 1 / Double.MIN_NORMAL) {
+ return 1 / Double.MIN_NORMAL;
+ }
+ return r;
+ }
+
+ /**
+ * Computes the frequencies of all loops in the given graph. This is done by performing a
+ * reverse postorder iteration and computing the probability of all fixed nodes. The combined
+ * probability of all exits of a loop can be used to compute the loop's expected frequency.
+ */
+ public static void compute(StructuredGraph graph) {
+ if (graph.hasLoops()) {
+ ReentrantNodeIterator.apply(INSTANCE, graph.start(), 1D);
+ }
+ }
+
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java
--- a/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.java/src/com/oracle/graal/java/GraphBuilderPhase.java Sat May 03 21:46:35 2014 +0200
@@ -26,6 +26,7 @@
import static com.oracle.graal.api.meta.DeoptimizationReason.*;
import static com.oracle.graal.bytecode.Bytecodes.*;
import static com.oracle.graal.compiler.common.GraalOptions.*;
+
import java.util.*;
import com.oracle.graal.api.code.*;
@@ -158,6 +159,8 @@
filter.remove();
}
parser = null;
+
+ ComputeLoopFrequenciesClosure.compute(graph);
}
@Override
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILArithmetic.java Sat May 03 21:46:35 2014 +0200
@@ -108,7 +108,7 @@
private final String from;
private final String to;
@Def({REG}) protected AllocatableValue result;
- @Use({REG, STACK}) protected AllocatableValue x;
+ @Use({REG}) protected AllocatableValue x;
public ConvertOp(AllocatableValue result, AllocatableValue x, String to, String from) {
this.from = from;
@@ -123,52 +123,10 @@
}
}
- public static class Op1Stack extends HSAILLIRInstruction {
- @Opcode private final HSAILArithmetic opcode;
- @Def({REG, HINT}) protected Value result;
- @Use({REG, STACK, CONST}) protected Value x;
-
- public Op1Stack(HSAILArithmetic opcode, Value result, Value x) {
- this.opcode = opcode;
- this.result = result;
- this.x = x;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
- emit(crb, masm, opcode, result, x, null);
- }
- }
-
- public static class Op2Stack extends HSAILLIRInstruction {
+ public static class Op1Reg extends HSAILLIRInstruction {
@Opcode private final HSAILArithmetic opcode;
@Def({REG, HINT}) protected Value result;
@Use({REG, CONST}) protected Value x;
- @Alive({REG, CONST}) protected Value y;
-
- public Op2Stack(HSAILArithmetic opcode, Value result, Value x, Value y) {
- this.opcode = opcode;
- this.result = result;
- this.x = x;
- this.y = y;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
- emit(crb, masm, opcode, result, x, y, null);
- }
-
- @Override
- public void verify() {
- super.verify();
- verifyKind(opcode, result, x, y);
- }
- }
-
- public static class Op1Reg extends HSAILLIRInstruction {
- @Opcode private final HSAILArithmetic opcode;
- @Def({REG, HINT}) protected Value result;
- @Use({REG}) protected Value x;
public Op1Reg(HSAILArithmetic opcode, Value result, Value x) {
this.opcode = opcode;
@@ -185,7 +143,7 @@
public static class Op2Reg extends HSAILLIRInstruction {
@Opcode private final HSAILArithmetic opcode;
@Def({REG, HINT}) protected Value result;
- @Use({REG, STACK, CONST}) protected Value x;
+ @Use({REG, CONST}) protected Value x;
@Alive({REG, CONST}) protected Value y;
public Op2Reg(HSAILArithmetic opcode, Value result, Value x, Value y) {
@@ -207,35 +165,10 @@
}
}
- public static class Op2RegCommutative extends HSAILLIRInstruction {
- @Opcode private final HSAILArithmetic opcode;
- @Def({REG, HINT}) protected Value result;
- @Use({REG, STACK, CONST}) protected Value x;
- @Use({REG, CONST}) protected Value y;
-
- public Op2RegCommutative(HSAILArithmetic opcode, Value result, Value x, Value y) {
- this.opcode = opcode;
- this.result = result;
- this.x = x;
- this.y = y;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, HSAILAssembler masm) {
- throw GraalInternalError.shouldNotReachHere();
- }
-
- @Override
- protected void verify() {
- super.verify();
- verifyKind(opcode, result, x, y);
- }
- }
-
public static class ShiftOp extends HSAILLIRInstruction {
@Opcode private final HSAILArithmetic opcode;
@Def({REG, HINT}) protected Value result;
- @Use({REG, STACK, CONST}) protected Value x;
+ @Use({REG, CONST}) protected Value x;
@Alive({REG, CONST}) protected Value y;
public ShiftOp(HSAILArithmetic opcode, Value result, Value x, Value y) {
@@ -295,7 +228,7 @@
/**
* Emits the HSAIL code for an arithmetic operation taking one input parameter.
- *
+ *
* @param crb the CompilationResultBuilder
* @param masm the HSAIL assembler
* @param opcode the opcode of the arithmetic operation
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILCompare.java Sat May 03 21:46:35 2014 +0200
@@ -50,8 +50,8 @@
public static class CompareOp extends HSAILLIRInstruction {
@Opcode private final HSAILCompare opcode;
- @Use({REG, STACK, CONST}) protected Value x;
- @Use({REG, STACK, CONST}) protected Value y;
+ @Use({REG, CONST}) protected Value x;
+ @Use({REG, CONST}) protected Value y;
@Def({REG}) protected Value z;
private final Condition condition;
public boolean unordered = false;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILControlFlow.java Sat May 03 21:46:35 2014 +0200
@@ -146,7 +146,6 @@
protected MetaAccessProvider metaAccessProvider;
protected String emitName;
protected int codeBufferPos = -1;
- protected int dregOopMap = 0;
public DeoptimizeOp(Value actionAndReason, LIRFrameState frameState, String emitName, MetaAccessProvider metaAccessProvider) {
super(Value.ILLEGAL); // return with no ret value
@@ -181,20 +180,10 @@
masm.emitComment("/* HSAIL Deoptimization pos=" + codeBufferPos + ", bci=" + frameState.debugInfo().getBytecodePosition().getBCI() + ", frameState=" + frameState + " */");
- // get the bitmap of $d regs that contain references
- ReferenceMap referenceMap = frameState.debugInfo().getReferenceMap();
- for (int dreg = HSAIL.d0.number; dreg <= HSAIL.d15.number; dreg++) {
- if (referenceMap.getRegister(dreg) == Kind.Object) {
- dregOopMap |= 1 << (dreg - HSAIL.d0.number);
- }
- }
-
AllocatableValue actionAndReasonReg = HSAIL.actionAndReasonReg.asValue(Kind.Int);
AllocatableValue codeBufferOffsetReg = HSAIL.codeBufferOffsetReg.asValue(Kind.Int);
- AllocatableValue dregOopMapReg = HSAIL.dregOopMapReg.asValue(Kind.Int);
masm.emitMov(Kind.Int, actionAndReasonReg, actionAndReason);
masm.emitMov(Kind.Int, codeBufferOffsetReg, Constant.forInt(codeBufferPos));
- masm.emitMov(Kind.Int, dregOopMapReg, Constant.forInt(dregOopMap));
masm.emitJumpToLabelName(masm.getDeoptLabelName());
// now record the debuginfo
@@ -305,10 +294,10 @@
@Opcode protected final HSAILCompare opcode;
@Def({REG, HINT}) protected Value result;
- @Use({REG, STACK, CONST}) protected Value trueValue;
- @Use({REG, STACK, CONST}) protected Value falseValue;
- @Use({REG, STACK, CONST}) protected Value left;
- @Use({REG, STACK, CONST}) protected Value right;
+ @Use({REG, CONST}) protected Value trueValue;
+ @Use({REG, CONST}) protected Value falseValue;
+ @Use({REG, CONST}) protected Value left;
+ @Use({REG, CONST}) protected Value right;
protected final Condition condition;
public CondMoveOp(HSAILCompare opcode, Variable left, Variable right, Variable result, Condition condition, Value trueValue, Value falseValue) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java
--- a/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.lir.hsail/src/com/oracle/graal/lir/hsail/HSAILMove.java Sat May 03 21:46:35 2014 +0200
@@ -63,29 +63,6 @@
}
@Opcode("MOVE")
- public static class SpillMoveOp extends AbstractMoveOp {
-
- @Def({REG, STACK}) protected AllocatableValue result;
- @Use({REG, STACK, CONST}) protected Value input;
-
- public SpillMoveOp(Kind moveKind, AllocatableValue result, Value input) {
- super(moveKind);
- this.result = result;
- this.input = input;
- }
-
- @Override
- public Value getInput() {
- return input;
- }
-
- @Override
- public AllocatableValue getResult() {
- return result;
- }
- }
-
- @Opcode("MOVE")
public static class MoveToRegOp extends AbstractMoveOp {
@Def({REG, HINT}) protected AllocatableValue result;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopPolicies.java Sat May 03 21:46:35 2014 +0200
@@ -24,11 +24,12 @@
import static com.oracle.graal.compiler.common.GraalOptions.*;
+import java.util.function.*;
+
import com.oracle.graal.debug.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
public abstract class LoopPolicies {
@@ -37,12 +38,12 @@
}
// TODO (gd) change when inversion is available
- public static boolean shouldPeel(LoopEx loop, NodesToDoubles probabilities) {
+ public static boolean shouldPeel(LoopEx loop, ToDoubleFunction probabilities) {
if (loop.detectCounted()) {
return false;
}
LoopBeginNode loopBegin = loop.loopBegin();
- double entryProbability = probabilities.get(loopBegin.forwardEnd());
+ double entryProbability = probabilities.applyAsDouble(loopBegin.forwardEnd());
return entryProbability > MinimumPeelProbability.getValue() && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue();
}
@@ -70,10 +71,8 @@
double maxProbability = 0;
for (Node successor : controlSplit.successors()) {
BeginNode branch = (BeginNode) successor;
- inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality(); // this may count
- // twice because
- // of fall-through
- // in switches
+ // this may count twice because of fall-through in switches
+ inBranchTotal += loop.nodesInLoopFrom(branch, postDom).cardinality();
double probability = controlSplit.probability(branch);
if (probability > maxProbability) {
maxProbability = probability;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/phases/LoopTransformHighPhase.java Sat May 03 21:46:35 2014 +0200
@@ -24,10 +24,11 @@
import static com.oracle.graal.compiler.common.GraalOptions.*;
+import java.util.function.*;
+
import com.oracle.graal.debug.*;
import com.oracle.graal.loop.*;
import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.graph.*;
@@ -37,7 +38,7 @@
protected void run(StructuredGraph graph) {
if (graph.hasLoops()) {
if (LoopPeeling.getValue()) {
- NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
+ ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
LoopsData data = new LoopsData(graph);
for (LoopEx loop : data.outterFirst()) {
if (LoopPolicies.shouldPeel(loop, probabilities)) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/BeginNode.java Sat May 03 21:46:35 2014 +0200
@@ -32,6 +32,7 @@
import com.oracle.graal.graph.spi.*;
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.util.*;
@NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
public class BeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, GuardingNode, AnchoringNode, IterableNodeType {
@@ -69,12 +70,8 @@
}
public static BeginNode prevBegin(FixedNode from) {
- Node prevBegin = from;
- while (prevBegin != null) {
- if (prevBegin instanceof BeginNode) {
- return (BeginNode) prevBegin;
- }
- prevBegin = prevBegin.predecessor();
+ for (BeginNode begin : GraphUtil.predecessorIterable(from).filter(BeginNode.class)) {
+ return begin;
}
return null;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/InvokeNode.java Sat May 03 21:46:35 2014 +0200
@@ -36,7 +36,7 @@
* The {@code InvokeNode} represents all kinds of method calls.
*/
@NodeInfo(nameTemplate = "Invoke#{p#targetMethod/s}", allowedUsageTypes = {InputType.Memory})
-public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single {
+public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke, LIRLowerable, MemoryCheckpoint.Single, IterableNodeType {
@Input(InputType.Extension) private CallTargetNode callTarget;
@Input(InputType.State) private FrameState stateDuring;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/MergeNode.java Sat May 03 21:46:35 2014 +0200
@@ -107,7 +107,7 @@
ends.clear();
}
- public NodeIterable forwardEnds() {
+ public NodeInputList forwardEnds() {
return ends;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/StructuredGraph.java Sat May 03 21:46:35 2014 +0200
@@ -231,7 +231,7 @@
}
public boolean hasLoops() {
- return getNodes(LoopBeginNode.class).isNotEmpty();
+ return hasNode(LoopBeginNode.class);
}
public void removeFloating(FloatingNode node) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/calc/CompareNode.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,7 @@
package com.oracle.graal.nodes.calc;
import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.ProfilingInfo.*;
+import com.oracle.graal.api.meta.ProfilingInfo.TriState;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.calc.*;
import com.oracle.graal.graph.*;
@@ -92,8 +92,8 @@
@Override
public TriState evaluate(ConstantReflectionProvider constantReflection, ValueNode forX, ValueNode forY) {
- if (x().isConstant() && y().isConstant()) {
- return TriState.get(condition().foldCondition(x().asConstant(), y().asConstant(), constantReflection, unorderedIsTrue()));
+ if (forX.isConstant() && forY.isConstant()) {
+ return TriState.get(condition().foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue()));
}
return TriState.UNKNOWN;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/Block.java Sat May 03 21:46:35 2014 +0200
@@ -33,6 +33,8 @@
protected final BeginNode beginNode;
protected FixedNode endNode;
+
+ protected double probability;
protected Loop loop;
protected List dominated;
@@ -175,4 +177,11 @@
return getDominator().isDominatedBy(block);
}
+ public double probability() {
+ return probability;
+ }
+
+ public void setProbability(double probability) {
+ this.probability = probability;
+ }
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/BlocksToDoubles.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.nodes.cfg;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-
-public class BlocksToDoubles {
-
- private final IdentityHashMap, Double> nodeProbabilities;
-
- public BlocksToDoubles(int numberOfNodes) {
- this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
- }
-
- public void put(AbstractBlock> n, double value) {
- assert value >= 0.0 : value;
- nodeProbabilities.put(n, value);
- }
-
- public boolean contains(AbstractBlock> n) {
- return nodeProbabilities.containsKey(n);
- }
-
- public double get(AbstractBlock> n) {
- Double value = nodeProbabilities.get(n);
- assert value != null;
- return value;
- }
-
- public static BlocksToDoubles createFromNodeProbability(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg) {
- BlocksToDoubles blockProbabilities = new BlocksToDoubles(cfg.getBlocks().length);
- for (Block block : cfg.getBlocks()) {
- blockProbabilities.put(block, nodeProbabilities.get(block.getBeginNode()));
- }
- assert verify(nodeProbabilities, cfg, blockProbabilities) : "Probabilities differ for nodes in the same block.";
- return blockProbabilities;
- }
-
- private static boolean verify(NodesToDoubles nodeProbabilities, ControlFlowGraph cfg, BlocksToDoubles blockProbabilities) {
- for (Block b : cfg.getBlocks()) {
- double p = blockProbabilities.get(b);
- for (FixedNode n : b.getNodes()) {
- if (nodeProbabilities.get(n) != p) {
- return false;
- }
- }
- }
- return true;
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/cfg/ControlFlowGraph.java Sat May 03 21:46:35 2014 +0200
@@ -200,14 +200,21 @@
private void connectBlocks() {
for (Block block : reversePostOrder) {
List predecessors = new ArrayList<>(4);
+ double probability = 0;
for (Node predNode : block.getBeginNode().cfgPredecessors()) {
Block predBlock = nodeToBlock.get(predNode);
if (predBlock.getId() >= 0) {
predecessors.add(predBlock);
+ probability += predBlock.probability;
}
}
+ if (predecessors.size() == 1 && predecessors.get(0).getEndNode() instanceof ControlSplitNode) {
+ probability *= ((ControlSplitNode) predecessors.get(0).getEndNode()).probability(block.getBeginNode());
+ }
if (block.getBeginNode() instanceof LoopBeginNode) {
- for (LoopEndNode predNode : ((LoopBeginNode) block.getBeginNode()).orderedLoopEnds()) {
+ LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode();
+ probability *= loopBegin.loopFrequency();
+ for (LoopEndNode predNode : loopBegin.orderedLoopEnds()) {
Block predBlock = nodeToBlock.get(predNode);
if (predBlock.getId() >= 0) {
predecessors.add(predBlock);
@@ -215,6 +222,7 @@
}
}
block.setPredecessors(predecessors);
+ block.setProbability(probability);
List successors = new ArrayList<>(4);
for (Node suxNode : block.getEndNode().cfgSuccessors()) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java Sat May 03 21:46:35 2014 +0200
@@ -73,7 +73,8 @@
if (merge != null) {
merge.removeEnd(end);
StructuredGraph graph = end.graph();
- if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { // dead loop
+ if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) {
+ // dead loop
for (PhiNode phi : merge.phis().snapshot()) {
propagateKill(phi);
}
@@ -93,13 +94,13 @@
} else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) {
// not a loop anymore
if (tool != null) {
- merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+ merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
}
graph.reduceDegenerateLoopBegin((LoopBeginNode) merge);
} else if (merge.phiPredecessorCount() == 1) {
// not a merge anymore
if (tool != null) {
- merge.phis().forEach(phi -> phi.usages().forEach(usage -> tool.addToWorkList(usage)));
+ merge.phis().forEach(phi -> phi.usages().forEach(tool::addToWorkList));
}
graph.reduceTrivialMerge(merge);
}
@@ -408,4 +409,32 @@
return true;
}
}
+
+ /**
+ * Returns an iterator that will return the given node followed by all its predecessors, up
+ * until the point where {@link Node#predecessor()} returns null;
+ *
+ * @param start the node at which to start iterating
+ */
+ public static NodeIterable predecessorIterable(final FixedNode start) {
+ return new NodeIterable() {
+ public Iterator iterator() {
+ return new Iterator() {
+ public FixedNode current = start;
+
+ public boolean hasNext() {
+ return current != null;
+ }
+
+ public FixedNode next() {
+ try {
+ return current;
+ } finally {
+ current = (FixedNode) current.predecessor();
+ }
+ }
+ };
+ }
+ };
+ }
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/NodesToDoubles.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.nodes.util;
-
-import java.util.*;
-
-import com.oracle.graal.nodes.*;
-
-public class NodesToDoubles {
-
- private final IdentityHashMap nodeProbabilities;
-
- public NodesToDoubles(int numberOfNodes) {
- this.nodeProbabilities = new IdentityHashMap<>(numberOfNodes);
- }
-
- public void put(FixedNode n, double value) {
- assert value >= 0.0 : value;
- nodeProbabilities.put(n, value);
- }
-
- public boolean contains(FixedNode n) {
- return nodeProbabilities.containsKey(n);
- }
-
- public double get(FixedNode n) {
- Double value = nodeProbabilities.get(n);
- assert value != null;
- return value;
- }
-
- public int getCount() {
- return nodeProbabilities.size();
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ConvertDeoptimizeToGuardPhase.java Sat May 03 21:46:35 2014 +0200
@@ -35,27 +35,20 @@
/**
* This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
* {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
- *
+ *
* This is useful because {@link FixedGuardNode FixedGuardNodes} will be lowered to
* {@link GuardNode GuardNodes} which can later be optimized more aggressively than control-flow
* constructs.
- *
+ *
* This is currently only done for branches that start from a {@link IfNode}. If it encounters a
* branch starting at an other kind of {@link ControlSplitNode}, it will only bring the
* {@link DeoptimizeNode} as close to the {@link ControlSplitNode} as possible.
- *
+ *
*/
public class ConvertDeoptimizeToGuardPhase extends Phase {
private static BeginNode findBeginNode(FixedNode startNode) {
- Node n = startNode;
- while (true) {
- if (n instanceof BeginNode) {
- return (BeginNode) n;
- } else {
- n = n.predecessor();
- }
- }
+ return GraphUtil.predecessorIterable(startNode).filter(BeginNode.class).first();
}
@Override
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FloatingReadPhase.java Sat May 03 21:46:35 2014 +0200
@@ -113,8 +113,8 @@
@Override
protected void run(StructuredGraph graph) {
Map> modifiedInLoops = new IdentityHashMap<>();
- ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet(), null);
- ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, execmode), graph.start(), new MemoryMapImpl(graph.start()), null);
+ ReentrantNodeIterator.apply(new CollectMemoryCheckpointsClosure(modifiedInLoops), graph.start(), new HashSet());
+ ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, execmode), graph.start(), new MemoryMapImpl(graph.start()));
if (execmode == ExecutionMode.CREATE_FLOATING_READS) {
assert !graph.isAfterFloatingReadPhase();
graph.setAfterFloatingReadPhase(true);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/FrameStateAssignmentPhase.java Sat May 03 21:46:35 2014 +0200
@@ -107,7 +107,7 @@
protected void run(StructuredGraph graph) {
assert graph.getGuardsStage().ordinal() >= GuardsStage.FIXED_DEOPTS.ordinal() && checkFixedDeopts(graph);
if (graph.getGuardsStage().ordinal() < GuardsStage.AFTER_FSA.ordinal()) {
- ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null, null);
+ ReentrantNodeIterator.apply(new FrameStateAssignmentClosure(), graph.start(), null);
graph.setGuardsStage(GuardsStage.AFTER_FSA);
}
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,858 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.phases.common;
-
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.phases.common.InliningPhase.Options.*;
-
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.Mark;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.options.*;
-import com.oracle.graal.phases.common.InliningUtil.InlineInfo;
-import com.oracle.graal.phases.common.InliningUtil.Inlineable;
-import com.oracle.graal.phases.common.InliningUtil.InlineableGraph;
-import com.oracle.graal.phases.common.InliningUtil.InlineableMacroNode;
-import com.oracle.graal.phases.common.InliningUtil.InliningPolicy;
-import com.oracle.graal.phases.graph.*;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-
-public class InliningPhase extends AbstractInliningPhase {
-
- static class Options {
-
- // @formatter:off
- @Option(help = "Unconditionally inline intrinsics")
- public static final OptionValue AlwaysInlineIntrinsics = new OptionValue<>(false);
- // @formatter:on
- }
-
- private final InliningPolicy inliningPolicy;
- private final CanonicalizerPhase canonicalizer;
-
- private int inliningCount;
- private int maxMethodPerInlining = Integer.MAX_VALUE;
-
- // Metrics
- private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
- private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
- private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
- private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
-
- public InliningPhase(CanonicalizerPhase canonicalizer) {
- this(new GreedyInliningPolicy(null), canonicalizer);
- }
-
- public InliningPhase(Map hints, CanonicalizerPhase canonicalizer) {
- this(new GreedyInliningPolicy(hints), canonicalizer);
- }
-
- public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
- this.inliningPolicy = policy;
- this.canonicalizer = canonicalizer;
- }
-
- public void setMaxMethodsPerInlining(int max) {
- maxMethodPerInlining = max;
- }
-
- public int getInliningCount() {
- return inliningCount;
- }
-
- @Override
- protected void run(final StructuredGraph graph, final HighTierContext context) {
- final InliningData data = new InliningData(graph, context.getAssumptions());
-
- while (data.hasUnprocessedGraphs()) {
- final MethodInvocation currentInvocation = data.currentInvocation();
- GraphInfo graphInfo = data.currentGraph();
- if (!currentInvocation.isRoot() &&
- !inliningPolicy.isWorthInlining(context.getReplacements(), currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(),
- currentInvocation.relevance(), false)) {
- int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
- assert remainingGraphs > 0;
- data.popGraphs(remainingGraphs);
- data.popInvocation();
- } else if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(graphInfo.graph())) {
- processNextInvoke(data, graphInfo, context);
- } else {
- data.popGraph();
- if (!currentInvocation.isRoot()) {
- assert currentInvocation.callee().invoke().asNode().isAlive();
- currentInvocation.incrementProcessedGraphs();
- if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
- data.popInvocation();
- final MethodInvocation parentInvoke = data.currentInvocation();
- try (Scope s = Debug.scope("Inlining", data.inliningContext())) {
- tryToInline(data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
- } catch (Throwable e) {
- throw Debug.handle(e);
- }
- }
- }
- }
- }
-
- assert data.inliningDepth() == 0;
- assert data.graphCount() == 0;
- }
-
- /**
- * Process the next invoke and enqueue all its graphs for processing.
- */
- private void processNextInvoke(InliningData data, GraphInfo graphInfo, HighTierContext context) {
- Invoke invoke = graphInfo.popInvoke();
- MethodInvocation callerInvocation = data.currentInvocation();
- Assumptions parentAssumptions = callerInvocation.assumptions();
- InlineInfo info = InliningUtil.getInlineInfo(data, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
-
- if (info != null) {
- double invokeProbability = graphInfo.invokeProbability(invoke);
- double invokeRelevance = graphInfo.invokeRelevance(invoke);
- MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
-
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()));
- info.setInlinableElement(i, elem);
- if (elem instanceof InlineableGraph) {
- data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
- } else {
- assert elem instanceof InlineableMacroNode;
- data.pushDummyGraph();
- }
- }
- }
- }
-
- private void tryToInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth, HighTierContext context) {
- InlineInfo callee = calleeInfo.callee();
- Assumptions callerAssumptions = parentInvocation.assumptions();
-
- if (inliningPolicy.isWorthInlining(context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
- doInline(callerGraphInfo, calleeInfo, callerAssumptions, context);
- } else if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
- callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
- }
- metricInliningConsidered.increment();
- }
-
- private void doInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
- StructuredGraph callerGraph = callerGraphInfo.graph();
- Mark markBeforeInlining = callerGraph.getMark();
- InlineInfo callee = calleeInfo.callee();
- try {
- try (Scope scope = Debug.scope("doInline", callerGraph)) {
- List invokeUsages = callee.invoke().asNode().usages().snapshot();
- callee.inline(new Providers(context), callerAssumptions);
- callerAssumptions.record(calleeInfo.assumptions());
- metricInliningRuns.increment();
- Debug.dump(callerGraph, "after %s", callee);
-
- if (OptCanonicalizer.getValue()) {
- Mark markBeforeCanonicalization = callerGraph.getMark();
- canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
-
- // process invokes that are possibly created during canonicalization
- for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
- if (newNode instanceof Invoke) {
- callerGraphInfo.pushInvoke((Invoke) newNode);
- }
- }
- }
-
- callerGraphInfo.computeProbabilities();
-
- inliningCount++;
- metricInliningPerformed.increment();
- }
- } catch (BailoutException bailout) {
- throw bailout;
- } catch (AssertionError | RuntimeException e) {
- throw new GraalInternalError(e).addContext(callee.toString());
- } catch (GraalInternalError e) {
- throw e.addContext(callee.toString());
- }
- }
-
- private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context) {
- Class extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
- if (macroNodeClass != null) {
- return new InlineableMacroNode(macroNodeClass);
- } else {
- return new InlineableGraph(buildGraph(method, invoke, context));
- }
- }
-
- private StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context) {
- final StructuredGraph newGraph;
- final boolean parseBytecodes;
-
- // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
- // any invokes
- StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
- if (intrinsicGraph != null) {
- newGraph = intrinsicGraph.copy();
- parseBytecodes = false;
- } else {
- StructuredGraph cachedGraph = getCachedGraph(method, context);
- if (cachedGraph != null) {
- newGraph = cachedGraph.copy();
- parseBytecodes = false;
- } else {
- newGraph = new StructuredGraph(method);
- parseBytecodes = true;
- }
- }
-
- try (Scope s = Debug.scope("InlineGraph", newGraph)) {
- if (parseBytecodes) {
- parseBytecodes(newGraph, context);
- }
-
- boolean callerHasMoreInformationAboutArguments = false;
- NodeInputList args = invoke.callTarget().arguments();
- for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
- ValueNode arg = args.get(param.index());
- if (arg.isConstant()) {
- Constant constant = arg.asConstant();
- newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
- callerHasMoreInformationAboutArguments = true;
- } else {
- Stamp joinedStamp = param.stamp().join(arg.stamp());
- if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
- param.setStamp(joinedStamp);
- callerHasMoreInformationAboutArguments = true;
- }
- }
- }
-
- if (!callerHasMoreInformationAboutArguments) {
- // TODO (chaeubl): if args are not more concrete, inlining should be avoided
- // in most cases or we could at least use the previous graph size + invoke
- // probability to check the inlining
- }
-
- if (OptCanonicalizer.getValue()) {
- canonicalizer.apply(newGraph, context);
- }
-
- return newGraph;
- } catch (Throwable e) {
- throw Debug.handle(e);
- }
- }
-
- private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
- if (context.getGraphCache() != null) {
- StructuredGraph cachedGraph = context.getGraphCache().get(method);
- if (cachedGraph != null) {
- return cachedGraph;
- }
- }
- return null;
- }
-
- private StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context) {
- boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
-
- if (context.getGraphBuilderSuite() != null) {
- context.getGraphBuilderSuite().apply(newGraph, context);
- }
- assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
-
- new DeadCodeEliminationPhase().apply(newGraph);
-
- if (OptCanonicalizer.getValue()) {
- canonicalizer.apply(newGraph, context);
- }
-
- if (hasMatureProfilingInfo && context.getGraphCache() != null) {
- context.getGraphCache().put(newGraph.method(), newGraph.copy());
- }
- return newGraph;
- }
-
- private abstract static class AbstractInliningPolicy implements InliningPolicy {
-
- protected final Map hints;
-
- public AbstractInliningPolicy(Map hints) {
- this.hints = hints;
- }
-
- protected double computeMaximumSize(double relevance, int configuredMaximum) {
- double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
- return configuredMaximum * inlineRatio;
- }
-
- protected double getInliningBonus(InlineInfo info) {
- if (hints != null && hints.containsKey(info.invoke())) {
- return hints.get(info.invoke());
- }
- return 1;
- }
-
- protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
- if (AlwaysInlineIntrinsics.getValue()) {
- return onlyIntrinsics(replacements, info);
- } else {
- return onlyForcedIntrinsics(replacements, info);
- }
- }
-
- private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
- for (int i = 0; i < info.numberOfMethods(); i++) {
- if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
- for (int i = 0; i < info.numberOfMethods(); i++) {
- if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
- return false;
- }
- if (!replacements.isForcedSubstitution(info.methodAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- protected static int previousLowLevelGraphSize(InlineInfo info) {
- int size = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- ResolvedJavaMethod m = info.methodAt(i);
- ProfilingInfo profile = m.getProfilingInfo();
- int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
- if (compiledGraphSize > 0) {
- size += compiledGraphSize;
- }
- }
- return size;
- }
-
- protected static int determineNodeCount(InlineInfo info) {
- int nodes = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable elem = info.inlineableElementAt(i);
- if (elem != null) {
- nodes += elem.getNodeCount();
- }
- }
- return nodes;
- }
-
- protected static double determineInvokeProbability(InlineInfo info) {
- double invokeProbability = 0;
- for (int i = 0; i < info.numberOfMethods(); i++) {
- Inlineable callee = info.inlineableElementAt(i);
- Iterable invokes = callee.getInvokes();
- if (invokes.iterator().hasNext()) {
- NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(((InlineableGraph) callee).getGraph()).apply();
- for (Invoke invoke : invokes) {
- invokeProbability += nodeProbabilities.get(invoke.asNode());
- }
- }
- }
- return invokeProbability;
- }
- }
-
- public static class GreedyInliningPolicy extends AbstractInliningPolicy {
-
- public GreedyInliningPolicy(Map hints) {
- super(hints);
- }
-
- public boolean continueInlining(StructuredGraph currentGraph) {
- if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
- InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
- metricInliningStoppedByMaxDesiredSize.increment();
- return false;
- }
- return true;
- }
-
- @Override
- public boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) {
- if (InlineEverything.getValue()) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
- }
-
- if (isIntrinsic(replacements, info)) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
- }
-
- if (info.shouldInline()) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
- }
-
- double inliningBonus = getInliningBonus(info);
- int nodes = determineNodeCount(info);
- int lowLevelGraphSize = previousLowLevelGraphSize(info);
-
- if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)",
- lowLevelGraphSize, relevance, probability, inliningBonus, nodes);
- }
-
- if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
- }
-
- /*
- * TODO (chaeubl): invoked methods that are on important paths but not yet compiled ->
- * will be compiled anyways and it is likely that we are the only caller... might be
- * useful to inline those methods but increases bootstrap time (maybe those methods are
- * also getting queued in the compilation queue concurrently)
- */
- double invokes = determineInvokeProbability(info);
- if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes,
- relevance, probability, inliningBonus, nodes);
- }
-
- double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
- if (nodes <= maximumNodes) {
- return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability,
- inliningBonus, nodes, maximumNodes);
- }
-
- return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes,
- maximumNodes);
- }
- }
-
- public static final class InlineEverythingPolicy implements InliningPolicy {
-
- public boolean continueInlining(StructuredGraph graph) {
- if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
- throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
- }
- return true;
- }
-
- public boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed) {
- return true;
- }
- }
-
- private static class InliningIterator {
-
- private final FixedNode start;
- private final Deque nodeQueue;
- private final NodeBitMap queuedNodes;
-
- public InliningIterator(FixedNode start, NodeBitMap visitedFixedNodes) {
- this.start = start;
- this.nodeQueue = new ArrayDeque<>();
- this.queuedNodes = visitedFixedNodes;
- assert start.isAlive();
- }
-
- public LinkedList apply() {
- LinkedList invokes = new LinkedList<>();
- FixedNode current;
- forcedQueue(start);
-
- while ((current = nextQueuedNode()) != null) {
- assert current.isAlive();
-
- if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
- if (current != start) {
- invokes.addLast((Invoke) current);
- }
- queueSuccessors(current);
- } else if (current instanceof LoopBeginNode) {
- queueSuccessors(current);
- } else if (current instanceof LoopEndNode) {
- // nothing todo
- } else if (current instanceof MergeNode) {
- queueSuccessors(current);
- } else if (current instanceof FixedWithNextNode) {
- queueSuccessors(current);
- } else if (current instanceof EndNode) {
- queueMerge((EndNode) current);
- } else if (current instanceof ControlSinkNode) {
- // nothing todo
- } else if (current instanceof ControlSplitNode) {
- queueSuccessors(current);
- } else {
- assert false : current;
- }
- }
-
- return invokes;
- }
-
- private void queueSuccessors(FixedNode x) {
- for (Node node : x.successors()) {
- queue(node);
- }
- }
-
- private void queue(Node node) {
- if (node != null && !queuedNodes.isMarked(node)) {
- forcedQueue(node);
- }
- }
-
- private void forcedQueue(Node node) {
- queuedNodes.mark(node);
- nodeQueue.addFirst((FixedNode) node);
- }
-
- private FixedNode nextQueuedNode() {
- if (nodeQueue.isEmpty()) {
- return null;
- }
-
- FixedNode result = nodeQueue.removeFirst();
- assert queuedNodes.isMarked(result);
- return result;
- }
-
- private void queueMerge(AbstractEndNode end) {
- MergeNode merge = end.merge();
- if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
- queuedNodes.mark(merge);
- nodeQueue.add(merge);
- }
- }
-
- private boolean visitedAllEnds(MergeNode merge) {
- for (int i = 0; i < merge.forwardEndCount(); i++) {
- if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
- return false;
- }
- }
- return true;
- }
- }
-
- /**
- * Holds the data for building the callee graphs recursively: graphs and invocations (each
- * invocation can have multiple graphs).
- */
- static class InliningData {
-
- private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new LinkedList(), 1.0, 1.0);
-
- /**
- * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
- */
- private final ArrayDeque graphQueue;
- private final ArrayDeque invocationQueue;
-
- private int maxGraphs;
-
- public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions) {
- this.graphQueue = new ArrayDeque<>();
- this.invocationQueue = new ArrayDeque<>();
- this.maxGraphs = 1;
-
- invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
- pushGraph(rootGraph, 1.0, 1.0);
- }
-
- public int graphCount() {
- return graphQueue.size();
- }
-
- public void pushGraph(StructuredGraph graph, double probability, double relevance) {
- assert !contains(graph);
- NodeBitMap visitedFixedNodes = graph.createNodeBitMap();
- LinkedList invokes = new InliningIterator(graph.start(), visitedFixedNodes).apply();
- assert invokes.size() == count(graph.getInvokes());
- graphQueue.push(new GraphInfo(graph, invokes, probability, relevance));
- assert graphQueue.size() <= maxGraphs;
- }
-
- public void pushDummyGraph() {
- graphQueue.push(DummyGraphInfo);
- }
-
- public boolean hasUnprocessedGraphs() {
- return !graphQueue.isEmpty();
- }
-
- public GraphInfo currentGraph() {
- return graphQueue.peek();
- }
-
- public void popGraph() {
- graphQueue.pop();
- assert graphQueue.size() <= maxGraphs;
- }
-
- public void popGraphs(int count) {
- assert count >= 0;
- for (int i = 0; i < count; i++) {
- graphQueue.pop();
- }
- }
-
- private static final Object[] NO_CONTEXT = {};
-
- /**
- * Gets the call hierarchy of this inlining from outer most call to inner most callee.
- */
- public Object[] inliningContext() {
- if (!Debug.isDumpEnabled()) {
- return NO_CONTEXT;
- }
- Object[] result = new Object[graphQueue.size()];
- int i = 0;
- for (GraphInfo g : graphQueue) {
- result[i++] = g.graph.method();
- }
- return result;
- }
-
- public MethodInvocation currentInvocation() {
- return invocationQueue.peekFirst();
- }
-
- public MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
- MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
- invocationQueue.addFirst(methodInvocation);
- maxGraphs += info.numberOfMethods();
- assert graphQueue.size() <= maxGraphs;
- return methodInvocation;
- }
-
- public void popInvocation() {
- maxGraphs -= invocationQueue.peekFirst().callee.numberOfMethods();
- assert graphQueue.size() <= maxGraphs;
- invocationQueue.removeFirst();
- }
-
- public int countRecursiveInlining(ResolvedJavaMethod method) {
- int count = 0;
- for (GraphInfo graphInfo : graphQueue) {
- if (method.equals(graphInfo.method())) {
- count++;
- }
- }
- return count;
- }
-
- public int inliningDepth() {
- assert invocationQueue.size() > 0;
- return invocationQueue.size() - 1;
- }
-
- @Override
- public String toString() {
- StringBuilder result = new StringBuilder("Invocations: ");
-
- for (MethodInvocation invocation : invocationQueue) {
- if (invocation.callee() != null) {
- result.append(invocation.callee().numberOfMethods());
- result.append("x ");
- result.append(invocation.callee().invoke());
- result.append("; ");
- }
- }
-
- result.append("\nGraphs: ");
- for (GraphInfo graph : graphQueue) {
- result.append(graph.graph());
- result.append("; ");
- }
-
- return result.toString();
- }
-
- private boolean contains(StructuredGraph graph) {
- for (GraphInfo info : graphQueue) {
- if (info.graph() == graph) {
- return true;
- }
- }
- return false;
- }
-
- private static int count(Iterable invokes) {
- int count = 0;
- Iterator iterator = invokes.iterator();
- while (iterator.hasNext()) {
- iterator.next();
- count++;
- }
- return count;
- }
- }
-
- private static class MethodInvocation {
-
- private final InlineInfo callee;
- private final Assumptions assumptions;
- private final double probability;
- private final double relevance;
-
- private int processedGraphs;
-
- public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
- this.callee = info;
- this.assumptions = assumptions;
- this.probability = probability;
- this.relevance = relevance;
- }
-
- public void incrementProcessedGraphs() {
- processedGraphs++;
- assert processedGraphs <= callee.numberOfMethods();
- }
-
- public int processedGraphs() {
- assert processedGraphs <= callee.numberOfMethods();
- return processedGraphs;
- }
-
- public int totalGraphs() {
- return callee.numberOfMethods();
- }
-
- public InlineInfo callee() {
- return callee;
- }
-
- public Assumptions assumptions() {
- return assumptions;
- }
-
- public double probability() {
- return probability;
- }
-
- public double relevance() {
- return relevance;
- }
-
- public boolean isRoot() {
- return callee == null;
- }
-
- @Override
- public String toString() {
- if (isRoot()) {
- return "";
- }
- CallTargetNode callTarget = callee.invoke().callTarget();
- if (callTarget instanceof MethodCallTargetNode) {
- ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
- return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
- } else {
- return "Invoke#" + callTarget.targetName();
- }
- }
- }
-
- /**
- * Information about a graph that will potentially be inlined. This includes tracking the
- * invocations in graph that will subject to inlining themselves.
- */
- private static class GraphInfo {
-
- private final StructuredGraph graph;
- private final LinkedList remainingInvokes;
- private final double probability;
- private final double relevance;
-
- private NodesToDoubles nodeProbabilities;
- private NodesToDoubles nodeRelevance;
-
- public GraphInfo(StructuredGraph graph, LinkedList invokes, double probability, double relevance) {
- this.graph = graph;
- this.remainingInvokes = invokes;
- this.probability = probability;
- this.relevance = relevance;
-
- if (graph != null) {
- computeProbabilities();
- }
- }
-
- /**
- * Gets the method associated with the {@linkplain #graph() graph} represented by this
- * object.
- */
- public ResolvedJavaMethod method() {
- return graph.method();
- }
-
- public boolean hasRemainingInvokes() {
- return !remainingInvokes.isEmpty();
- }
-
- /**
- * The graph about which this object contains inlining information.
- */
- public StructuredGraph graph() {
- return graph;
- }
-
- public Invoke popInvoke() {
- return remainingInvokes.removeFirst();
- }
-
- public void pushInvoke(Invoke invoke) {
- remainingInvokes.push(invoke);
- }
-
- public void computeProbabilities() {
- nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
- nodeRelevance = new ComputeInliningRelevanceClosure(graph, nodeProbabilities).apply();
- }
-
- public double invokeProbability(Invoke invoke) {
- return probability * nodeProbabilities.get(invoke.asNode());
- }
-
- public double invokeRelevance(Invoke invoke) {
- return Math.min(CapInheritedRelevance.getValue(), relevance) * nodeRelevance.get(invoke.asNode());
- }
-
- @Override
- public String toString() {
- return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "") + remainingInvokes;
- }
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1618 +0,0 @@
-/*
- * Copyright (c) 2012, 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 com.oracle.graal.phases.common;
-
-import static com.oracle.graal.api.meta.DeoptimizationAction.*;
-import static com.oracle.graal.api.meta.DeoptimizationReason.*;
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.compiler.common.type.StampFactory.*;
-import java.util.*;
-
-import com.oracle.graal.api.code.*;
-import com.oracle.graal.api.code.Assumptions.Assumption;
-import com.oracle.graal.api.meta.*;
-import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
-import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
-import com.oracle.graal.compiler.common.*;
-import com.oracle.graal.compiler.common.calc.*;
-import com.oracle.graal.compiler.common.type.*;
-import com.oracle.graal.debug.*;
-import com.oracle.graal.debug.Debug.Scope;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.graph.Graph.DuplicationReplacement;
-import com.oracle.graal.graph.Node.Verbosity;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.calc.*;
-import com.oracle.graal.nodes.extended.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
-import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.type.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.InliningPhase.InliningData;
-import com.oracle.graal.phases.tiers.*;
-import com.oracle.graal.phases.util.*;
-
-public class InliningUtil {
-
- private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
- private static final String inliningDecisionsScopeString = "InliningDecisions";
- /**
- * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
- * and all inlined methods), irrespective of how many bytecodes in each method are actually
- * parsed (which may be none for methods whose IR is retrieved from a cache).
- */
- public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
-
- public interface InliningPolicy {
-
- boolean continueInlining(StructuredGraph graph);
-
- boolean isWorthInlining(Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
- }
-
- public interface Inlineable {
-
- int getNodeCount();
-
- Iterable getInvokes();
- }
-
- public static class InlineableGraph implements Inlineable {
-
- private final StructuredGraph graph;
-
- public InlineableGraph(StructuredGraph graph) {
- this.graph = graph;
- }
-
- @Override
- public int getNodeCount() {
- return graph.getNodeCount();
- }
-
- @Override
- public Iterable getInvokes() {
- return graph.getInvokes();
- }
-
- public StructuredGraph getGraph() {
- return graph;
- }
- }
-
- public static class InlineableMacroNode implements Inlineable {
-
- private final Class extends FixedWithNextNode> macroNodeClass;
-
- public InlineableMacroNode(Class extends FixedWithNextNode> macroNodeClass) {
- this.macroNodeClass = macroNodeClass;
- }
-
- @Override
- public int getNodeCount() {
- return 1;
- }
-
- @Override
- public Iterable getInvokes() {
- return Collections.emptyList();
- }
-
- public Class extends FixedWithNextNode> getMacroNodeClass() {
- return macroNodeClass;
- }
- }
-
- /**
- * Print a HotSpot-style inlining message to the console.
- */
- private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) {
- printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
- }
-
- /**
- * Print a HotSpot-style inlining message to the console.
- */
- private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
- if (HotSpotPrintInlining.getValue()) {
- // 1234567
- TTY.print(" "); // print timestamp
- // 1234
- TTY.print(" "); // print compilation number
- // % s ! b n
- TTY.print("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
- TTY.print(" "); // more indent
- TTY.print(" "); // initial inlining indent
- for (int i = 0; i < inliningDepth; i++) {
- TTY.print(" ");
- }
- TTY.println(String.format("@ %d %s %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args)));
- }
- }
-
- public static boolean logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
- return logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
- }
-
- public static boolean logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
- return logInliningDecision(info, inliningDepth, true, false, msg, args);
- }
-
- public static boolean logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
- if (allowLogging) {
- printInlining(info, inliningDepth, success, msg, args);
- if (shouldLogInliningDecision()) {
- logInliningDecision(methodName(info), success, msg, args);
- }
- }
- return success;
- }
-
- public static void logInliningDecision(final String msg, final Object... args) {
- try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
- // Can't use log here since we are varargs
- if (Debug.isLogEnabled()) {
- Debug.logv(msg, args);
- }
- }
- }
-
- private static boolean logNotInlinedMethod(Invoke invoke, String msg) {
- if (shouldLogInliningDecision()) {
- String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
- logInliningDecision(methodString, false, msg, new Object[0]);
- }
- return false;
- }
-
- private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
- return logNotInlinedMethodAndReturnNull(invoke, inliningDepth, method, msg, new Object[0]);
- }
-
- private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
- printInlining(method, invoke, inliningDepth, false, msg, args);
- if (shouldLogInliningDecision()) {
- String methodString = methodName(method, invoke);
- logInliningDecision(methodString, false, msg, args);
- }
- return null;
- }
-
- private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
- printInlining(method, invoke, inliningDepth, false, msg, new Object[0]);
- if (shouldLogInliningDecision()) {
- String methodString = methodName(method, invoke);
- logInliningDecision(methodString, false, msg, new Object[0]);
- }
- return false;
- }
-
- private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
- String inliningMsg = "inlining " + methodString + ": " + msg;
- if (!success) {
- inliningMsg = "not " + inliningMsg;
- }
- logInliningDecision(inliningMsg, args);
- }
-
- public static boolean shouldLogInliningDecision() {
- try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
- return Debug.isLogEnabled();
- }
- }
-
- private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
- if (invoke != null && invoke.stateAfter() != null) {
- return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
- } else {
- return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
- }
- }
-
- private static String methodName(InlineInfo info) {
- if (info == null) {
- return "null";
- } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
- return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
- } else {
- return info.toString();
- }
- }
-
- private static String methodName(FrameState frameState, int bci) {
- StringBuilder sb = new StringBuilder();
- if (frameState.outerFrameState() != null) {
- sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
- sb.append("->");
- }
- sb.append(MetaUtil.format("%h.%n", frameState.method()));
- sb.append("@").append(bci);
- return sb.toString();
- }
-
- /**
- * Represents an opportunity for inlining at a given invoke, with the given weight and level.
- * The weight is the amortized weight of the additional code - so smaller is better. The level
- * is the number of nested inlinings that lead to this invoke.
- */
- public interface InlineInfo {
-
- /**
- * The graph containing the {@link #invoke() invocation} that may be inlined.
- */
- StructuredGraph graph();
-
- /**
- * The invocation that may be inlined.
- */
- Invoke invoke();
-
- /**
- * Returns the number of methods that may be inlined by the {@link #invoke() invocation}.
- * This may be more than one in the case of a invocation profile showing a number of "hot"
- * concrete methods dispatched to by the invocation.
- */
- int numberOfMethods();
-
- ResolvedJavaMethod methodAt(int index);
-
- Inlineable inlineableElementAt(int index);
-
- double probabilityAt(int index);
-
- double relevanceAt(int index);
-
- void setInlinableElement(int index, Inlineable inlineableElement);
-
- /**
- * Performs the inlining described by this object and returns the node that represents the
- * return value of the inlined method (or null for void methods and methods that have no
- * non-exceptional exit).
- */
- void inline(Providers providers, Assumptions assumptions);
-
- /**
- * Try to make the call static bindable to avoid interface and virtual method calls.
- */
- void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
-
- boolean shouldInline();
- }
-
- public abstract static class AbstractInlineInfo implements InlineInfo {
-
- protected final Invoke invoke;
-
- public AbstractInlineInfo(Invoke invoke) {
- this.invoke = invoke;
- }
-
- @Override
- public StructuredGraph graph() {
- return invoke.asNode().graph();
- }
-
- @Override
- public Invoke invoke() {
- return invoke;
- }
-
- protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
- if (inlineable instanceof InlineableGraph) {
- StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
- InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
- } else {
- assert inlineable instanceof InlineableMacroNode;
-
- Class extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
- inlineMacroNode(invoke, concrete, macroNodeClass);
- }
-
- InlinedBytecodes.add(concrete.getCodeSize());
- assumptions.recordMethodContents(concrete);
- }
- }
-
- public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
- MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
- MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
- invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
- }
-
- /**
- * Represents an inlining opportunity where the compiler can statically determine a monomorphic
- * target method and therefore is able to determine the called method exactly.
- */
- public static class ExactInlineInfo extends AbstractInlineInfo {
-
- protected final ResolvedJavaMethod concrete;
- private Inlineable inlineableElement;
- private boolean suppressNullCheck;
-
- public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
- super(invoke);
- this.concrete = concrete;
- assert concrete != null;
- }
-
- public void suppressNullCheck() {
- suppressNullCheck = true;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- // nothing todo, can already be bound statically
- }
-
- @Override
- public int numberOfMethods() {
- return 1;
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index == 0;
- return concrete;
- }
-
- @Override
- public double probabilityAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public double relevanceAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public String toString() {
- return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index == 0;
- return inlineableElement;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index == 0;
- this.inlineableElement = inlineableElement;
- }
-
- public boolean shouldInline() {
- return concrete.shouldBeInlined();
- }
- }
-
- /**
- * Represents an inlining opportunity for which profiling information suggests a monomorphic
- * receiver, but for which the receiver type cannot be proven. A type check guard will be
- * generated if this inlining is performed.
- */
- private static class TypeGuardInlineInfo extends AbstractInlineInfo {
-
- private final ResolvedJavaMethod concrete;
- private final ResolvedJavaType type;
- private Inlineable inlineableElement;
-
- public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
- super(invoke);
- this.concrete = concrete;
- this.type = type;
- assert type.isArray() || !type.isAbstract() : type;
- }
-
- @Override
- public int numberOfMethods() {
- return 1;
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index == 0;
- return concrete;
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index == 0;
- return inlineableElement;
- }
-
- @Override
- public double probabilityAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public double relevanceAt(int index) {
- assert index == 0;
- return 1.0;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index == 0;
- this.inlineableElement = inlineableElement;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- createGuard(graph(), providers.getMetaAccess());
- inline(invoke, concrete, inlineableElement, assumptions, false);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- createGuard(graph(), metaAccess);
- replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
- }
-
- private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
- ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
- ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph);
- LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind()));
-
- CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
- FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
- assert invoke.predecessor() != null;
-
- ValueNode anchoredReceiver = createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
- invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
-
- graph.addBeforeFixed(invoke.asNode(), guard);
- }
-
- @Override
- public String toString() {
- return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
-
- public boolean shouldInline() {
- return concrete.shouldBeInlined();
- }
- }
-
- /**
- * Polymorphic inlining of m methods with n type checks (n ≥ m) in case that the profiling
- * information suggests a reasonable amount of different receiver types and different methods.
- * If an unknown type is encountered a deoptimization is triggered.
- */
- private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
-
- private final List concretes;
- private final double[] methodProbabilities;
- private final double maximumMethodProbability;
- private final ArrayList typesToConcretes;
- private final ArrayList ptypes;
- private final ArrayList concretesProbabilities;
- private final double notRecordedTypeProbability;
- private final Inlineable[] inlineableElements;
-
- public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes,
- ArrayList typesToConcretes, double notRecordedTypeProbability) {
- super(invoke);
- assert concretes.size() > 0 : "must have at least one method";
- assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
-
- this.concretesProbabilities = concretesProbabilities;
- this.concretes = concretes;
- this.ptypes = ptypes;
- this.typesToConcretes = typesToConcretes;
- this.notRecordedTypeProbability = notRecordedTypeProbability;
- this.inlineableElements = new Inlineable[concretes.size()];
- this.methodProbabilities = computeMethodProbabilities();
- this.maximumMethodProbability = maximumMethodProbability();
- assert maximumMethodProbability > 0;
- }
-
- private double[] computeMethodProbabilities() {
- double[] result = new double[concretes.size()];
- for (int i = 0; i < typesToConcretes.size(); i++) {
- int concrete = typesToConcretes.get(i);
- double probability = ptypes.get(i).getProbability();
- result[concrete] += probability;
- }
- return result;
- }
-
- private double maximumMethodProbability() {
- double max = 0;
- for (int i = 0; i < methodProbabilities.length; i++) {
- max = Math.max(max, methodProbabilities[i]);
- }
- return max;
- }
-
- @Override
- public int numberOfMethods() {
- return concretes.size();
- }
-
- @Override
- public ResolvedJavaMethod methodAt(int index) {
- assert index >= 0 && index < concretes.size();
- return concretes.get(index);
- }
-
- @Override
- public Inlineable inlineableElementAt(int index) {
- assert index >= 0 && index < concretes.size();
- return inlineableElements[index];
- }
-
- @Override
- public double probabilityAt(int index) {
- return methodProbabilities[index];
- }
-
- @Override
- public double relevanceAt(int index) {
- return probabilityAt(index) / maximumMethodProbability;
- }
-
- @Override
- public void setInlinableElement(int index, Inlineable inlineableElement) {
- assert index >= 0 && index < concretes.size();
- inlineableElements[index] = inlineableElement;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- if (hasSingleMethod()) {
- inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
- } else {
- inlineMultipleMethods(graph(), providers, assumptions);
- }
- }
-
- public boolean shouldInline() {
- for (ResolvedJavaMethod method : concretes) {
- if (method.shouldBeInlined()) {
- return true;
- }
- }
- return false;
- }
-
- private boolean hasSingleMethod() {
- return concretes.size() == 1 && !shouldFallbackToInvoke();
- }
-
- private boolean shouldFallbackToInvoke() {
- return notRecordedTypeProbability > 0;
- }
-
- private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
- int numberOfMethods = concretes.size();
- FixedNode continuation = invoke.next();
-
- ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
- // setup merge and phi nodes for results and exceptions
- MergeNode returnMerge = graph.add(new MergeNode());
- returnMerge.setStateAfter(invoke.stateAfter());
-
- PhiNode returnValuePhi = null;
- if (invoke.asNode().getKind() != Kind.Void) {
- returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
- }
-
- MergeNode exceptionMerge = null;
- PhiNode exceptionObjectPhi = null;
- if (invoke instanceof InvokeWithExceptionNode) {
- InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
-
- exceptionMerge = graph.add(new MergeNode());
-
- FixedNode exceptionSux = exceptionEdge.next();
- graph.addBeforeFixed(exceptionSux, exceptionMerge);
- exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
- exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
- }
-
- // create one separate block for each invoked method
- BeginNode[] successors = new BeginNode[numberOfMethods + 1];
- for (int i = 0; i < numberOfMethods; i++) {
- successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
- }
-
- // create the successor for an unknown type
- FixedNode unknownTypeSux;
- if (shouldFallbackToInvoke()) {
- unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
- } else {
- unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
- }
- successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
-
- // replace the invoke exception edge
- if (invoke instanceof InvokeWithExceptionNode) {
- InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
- exceptionEdge.replaceAtUsages(exceptionObjectPhi);
- exceptionEdge.setNext(null);
- GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
- }
-
- assert invoke.asNode().isAlive();
-
- // replace the invoke with a switch on the type of the actual receiver
- boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
-
- assert invoke.next() == continuation;
- invoke.setNext(null);
- returnMerge.setNext(continuation);
- invoke.asNode().replaceAtUsages(returnValuePhi);
- invoke.asNode().replaceAndDelete(null);
-
- ArrayList replacementNodes = new ArrayList<>();
-
- // do the actual inlining for every invoke
- for (int i = 0; i < numberOfMethods; i++) {
- BeginNode node = successors[i];
- Invoke invokeForInlining = (Invoke) node.next();
-
- ResolvedJavaType commonType;
- if (methodDispatch) {
- commonType = concretes.get(i).getDeclaringClass();
- } else {
- commonType = getLeastCommonType(i);
- }
-
- ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
- boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
- GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
- invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
-
- inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
-
- replacementNodes.add(anchoredReceiver);
- }
- if (shouldFallbackToInvoke()) {
- replacementNodes.add(null);
- }
-
- if (OptTailDuplication.getValue()) {
- /*
- * We might want to perform tail duplication at the merge after a type switch, if
- * there are invokes that would benefit from the improvement in type information.
- */
- FixedNode current = returnMerge;
- int opportunities = 0;
- do {
- if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
- ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
- opportunities++;
- } else if (current.inputs().contains(originalReceiver)) {
- opportunities++;
- }
- current = ((FixedWithNextNode) current).next();
- } while (current instanceof FixedWithNextNode);
-
- if (opportunities > 0) {
- metricInliningTailDuplication.increment();
- Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
- PhaseContext phaseContext = new PhaseContext(providers, assumptions);
- CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
- TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
- }
- }
- }
-
- private int getTypeCount(int concreteMethodIndex) {
- int count = 0;
- for (int i = 0; i < typesToConcretes.size(); i++) {
- if (typesToConcretes.get(i) == concreteMethodIndex) {
- count++;
- }
- }
- return count;
- }
-
- private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
- ResolvedJavaType commonType = null;
- for (int i = 0; i < typesToConcretes.size(); i++) {
- if (typesToConcretes.get(i) == concreteMethodIndex) {
- if (commonType == null) {
- commonType = ptypes.get(i).getType();
- } else {
- commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
- }
- }
- }
- assert commonType != null;
- return commonType;
- }
-
- private ResolvedJavaType getLeastCommonType() {
- ResolvedJavaType result = getLeastCommonType(0);
- for (int i = 1; i < concretes.size(); i++) {
- result = result.findLeastCommonAncestor(getLeastCommonType(i));
- }
- return result;
- }
-
- private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
- assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
-
- BeginNode calleeEntryNode = graph.add(new BeginNode());
-
- BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
- BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
- createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
-
- calleeEntryNode.setNext(invoke.asNode());
-
- inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
- }
-
- private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
- assert ptypes.size() >= 1;
- ValueNode nonNullReceiver = nonNullReceiver(invoke);
- Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
- LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
-
- if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
- assert successors.length == concretes.size() + 1;
- assert concretes.size() > 0;
- Debug.log("Method check cascade with %d methods", concretes.size());
-
- ValueNode[] constantMethods = new ValueNode[concretes.size()];
- double[] probability = new double[concretes.size()];
- for (int i = 0; i < concretes.size(); ++i) {
- ResolvedJavaMethod firstMethod = concretes.get(i);
- Constant firstMethodConstant = firstMethod.getEncoding();
-
- ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
- constantMethods[i] = firstMethodConstantNode;
- double concretesProbability = concretesProbabilities.get(i);
- assert concretesProbability >= 0.0;
- probability[i] = concretesProbability;
- if (i > 0) {
- double prevProbability = probability[i - 1];
- if (prevProbability == 1.0) {
- probability[i] = 1.0;
- } else {
- probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
- }
- }
- }
-
- FixedNode lastSucc = successors[concretes.size()];
- for (int i = concretes.size() - 1; i >= 0; --i) {
- LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind()));
- CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
- IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
- method.setNext(ifNode);
- lastSucc = method;
- }
-
- FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
- pred.setNext(lastSucc);
- return true;
- } else {
- Debug.log("Type switch with %d types", concretes.size());
- }
-
- ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
- double[] keyProbabilities = new double[ptypes.size() + 1];
- int[] keySuccessors = new int[ptypes.size() + 1];
- for (int i = 0; i < ptypes.size(); i++) {
- keys[i] = ptypes.get(i).getType();
- keyProbabilities[i] = ptypes.get(i).getProbability();
- keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
- assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
- }
- keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
- keySuccessors[keySuccessors.length - 1] = successors.length - 1;
-
- TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
- FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
- pred.setNext(typeSwitch);
- return false;
- }
-
- private boolean chooseMethodDispatch() {
- for (ResolvedJavaMethod concrete : concretes) {
- if (!concrete.isInVirtualMethodTable()) {
- return false;
- }
- }
-
- if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
- // Always chose method dispatch if there is a single concrete method and the call
- // site is megamorphic.
- return true;
- }
-
- if (concretes.size() == ptypes.size()) {
- // Always prefer types over methods if the number of types is smaller than the
- // number of methods.
- return false;
- }
-
- return chooseMethodDispatchCostBased();
- }
-
- private boolean chooseMethodDispatchCostBased() {
- double remainder = 1.0 - this.notRecordedTypeProbability;
- double costEstimateMethodDispatch = remainder;
- for (int i = 0; i < concretes.size(); ++i) {
- if (i != 0) {
- costEstimateMethodDispatch += remainder;
- }
- remainder -= concretesProbabilities.get(i);
- }
-
- double costEstimateTypeDispatch = 0.0;
- remainder = 1.0;
- for (int i = 0; i < ptypes.size(); ++i) {
- if (i != 0) {
- costEstimateTypeDispatch += remainder;
- }
- remainder -= ptypes.get(i).getProbability();
- }
- costEstimateTypeDispatch += notRecordedTypeProbability;
- return costEstimateMethodDispatch < costEstimateTypeDispatch;
- }
-
- private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
- boolean useForInlining) {
- Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
- BeginNode calleeEntryNode = graph.add(new BeginNode());
- calleeEntryNode.setNext(duplicatedInvoke.asNode());
-
- AbstractEndNode endNode = graph.add(new EndNode());
- duplicatedInvoke.setNext(endNode);
- returnMerge.addForwardEnd(endNode);
-
- if (returnValuePhi != null) {
- returnValuePhi.addInput(duplicatedInvoke.asNode());
- }
- return calleeEntryNode;
- }
-
- private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
- Invoke result = (Invoke) invoke.asNode().copyWithInputs();
- Node callTarget = result.callTarget().copyWithInputs();
- result.asNode().replaceFirstInput(result.callTarget(), callTarget);
- result.setUseForInlining(useForInlining);
-
- Kind kind = invoke.asNode().getKind();
- if (kind != Kind.Void) {
- FrameState stateAfter = invoke.stateAfter();
- stateAfter = stateAfter.duplicate(stateAfter.bci);
- stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
- result.setStateAfter(stateAfter);
- }
-
- if (invoke instanceof InvokeWithExceptionNode) {
- assert exceptionMerge != null && exceptionObjectPhi != null;
-
- InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
- ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
- FrameState stateAfterException = exceptionEdge.stateAfter();
-
- ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
- // set new state (pop old exception object, push new one)
- newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
-
- AbstractEndNode endNode = graph.add(new EndNode());
- newExceptionEdge.setNext(endNode);
- exceptionMerge.addForwardEnd(endNode);
- exceptionObjectPhi.addInput(newExceptionEdge);
-
- ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
- }
- return result;
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- if (hasSingleMethod()) {
- devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
- } else {
- tryToDevirtualizeMultipleMethods(graph(), metaAccess);
- }
- }
-
- private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
- MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
- if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
- ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
- ResolvedJavaType leastCommonType = getLeastCommonType();
- // check if we have a common base type that implements the interface -> in that case
- // we have a vtable entry for the interface method and can use a less expensive
- // virtual call
- if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
- ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
- if (baseClassTargetMethod != null) {
- devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), metaAccess);
- }
- }
- }
- }
-
- private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
- BeginNode invocationEntry = graph.add(new BeginNode());
- BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
- BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
- createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
-
- invocationEntry.setNext(invoke.asNode());
- ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
- GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
- invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
- replaceInvokeCallTarget(invoke, graph, kind, target);
- }
-
- private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
- return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
- builder.append(", ");
- builder.append(concretes.size());
- builder.append(" methods [ ");
- for (int i = 0; i < concretes.size(); i++) {
- builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i)));
- }
- builder.append(" ], ");
- builder.append(ptypes.size());
- builder.append(" type checks [ ");
- for (int i = 0; i < ptypes.size(); i++) {
- builder.append(" ");
- builder.append(ptypes.get(i).getType().getName());
- builder.append(ptypes.get(i).getProbability());
- }
- builder.append(" ]");
- return builder.toString();
- }
- }
-
- /**
- * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
- * target method, but for which an assumption has to be registered because of non-final classes.
- */
- private static class AssumptionInlineInfo extends ExactInlineInfo {
-
- private final Assumption takenAssumption;
-
- public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
- super(invoke, concrete);
- this.takenAssumption = takenAssumption;
- }
-
- @Override
- public void inline(Providers providers, Assumptions assumptions) {
- assumptions.record(takenAssumption);
- super.inline(providers, assumptions);
- }
-
- @Override
- public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
- assumptions.record(takenAssumption);
- replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
- }
-
- @Override
- public String toString() {
- return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
- }
- }
-
- /**
- * Determines if inlining is possible at the given invoke node.
- *
- * @param invoke the invoke that should be inlined
- * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
- */
- public static InlineInfo getInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
- if (!checkInvokeConditions(invoke)) {
- return null;
- }
- MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
- ResolvedJavaMethod targetMethod = callTarget.targetMethod();
-
- if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, targetMethod);
- }
-
- assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
-
- ResolvedJavaType holder = targetMethod.getDeclaringClass();
- if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
- return null;
- }
- ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
- if (receiverStamp.alwaysNull()) {
- // Don't inline if receiver is known to be null
- return null;
- }
- if (receiverStamp.type() != null) {
- // the invoke target might be more specific than the holder (happens after inlining:
- // parameters lose their declared type...)
- ResolvedJavaType receiverType = receiverStamp.type();
- if (receiverType != null && holder.isAssignableFrom(receiverType)) {
- holder = receiverType;
- if (receiverStamp.isExactType()) {
- assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
- ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
- }
- }
- }
- }
-
- if (holder.isArray()) {
- // arrays can be treated as Objects
- ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
- }
- }
-
- if (assumptions.useOptimisticAssumptions()) {
- ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
- if (uniqueSubtype != null) {
- ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod);
- if (resolvedMethod != null) {
- return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
- }
- }
-
- ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
- if (concrete != null) {
- return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
- }
- }
-
- // type check based inlining
- return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts);
- }
-
- private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
- Assumption takenAssumption) {
- assert !concrete.isAbstract();
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return null;
- }
- return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
- }
-
- private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) {
- assert !targetMethod.isAbstract();
- if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) {
- return null;
- }
- return new ExactInlineInfo(invoke, targetMethod);
- }
-
- private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod,
- OptimisticOptimizations optimisticOpts) {
- JavaTypeProfile typeProfile;
- ValueNode receiver = invoke.callTarget().arguments().get(0);
- if (receiver instanceof TypeProfileProxyNode) {
- TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
- typeProfile = typeProfileProxyNode.getProfile();
- } else {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no type profile exists");
- }
-
- ProfiledType[] ptypes = typeProfile.getTypes();
- if (ptypes == null || ptypes.length <= 0) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types in profile");
- }
-
- double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
- if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
- if (!optimisticOpts.inlineMonomorphicCalls()) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
- }
-
- ResolvedJavaType type = ptypes[0].getType();
- assert type.isArray() || !type.isAbstract();
- ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return null;
- }
- return new TypeGuardInlineInfo(invoke, concrete, type);
- } else {
- invoke.setPolymorphic(true);
-
- if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
- }
- if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
- // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
- // the number of types is lower than what can be recorded in a type profile
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
- notRecordedTypeProbability * 100);
- }
-
- // Find unique methods and their probabilities.
- ArrayList concreteMethods = new ArrayList<>();
- ArrayList concreteMethodsProbabilities = new ArrayList<>();
- for (int i = 0; i < ptypes.length; i++) {
- ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
- if (concrete == null) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "could not resolve method");
- }
- int index = concreteMethods.indexOf(concrete);
- double curProbability = ptypes[i].getProbability();
- if (index < 0) {
- index = concreteMethods.size();
- concreteMethods.add(concrete);
- concreteMethodsProbabilities.add(curProbability);
- } else {
- concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
- }
- }
-
- if (concreteMethods.size() > maxNumberOfMethods) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods);
- }
-
- // Clear methods that fall below the threshold.
- if (notRecordedTypeProbability > 0) {
- ArrayList newConcreteMethods = new ArrayList<>();
- ArrayList newConcreteMethodsProbabilities = new ArrayList<>();
- for (int i = 0; i < concreteMethods.size(); ++i) {
- if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
- newConcreteMethods.add(concreteMethods.get(i));
- newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
- }
- }
-
- if (newConcreteMethods.size() == 0) {
- // No method left that is worth inlining.
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
- concreteMethods.size());
- }
-
- concreteMethods = newConcreteMethods;
- concreteMethodsProbabilities = newConcreteMethodsProbabilities;
- }
-
- // Clean out types whose methods are no longer available.
- ArrayList usedTypes = new ArrayList<>();
- ArrayList typesToConcretes = new ArrayList<>();
- for (ProfiledType type : ptypes) {
- ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
- int index = concreteMethods.indexOf(concrete);
- if (index == -1) {
- notRecordedTypeProbability += type.getProbability();
- } else {
- assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
- usedTypes.add(type);
- typesToConcretes.add(index);
- }
- }
-
- if (usedTypes.size() == 0) {
- // No type left that is worth checking for.
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
- }
-
- for (ResolvedJavaMethod concrete : concreteMethods) {
- if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
- return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
- }
- }
- return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
- }
- }
-
- private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
- return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType));
- }
-
- private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) {
- // to avoid that floating reads on receiver fields float above the type check
- return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
- }
-
- // TODO (chaeubl): cleanup this method
- private static boolean checkInvokeConditions(Invoke invoke) {
- if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
- return logNotInlinedMethod(invoke, "the invoke is dead code");
- } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
- return logNotInlinedMethod(invoke, "the invoke has already been lowered, or has been created as a low-level node");
- } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) {
- return logNotInlinedMethod(invoke, "target method is null");
- } else if (invoke.stateAfter() == null) {
- // TODO (chaeubl): why should an invoke not have a state after?
- return logNotInlinedMethod(invoke, "the invoke has no after state");
- } else if (!invoke.useForInlining()) {
- return logNotInlinedMethod(invoke, "the invoke is marked to be not used for inlining");
- } else if (((MethodCallTargetNode) invoke.callTarget()).receiver() != null && ((MethodCallTargetNode) invoke.callTarget()).receiver().isConstant() &&
- ((MethodCallTargetNode) invoke.callTarget()).receiver().asConstant().isNull()) {
- return logNotInlinedMethod(invoke, "receiver is null");
- } else {
- return true;
- }
- }
-
- private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
- if (method == null) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
- } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method");
- } else if (method.isAbstract()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
- } else if (!method.getDeclaringClass().isInitialized()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
- } else if (!method.canBeInlined()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable");
- } else if (data.countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it exceeds the maximum recursive inlining depth");
- } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(optimisticOpts)) {
- return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the callee uses less optimistic optimizations than caller");
- } else {
- return true;
- }
- }
-
- static MonitorExitNode findPrecedingMonitorExit(UnwindNode unwind) {
- Node pred = unwind.predecessor();
- while (pred != null) {
- if (pred instanceof MonitorExitNode) {
- return (MonitorExitNode) pred;
- }
- pred = pred.predecessor();
- }
- return null;
- }
-
- /**
- * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
- *
- * @param invoke the invoke that will be replaced
- * @param inlineGraph the graph that the invoke will be replaced with
- * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
- * false if no such check is required
- */
- public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
- final NodeInputList parameters = invoke.callTarget().arguments();
- FixedNode invokeNode = invoke.asNode();
- StructuredGraph graph = invokeNode.graph();
- assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
- assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
-
- FrameState stateAfter = invoke.stateAfter();
- assert stateAfter == null || stateAfter.isAlive();
- if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
- nonNullReceiver(invoke);
- }
-
- ArrayList nodes = new ArrayList<>(inlineGraph.getNodes().count());
- ArrayList returnNodes = new ArrayList<>(4);
- UnwindNode unwindNode = null;
- final StartNode entryPointNode = inlineGraph.start();
- FixedNode firstCFGNode = entryPointNode.next();
- if (firstCFGNode == null) {
- throw new IllegalStateException("Inlined graph is in invalid state");
- }
- for (Node node : inlineGraph.getNodes()) {
- if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof ParameterNode) {
- // Do nothing.
- } else {
- nodes.add(node);
- if (node instanceof ReturnNode) {
- returnNodes.add((ReturnNode) node);
- } else if (node instanceof UnwindNode) {
- assert unwindNode == null;
- unwindNode = (UnwindNode) node;
- }
- }
- }
-
- final BeginNode prevBegin = BeginNode.prevBegin(invokeNode);
- DuplicationReplacement localReplacement = new DuplicationReplacement() {
-
- public Node replacement(Node node) {
- if (node instanceof ParameterNode) {
- return parameters.get(((ParameterNode) node).index());
- } else if (node == entryPointNode) {
- return prevBegin;
- }
- return node;
- }
- };
-
- assert invokeNode.successors().first() != null : invoke;
- assert invokeNode.predecessor() != null;
-
- Map duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
- FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
- invokeNode.replaceAtPredecessor(firstCFGNodeDuplicate);
-
- FrameState stateAtExceptionEdge = null;
- if (invoke instanceof InvokeWithExceptionNode) {
- InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
- if (unwindNode != null) {
- assert unwindNode.predecessor() != null;
- assert invokeWithException.exceptionEdge().successors().count() == 1;
- ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
- stateAtExceptionEdge = obj.stateAfter();
- UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
- obj.replaceAtUsages(unwindDuplicate.exception());
- unwindDuplicate.clearInputs();
- Node n = obj.next();
- obj.setNext(null);
- unwindDuplicate.replaceAndDelete(n);
- } else {
- invokeWithException.killExceptionEdge();
- }
-
- // get rid of memory kill
- BeginNode begin = invokeWithException.next();
- if (begin instanceof KillingBeginNode) {
- BeginNode newBegin = new BeginNode();
- graph.addAfterFixed(begin, graph.add(newBegin));
- begin.replaceAtUsages(newBegin);
- graph.removeFixed(begin);
- }
- } else {
- if (unwindNode != null) {
- UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
- DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
- unwindDuplicate.replaceAndDelete(deoptimizeNode);
- }
- }
-
- if (stateAfter != null) {
- processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
- int callerLockDepth = stateAfter.nestedLockDepth();
- if (callerLockDepth != 0) {
- for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
- MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
- monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
- }
- }
- } else {
- assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
- }
- if (!returnNodes.isEmpty()) {
- FixedNode n = invoke.next();
- invoke.setNext(null);
- if (returnNodes.size() == 1) {
- ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
- Node returnValue = returnNode.result();
- invokeNode.replaceAtUsages(returnValue);
- returnNode.clearInputs();
- returnNode.replaceAndDelete(n);
- } else {
- ArrayList returnDuplicates = new ArrayList<>(returnNodes.size());
- for (ReturnNode returnNode : returnNodes) {
- returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
- }
- MergeNode merge = graph.add(new MergeNode());
- merge.setStateAfter(stateAfter);
- ValueNode returnValue = mergeReturns(merge, returnDuplicates);
- invokeNode.replaceAtUsages(returnValue);
- merge.setNext(n);
- }
- }
-
- invokeNode.replaceAtUsages(null);
- GraphUtil.killCFG(invokeNode);
-
- return duplicates;
- }
-
- protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map duplicates, FrameState stateAtExceptionEdge) {
- FrameState stateAtReturn = invoke.stateAfter();
- FrameState outerFrameState = null;
- Kind invokeReturnKind = invoke.asNode().getKind();
- for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
- FrameState frameState = (FrameState) duplicates.get(original);
- if (frameState != null && frameState.isAlive()) {
- if (frameState.bci == BytecodeFrame.AFTER_BCI) {
- /*
- * pop return kind from invoke's stateAfter and replace with this frameState's
- * return value (top of stack)
- */
- FrameState stateAfterReturn = stateAtReturn;
- if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
- stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
- }
- frameState.replaceAndDelete(stateAfterReturn);
- } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
- /*
- * pop exception object from invoke's stateAfter and replace with this
- * frameState's exception object (top of stack)
- */
- FrameState stateAfterException = stateAtExceptionEdge;
- if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
- stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
- }
- frameState.replaceAndDelete(stateAfterException);
- } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
- handleMissingAfterExceptionFrameState(frameState);
- } else {
- // only handle the outermost frame states
- if (frameState.outerFrameState() == null) {
- assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
- assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
- assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
- frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
- if (outerFrameState == null) {
- outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
- outerFrameState.setDuringCall(true);
- }
- frameState.setOuterFrameState(outerFrameState);
- }
- }
- }
- }
- }
-
- private static boolean isStateAfterException(FrameState frameState) {
- return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
- }
-
- protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
- Graph graph = nonReplaceableFrameState.graph();
- NodeWorkList workList = graph.createNodeWorkList();
- workList.add(nonReplaceableFrameState);
- for (Node node : workList) {
- FrameState fs = (FrameState) node;
- for (Node usage : fs.usages().snapshot()) {
- if (!usage.isAlive()) {
- continue;
- }
- if (usage instanceof FrameState) {
- workList.add(usage);
- } else {
- StateSplit stateSplit = (StateSplit) usage;
- FixedNode fixedStateSplit = stateSplit.asNode();
- if (fixedStateSplit instanceof MergeNode) {
- MergeNode merge = (MergeNode) fixedStateSplit;
- while (merge.isAlive()) {
- AbstractEndNode end = merge.forwardEnds().first();
- DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
- end.replaceAtPredecessor(deoptimizeNode);
- GraphUtil.killCFG(end);
- }
- } else {
- FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
- if (fixedStateSplit instanceof BeginNode) {
- deoptimizeNode = BeginNode.begin(deoptimizeNode);
- }
- fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
- GraphUtil.killCFG(fixedStateSplit);
- }
- }
- }
- }
- }
-
- public static ValueNode mergeReturns(MergeNode merge, List extends ReturnNode> returnNodes) {
- PhiNode returnValuePhi = null;
-
- for (ReturnNode returnNode : returnNodes) {
- // create and wire up a new EndNode
- EndNode endNode = merge.graph().add(new EndNode());
- merge.addForwardEnd(endNode);
-
- if (returnNode.result() != null) {
- if (returnValuePhi == null) {
- returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
- }
- returnValuePhi.addInput(returnNode.result());
- }
- returnNode.clearInputs();
- returnNode.replaceAndDelete(endNode);
-
- }
- return returnValuePhi;
- }
-
- private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map duplicates) {
- for (Node node : duplicates.values()) {
- if (node instanceof FrameState) {
- FrameState frameState = (FrameState) node;
- assert frameState.bci == BytecodeFrame.AFTER_BCI || frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
- }
- }
- return true;
- }
-
- /**
- * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null.
- */
- public static ValueNode nonNullReceiver(Invoke invoke) {
- MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
- assert !callTarget.isStatic() : callTarget.targetMethod();
- StructuredGraph graph = callTarget.graph();
- ValueNode firstParam = callTarget.arguments().get(0);
- if (firstParam.getKind() == Kind.Object && !StampTool.isObjectNonNull(firstParam)) {
- IsNullNode condition = graph.unique(new IsNullNode(firstParam));
- Stamp stamp = firstParam.stamp().join(objectNonNull());
- GuardingPiNode nonNullReceiver = graph.add(new GuardingPiNode(firstParam, condition, true, NullCheckException, InvalidateReprofile, stamp));
- graph.addBeforeFixed(invoke.asNode(), nonNullReceiver);
- callTarget.replaceFirstInput(firstParam, nonNullReceiver);
- return nonNullReceiver;
- }
- return firstParam;
- }
-
- public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
- return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null;
- }
-
- public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
- return replacements.getMethodSubstitution(target);
- }
-
- public static Class extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
- return replacements.getMacroSubstitution(target);
- }
-
- public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
- StructuredGraph graph = invoke.asNode().graph();
- if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
- assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
- InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
- }
-
- FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
-
- CallTargetNode callTarget = invoke.callTarget();
- if (invoke instanceof InvokeNode) {
- graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
- } else {
- InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
- invokeWithException.killExceptionEdge();
- graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
- }
- GraphUtil.killWithUnusedFloatingInputs(callTarget);
- return macroNode;
- }
-
- private static FixedWithNextNode createMacroNodeInstance(Class extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
- try {
- return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
- } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
- throw new GraalGraphInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
- }
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ProfileCompiledMethodsPhase.java Sat May 03 21:46:35 2014 +0200
@@ -23,6 +23,7 @@
package com.oracle.graal.phases.common;
import java.util.*;
+import java.util.function.*;
import com.oracle.graal.compiler.common.cfg.*;
import com.oracle.graal.graph.*;
@@ -33,7 +34,6 @@
import com.oracle.graal.nodes.extended.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.nodes.virtual.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.graph.*;
@@ -63,14 +63,13 @@
@Override
protected void run(StructuredGraph graph) {
- ComputeProbabilityClosure closure = new ComputeProbabilityClosure(graph);
- NodesToDoubles probabilities = closure.apply();
+ ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
SchedulePhase schedule = new SchedulePhase();
schedule.apply(graph, false);
ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true);
for (Loop loop : cfg.getLoops()) {
- double loopProbability = probabilities.get(loop.header.getBeginNode());
+ double loopProbability = probabilities.applyAsDouble(loop.header.getBeginNode());
if (loopProbability > (1D / Integer.MAX_VALUE)) {
addSectionCounters(loop.header.getBeginNode(), loop.blocks, loop.children, schedule, probabilities);
}
@@ -93,12 +92,13 @@
}
}
- private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection> childLoops, SchedulePhase schedule, NodesToDoubles probabilities) {
+ private static void addSectionCounters(FixedWithNextNode start, Collection sectionBlocks, Collection> childLoops, SchedulePhase schedule,
+ ToDoubleFunction probabilities) {
HashSet blocks = new HashSet<>(sectionBlocks);
for (Loop> loop : childLoops) {
blocks.removeAll(loop.blocks);
}
- double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.get(start);
+ double weight = getSectionWeight(schedule, probabilities, blocks) / probabilities.applyAsDouble(start);
DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next());
if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) {
DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next());
@@ -113,10 +113,10 @@
}
}
- private static double getSectionWeight(SchedulePhase schedule, NodesToDoubles probabilities, Collection blocks) {
+ private static double getSectionWeight(SchedulePhase schedule, ToDoubleFunction probabilities, Collection blocks) {
double count = 0;
for (Block block : blocks) {
- double blockProbability = probabilities.get(block.getBeginNode());
+ double blockProbability = probabilities.applyAsDouble(block.getBeginNode());
for (ScheduledNode node : schedule.getBlockToNodesMap().get(block)) {
count += blockProbability * getNodeWeight(node);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java Sat May 03 21:46:35 2014 +0200
@@ -25,6 +25,7 @@
import static com.oracle.graal.compiler.common.GraalOptions.*;
import java.util.*;
+import java.util.function.*;
import com.oracle.graal.compiler.common.*;
import com.oracle.graal.compiler.common.type.*;
@@ -153,13 +154,15 @@
@Override
protected void run(StructuredGraph graph, PhaseContext phaseContext) {
- NodesToDoubles nodeProbabilities = new ComputeProbabilityClosure(graph).apply();
+ if (graph.hasNode(MergeNode.class)) {
+ ToDoubleFunction nodeProbabilities = new FixedNodeProbabilityCache();
- // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
- // duplication.
- for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
- if (!(merge instanceof LoopBeginNode) && nodeProbabilities.get(merge) >= TailDuplicationProbability.getValue()) {
- tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
+ // A snapshot is taken here, so that new MergeNode instances aren't considered for tail
+ // duplication.
+ for (MergeNode merge : graph.getNodes(MergeNode.class).snapshot()) {
+ if (!(merge instanceof LoopBeginNode) && nodeProbabilities.applyAsDouble(merge) >= TailDuplicationProbability.getValue()) {
+ tailDuplicate(merge, DEFAULT_DECISION, null, phaseContext, canonicalizer);
+ }
}
}
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/BaseReduction.java Sat May 03 21:46:35 2014 +0200
@@ -44,11 +44,16 @@
* disadvantages.
*
*
- *
*
* This class makes available little more than a few fields and a few utility methods used
* throughout the remaining components making up control-flow sensitive reductions.
*
+ *
+ *
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ *
+ *
*/
public abstract class BaseReduction extends PostOrderNodeIterator {
@@ -83,6 +88,12 @@
this.deoptReason = deoptReason;
}
+ /*
+ * TODO Actually, we want to emit instructions to signal "should-not-reach-here". An
+ * imperfect substitute (as done here) is emitting FixedGuard(false).
+ * "should-not-reach-here" would be better for the runtime error it raises, thus pointing to
+ * a bug in FlowSensitiveReduction (the code was reachable, after all).
+ */
public void doRewrite(LogicNode falseConstant) {
StructuredGraph graph = fixed.graph();
// have to insert a FixedNode other than a ControlSinkNode
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/CheckCastReduction.java Sat May 03 21:46:35 2014 +0200
@@ -41,6 +41,11 @@
* {@link com.oracle.graal.nodes.java.CheckCastNode}.
*
*
+ *
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ *
+ *
* @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
*/
public abstract class CheckCastReduction extends GuardingPiReduction {
@@ -51,17 +56,37 @@
/**
*
- * This phase is able to refine the types of reference-values at use sites provided a
- * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} is available witnessing
- * that fact.
+ * Upon visiting a {@link com.oracle.graal.nodes.java.CheckCastNode}, based on flow-sensitive
+ * conditions, we need to determine whether:
+ *
+ * - it is redundant (in which case it should be simplified), or
+ * - flow-sensitive information can be gained from it. "Gain information from it" requires
+ * lowering the {@link com.oracle.graal.nodes.java.CheckCastNode} such that a
+ * {@link com.oracle.graal.nodes.extended.GuardingNode GuardingNode} becomes available.
+ *
*
*
*
- * This method turns non-redundant {@link com.oracle.graal.nodes.java.CheckCastNode}s into
- * {@link com.oracle.graal.nodes.GuardingPiNode}s. Once such lowering has been performed (during
- * run N of this phase) follow-up runs attempt to further simplify the resulting node, see
- * {@link EquationalReasoner#downcastGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode, Witness)}
- * and {@link #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)}
+ * This method realizes the above by testing first for situations that require less work:
+ *
+ * - the stamp of the subject deems the check-cast redundant or unsatisfiable (ie,
+ * always-succeeds or always-fails). A previous round of canonicalization takes care of this
+ * situation, however it can also arise due to consecutive runs of
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} without intervening
+ * {@link com.oracle.graal.phases.common.CanonicalizerPhase canonicalization}.
+ * -
+ * flow-sensitive information reveals the subject to be null, trivially fulfilling the
+ * check-cast.
+ * -
+ * flow-sensitive information reveals the subject to be narrower than it stamp says. If the
+ * narrower ("downcasted") value fulfills the check-cast, the check-cast is removed.
+ * -
+ * otherwise the check-cast provides additional flow-sensitive information. For that, a
+ * {@link com.oracle.graal.nodes.FixedGuardNode} is needed, as described in
+ * {@link #lowerCheckCastAnchorFriendlyWay(com.oracle.graal.nodes.java.CheckCastNode, com.oracle.graal.nodes.ValueNode)}
+ * . Please notice this lowering is currently performed unconditionally: it might occur no
+ * flow-sensitive reduction is enabled down the road.
+ *
*
*
*
@@ -155,19 +180,24 @@
*
*
* Rather than tracking the CheckCastNode via {@link com.oracle.graal.phases.common.cfs.State
- * State} (doing so woud add a special case because a
+ * State} (doing so would add a special case because a
* {@link com.oracle.graal.nodes.java.CheckCastNode} isn't a
- * {@link com.oracle.graal.nodes.extended.GuardingNode}) this method creates an anchor by
- * lowering the CheckCastNode into a FixedGuardNode. Not the same way as done by
- * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)}
- * which lowers into a {@link com.oracle.graal.nodes.GuardingPiNode} (which is not a
- * {@link com.oracle.graal.nodes.extended.GuardingNode}).
+ * {@link com.oracle.graal.nodes.extended.GuardingNode guarding node}) this method creates an
+ * anchor by lowering the CheckCastNode into a FixedGuardNode. Not the same as the
+ * {@link com.oracle.graal.nodes.java.CheckCastNode#lower(com.oracle.graal.nodes.spi.LoweringTool)
+ * lowering of a CheckCastNode} which results in a {@link com.oracle.graal.nodes.GuardingPiNode}
+ * (which is not a {@link com.oracle.graal.nodes.extended.GuardingNode guarding node}).
*
*
*
* With that, state tracking can proceed as usual.
*
*
+ *
+ * TODO This lowering is currently performed unconditionally: it might occur no flow-sensitive
+ * reduction is enabled down the road
+ *
+ *
* @see #visitCheckCastNode(com.oracle.graal.nodes.java.CheckCastNode)
*
*/
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/EquationalReasoner.java Sat May 03 21:46:35 2014 +0200
@@ -219,7 +219,7 @@
if (n == null) {
return null;
}
- assert !(n instanceof GuardNode) : "This phase not yet ready to run during MidTier";
+ assert !(n instanceof GuardNode) : "This phase not intended to run during MidTier";
if (!(n instanceof ValueNode)) {
return n;
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FixedGuardReduction.java Sat May 03 21:46:35 2014 +0200
@@ -33,6 +33,11 @@
* This class implements control-flow sensitive reductions for
* {@link com.oracle.graal.nodes.FixedGuardNode}.
*
+ *
+ *
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ *
*
* @see #visitFixedGuardNode(com.oracle.graal.nodes.FixedGuardNode)
*/
@@ -43,15 +48,33 @@
}
/**
- * In case the condition is constant,
- * {@link com.oracle.graal.nodes.FixedGuardNode#simplify(com.oracle.graal.graph.spi.SimplifierTool)
- * FixedGuardNode#simplify(SimplifierTool)} will eventually remove the
- * {@link com.oracle.graal.nodes.FixedGuardNode} ("always succeeds") or kill the code that
- * should be killed ("always fails").
+ *
+ * Upon visiting a {@link com.oracle.graal.nodes.FixedGuardNode}, based on flow-sensitive
+ * conditions, we need to determine whether:
+ *
+ * - it is redundant (in which case it should be simplified), or
+ * - flow-sensitive information can be gained from it.
+ *
+ *
*
*
- * The only thing we do here is tracking as true fact (from this program point onwards) the
- * condition of the {@link com.oracle.graal.nodes.FixedGuardNode FixedGuardNode}.
+ * This method realizes the above by inspecting the
+ * {@link com.oracle.graal.nodes.FixedGuardNode}'s condition:
+ *
+ * - a constant condition signals the node won't be reduced here
+ * - the outcome of the condition can be predicted:
+ *
+ * -
+ * "always succeeds", after finding an equivalent (or stronger)
+ * {@link com.oracle.graal.nodes.extended.GuardingNode} in scope. The
+ * {@link com.oracle.graal.nodes.FixedGuardNode} is removed after replacing its usages with the
+ * existing guarding node
+ * -
+ * "always fails", which warrants making that explicit by making the condition constant, see
+ * {@link #markFixedGuardNodeAlwaysFails(com.oracle.graal.nodes.FixedGuardNode)}
+ *
+ * - otherwise the condition is tracked flow-sensitively
+ *
*
*
*
@@ -62,6 +85,8 @@
/*
* A FixedGuardNode with LogicConstantNode condition is left untouched.
+ * `FixedGuardNode.simplify()` will eventually remove the FixedGuardNode (in case it
+ * "always succeeds") or kill code ("always fails").
*/
if (f.condition() instanceof LogicConstantNode) {
@@ -92,10 +117,10 @@
final boolean isTrue = !f.isNegated();
/*
- * FixedGuardNode requires handling similar to that of GuardingPiNode, (ie the condition
- * can't simply be deverbosified in place). A replacement anchor is needed, ie an anchor
- * that amounts to the same combination of (negated, condition) for the FixedGuardNode at
- * hand.
+ * A FixedGuardNode can only be removed provided a replacement anchor is found (so called
+ * "evidence"), ie an anchor that amounts to the same combination of (negated, condition) as
+ * for the FixedGuardNode at hand. Just deverbosifying the condition in place isn't
+ * semantics-preserving.
*/
// TODO what about isDependencyTainted
@@ -202,7 +227,8 @@
* Porcelain method.
*
*
- * The `replacement` guard must be such that it implies the `old` guard.
+ * The `replacement` guard must be such that it implies the `old` guard. Moreover, rhe
+ * `replacement` guard must be in scope.
*
*/
private void removeFixedGuardNode(FixedGuardNode old, GuardingNode replacement) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReduction.java Sat May 03 21:46:35 2014 +0200
@@ -43,20 +43,37 @@
/**
*
- * All control-flow-sensitive reductions follow the common pattern of
+ * In a nutshell, {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReductionPhase} makes a
+ * single pass in dominator-based order over the graph:
+ *
+ * - collecting properties of interest at control-splits; as well as for check-casts,
+ * guarding-pis, null-checks, and fixed-guards. Such flow-sensitive information is tracked via a
+ * dedicated {@link com.oracle.graal.phases.common.cfs.State state instance} for each control-flow
+ * path.
+ * - performing rewritings that are safe at specific program-points. This comprises:
*
- * - Recognizing properties of interest (ie, LogicNode-s) at control-flow splits, as well as upon
- * check-casts and fixed-guards.
- * - Using the information thus tracked to simplify
- *
- * - side-effects free expressions, via
+ *
- simplification of side-effects free expressions, via
* {@link com.oracle.graal.phases.common.cfs.EquationalReasoner#deverbosify(com.oracle.graal.graph.Node)}
*
- * - control-flow, eg. by eliminating redundant fixed-guards and check-casts, ie which are known
- * always to hold.
+ * - simplification of control-flow:
+ *
+ * -
+ * by simplifying the input-condition to an {@link com.oracle.graal.nodes.IfNode}
+ * -
+ * by eliminating redundant check-casts, guarding-pis, null-checks, and fixed-guards; where
+ * "redundancy" is determined using flow-sensitive information. In these cases, redundancy can be
+ * due to:
+ *
+ * - an equivalent, existing, guarding node is already in scope (thus, use it as replacement and
+ * remove the redundant one)
+ * - "always fails" (thus, replace the node in question with
FixedGuardNode(false)
)
*
*
*
+ *
+ *
+ *
+ *
*
*
* @see com.oracle.graal.phases.common.cfs.CheckCastReduction
@@ -145,6 +162,9 @@
if (begin instanceof LoopExitNode) {
state.clear();
+ /*
+ * TODO return or not? (by not returning we agree it's ok to update the state as below)
+ */
}
if (pred instanceof IfNode) {
@@ -253,7 +273,7 @@
public boolean deverbosifyInputsInPlace(ValueNode parent) {
boolean changed = false;
for (ValueNode i : FlowUtil.distinctValueAndConditionInputs(parent)) {
- assert !(i instanceof GuardNode) : "ConditionalElim shouldn't run in MidTier";
+ assert !(i instanceof GuardNode) : "This phase not intended to run during MidTier";
ValueNode j = (ValueNode) reasoner.deverbosify(i);
if (i != j) {
changed = true;
@@ -390,7 +410,7 @@
* Step 5: After special-case handling, we do our best for those FixedNode-s
* where the effort to reduce their inputs might pay off.
*
- * Why is this useful? For example, by the time the AbstractBeginNode for an If-branch
+ * Why is this useful? For example, by the time the BeginNode for an If-branch
* is visited (in general a ControlSplitNode), the If-condition will have gone already
* through simplification (and thus potentially have been reduced to a
* LogicConstantNode).
@@ -407,8 +427,7 @@
paysOffToReduce = true;
}
- // TODO comb the remaining FixedWithNextNode subclasses, pick those with good changes of
- // paying-off
+ // TODO comb remaining FixedWithNextNode subclasses, pick those with chances of paying-off
// TODO UnsafeLoadNode takes a condition
@@ -423,8 +442,7 @@
*/
// TODO some nodes are GuardingNodes (eg, FixedAccessNode) we could use them to track state
- // TODO others are additionally guarded (eg JavaReadNode), thus *their* guards could be
- // simplified.
+ // TODO other nodes are guarded (eg JavaReadNode), thus *their* guards could be replaced.
}
@@ -498,11 +516,29 @@
}
/**
- * One or more arguments at `invoke` may have control-flow sensitive simplifications. In such
- * case, a new {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is
- * prepared just for this callsite, consuming reduced arguments. This proves useful in
- * connection with inlining, in order to specialize callees on the types of arguments other than
- * the receiver (examples: multi-methods, the inlining problem, lambdas as arguments).
+ *
+ * For one or more `invoke` arguments, flow-sensitive information may suggest their narrowing or
+ * simplification. In those cases, a new
+ * {@link com.oracle.graal.nodes.java.MethodCallTargetNode MethodCallTargetNode} is prepared
+ * just for this callsite, consuming reduced arguments.
+ *
+ *
+ *
+ * Specializing the {@link com.oracle.graal.nodes.java.MethodCallTargetNode
+ * MethodCallTargetNode} as described above may enable two optimizations:
+ *
+ * -
+ * devirtualization of an
+ * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Interface} or
+ * {@link com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind#Virtual} callsite
+ * (devirtualization made possible after narrowing the type of the receiver)
+ * -
+ * (future work) actual-argument-aware inlining, ie, to specialize callees on the types of
+ * arguments other than the receiver (examples: multi-methods, the inlining problem, lambdas as
+ * arguments).
+ *
+ *
+ *
*
*
* Precondition: inputs haven't been deverbosified yet.
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowSensitiveReductionPhase.java Sat May 03 21:46:35 2014 +0200
@@ -43,6 +43,10 @@
@Override
protected final void run(StructuredGraph graph, PhaseContext context) {
try (Debug.Scope s = Debug.scope("FlowSensitiveReduction")) {
+ if (graph.isOSR()) {
+ Debug.log("Skipping OSR method %s", graph.method() == null ? "" : MetaUtil.format("%H.%n", graph.method()));
+ return;
+ }
Debug.dump(graph, "FlowSensitiveReduction initial");
new FlowSensitiveReduction(graph.start(), new State(), context).apply();
Debug.dump(graph, "FlowSensitiveReduction done");
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/FlowUtil.java Sat May 03 21:46:35 2014 +0200
@@ -23,10 +23,6 @@
package com.oracle.graal.phases.common.cfs;
import com.oracle.graal.api.meta.ResolvedJavaType;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugConfig;
-import com.oracle.graal.debug.DebugConfigScope;
-import com.oracle.graal.debug.internal.DebugScope;
import com.oracle.graal.graph.InputType;
import com.oracle.graal.graph.Node;
import com.oracle.graal.graph.NodeClass;
@@ -290,28 +286,4 @@
// `oldInput` if unused wil be removed in finished()
}
- public static StructuredGraph visualize(StructuredGraph graph, String title) {
- DebugConfig debugConfig = DebugScope.getConfig();
- DebugConfig fixedConfig = Debug.fixedConfig(false, true, false, false, debugConfig.dumpHandlers(), debugConfig.output());
- try (DebugConfigScope s = Debug.setConfig(fixedConfig)) {
- Debug.dump(graph, title);
-
- return graph;
- }
- }
-
- public static final String ANSI_RESET = "\u001B[0m";
- public static final String ANSI_BLACK = "\u001B[30m";
- public static final String ANSI_RED = "\u001B[31m";
- public static final String ANSI_GREEN = "\u001B[32m";
- public static final String ANSI_YELLOW = "\u001B[33m";
- public static final String ANSI_BLUE = "\u001B[34m";
- public static final String ANSI_PURPLE = "\u001B[35m";
- public static final String ANSI_CYAN = "\u001B[36m";
- public static final String ANSI_WHITE = "\u001B[37m";
-
- public static void highlightInRed(String msg) {
- System.out.println(ANSI_RED + msg + ANSI_RESET);
- }
-
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/GuardingPiReduction.java Sat May 03 21:46:35 2014 +0200
@@ -37,7 +37,12 @@
* This class implements control-flow sensitive reductions for
* {@link com.oracle.graal.nodes.GuardingPiNode}.
*
- *
+ *
+ *
+ * The laundry-list of all flow-sensitive reductions is summarized in
+ * {@link com.oracle.graal.phases.common.cfs.FlowSensitiveReduction}
+ *
+ *
* @see #visitGuardingPiNode(com.oracle.graal.nodes.GuardingPiNode)
*/
public abstract class GuardingPiReduction extends BaseReduction {
@@ -139,6 +144,12 @@
FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(envelope.condition(), envelope.getReason(), envelope.getAction(), envelope.isNegated()));
graph.addBeforeFixed(envelope, fixedGuard);
+ /*
+ *
+ * TODO This lowering is currently performed unconditionally: it might occur no
+ * flow-sensitive reduction is enabled down the road
+ */
+
if (!FlowUtil.lacksUsages(envelope)) {
// not calling wrapInPiNode() because we don't want to rememberSubstitution()
PiNode replacement = graph.unique(new PiNode(envelope.object(), envelope.stamp(), fixedGuard));
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/cfs/Histogram.java Sat May 03 21:46:35 2014 +0200
@@ -54,7 +54,7 @@
int percentOut = (int) (numCases / casesTotal * 100);
String msg = prefix + String.format("%d iters in %4d cases (%2d %%)", entry.getKey(), numCases, percentOut);
if (entry.getKey() > 3) {
- FlowUtil.highlightInRed(msg);
+ highlightInRed(msg);
} else {
System.out.println(msg);
}
@@ -67,4 +67,11 @@
return (Histogram) super.clone();
}
+ public static final String ANSI_RESET = "\u001B[0m";
+ public static final String ANSI_RED = "\u001B[31m";
+
+ public static void highlightInRed(String msg) {
+ System.out.println(ANSI_RED + msg + ANSI_RESET);
+ }
+
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/ComputeInliningRelevance.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.graal.phases.common.inlining;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+import edu.umd.cs.findbugs.annotations.*;
+
+public class ComputeInliningRelevance {
+
+ private static final double EPSILON = 1d / Integer.MAX_VALUE;
+ private static final double UNINITIALIZED = -1D;
+
+ private static final int EXPECTED_MIN_INVOKE_COUNT = 3;
+ private static final int EXPECTED_INVOKE_RATIO = 20;
+ private static final int EXPECTED_LOOP_COUNT = 3;
+
+ private final StructuredGraph graph;
+ private final ToDoubleFunction nodeProbabilities;
+
+ /**
+ * Node relevances are pre-computed for all invokes if the graph contains loops. If there are no
+ * loops, the computation happens lazily based on {@link #rootScope}.
+ */
+ private IdentityHashMap nodeRelevances;
+ /**
+ * This scope is non-null if (and only if) there are no loops in the graph. In this case, the
+ * root scope is used to compute invoke relevances on the fly.
+ */
+ private Scope rootScope;
+
+ public ComputeInliningRelevance(StructuredGraph graph, ToDoubleFunction nodeProbabilities) {
+ this.graph = graph;
+ this.nodeProbabilities = nodeProbabilities;
+ }
+
+ /**
+ * Initializes or updates the relevance computation. If there are no loops within the graph,
+ * most computation happens lazily.
+ */
+ public void compute() {
+ rootScope = null;
+ if (!graph.hasLoops()) {
+ // fast path for the frequent case of no loops
+ rootScope = new Scope(graph.start(), null);
+ } else {
+ if (nodeRelevances == null) {
+ nodeRelevances = new IdentityHashMap<>(EXPECTED_MIN_INVOKE_COUNT + graph.getNodeCount() / EXPECTED_INVOKE_RATIO);
+ }
+ NodeWorkList workList = graph.createNodeWorkList();
+ IdentityHashMap loops = new IdentityHashMap<>(EXPECTED_LOOP_COUNT);
+
+ loops.put(null, new Scope(graph.start(), null));
+ for (LoopBeginNode loopBegin : graph.getNodes(LoopBeginNode.class)) {
+ createLoopScope(loopBegin, loops);
+ }
+
+ for (Scope scope : loops.values()) {
+ scope.process(workList);
+ }
+ }
+ }
+
+ public double getRelevance(Invoke invoke) {
+ if (rootScope != null) {
+ return rootScope.computeInvokeRelevance(invoke);
+ }
+ assert nodeRelevances != null : "uninitialized relevance";
+ return nodeRelevances.get(invoke);
+ }
+
+ /**
+ * Determines the parent of the given loop and creates a {@link Scope} object for each one. This
+ * method will call itself recursively if no {@link Scope} for the parent loop exists.
+ */
+ private Scope createLoopScope(LoopBeginNode loopBegin, IdentityHashMap loops) {
+ Scope scope = loops.get(loopBegin);
+ if (scope == null) {
+ final Scope parent;
+ // look for the parent scope
+ FixedNode current = loopBegin.forwardEnd();
+ while (true) {
+ if (current.predecessor() == null) {
+ if (current instanceof LoopBeginNode) {
+ // if we reach a LoopBeginNode then we're within this loop
+ parent = createLoopScope((LoopBeginNode) current, loops);
+ break;
+ } else if (current instanceof StartNode) {
+ // we're within the outermost scope
+ parent = loops.get(null);
+ break;
+ } else {
+ assert current.getClass() == MergeNode.class : current;
+ // follow any path upwards - it doesn't matter which one
+ current = ((MergeNode) current).forwardEndAt(0);
+ }
+ } else if (current instanceof LoopExitNode) {
+ // if we reach a loop exit then we follow this loop and have the same parent
+ parent = createLoopScope(((LoopExitNode) current).loopBegin(), loops).parent;
+ break;
+ } else {
+ current = (FixedNode) current.predecessor();
+ }
+ }
+ scope = new Scope(loopBegin, parent);
+ loops.put(loopBegin, scope);
+ }
+ return scope;
+ }
+
+ /**
+ * A scope holds information for the contents of one loop or of the root of the method. It does
+ * not include child loops, i.e., the iteration in {@link #process(NodeWorkList)} explicitly
+ * excludes the nodes of child loops.
+ */
+ private class Scope {
+ public final FixedNode start;
+ public final Scope parent; // can be null for the outermost scope
+
+ /**
+ * The minimum probability along the most probable path in this scope. Computed lazily.
+ */
+ private double fastPathMinProbability = UNINITIALIZED;
+ /**
+ * A measure of how important this scope is within its parent scope. Computed lazily.
+ */
+ private double scopeRelevanceWithinParent = UNINITIALIZED;
+
+ public Scope(FixedNode start, Scope parent) {
+ this.start = start;
+ this.parent = parent;
+ }
+
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+ public double getFastPathMinProbability() {
+ if (fastPathMinProbability == UNINITIALIZED) {
+ fastPathMinProbability = Math.max(EPSILON, computeFastPathMinProbability(start));
+ }
+ return fastPathMinProbability;
+ }
+
+ /**
+ * Computes the ratio between the probabilities of the current scope's entry point and the
+ * parent scope's fastPathMinProbability.
+ */
+ @SuppressFBWarnings("FE_FLOATING_POINT_EQUALITY")
+ public double getScopeRelevanceWithinParent() {
+ if (scopeRelevanceWithinParent == UNINITIALIZED) {
+ if (start instanceof LoopBeginNode) {
+ assert parent != null;
+ double scopeEntryProbability = nodeProbabilities.applyAsDouble(((LoopBeginNode) start).forwardEnd());
+
+ scopeRelevanceWithinParent = scopeEntryProbability / parent.getFastPathMinProbability();
+ } else {
+ scopeRelevanceWithinParent = 1D;
+ }
+ }
+ return scopeRelevanceWithinParent;
+ }
+
+ /**
+ * Processes all invokes in this scope by starting at the scope's start node and iterating
+ * all fixed nodes. Child loops are skipped by going from loop entries directly to the loop
+ * exits. Processing stops at loop exits of the current loop.
+ */
+ public void process(NodeWorkList workList) {
+ assert !(start instanceof Invoke);
+ workList.addAll(start.successors());
+
+ for (Node current : workList) {
+ assert current.isAlive();
+
+ if (current instanceof Invoke) {
+ // process the invoke and queue its successors
+ nodeRelevances.put((FixedNode) current, computeInvokeRelevance((Invoke) current));
+ workList.addAll(current.successors());
+ } else if (current instanceof LoopBeginNode) {
+ // skip child loops by advancing over the loop exits
+ ((LoopBeginNode) current).loopExits().forEach(exit -> workList.add(exit.next()));
+ } else if (current instanceof LoopEndNode) {
+ // nothing to do
+ } else if (current instanceof LoopExitNode) {
+ // nothing to do
+ } else if (current instanceof FixedWithNextNode) {
+ workList.add(((FixedWithNextNode) current).next());
+ } else if (current instanceof EndNode) {
+ workList.add(((EndNode) current).merge());
+ } else if (current instanceof ControlSinkNode) {
+ // nothing to do
+ } else if (current instanceof ControlSplitNode) {
+ workList.addAll(current.successors());
+ } else {
+ assert false : current;
+ }
+ }
+ }
+
+ /**
+ * The relevance of an invoke is the ratio between the invoke's probability and the current
+ * scope's fastPathMinProbability, adjusted by scopeRelevanceWithinParent.
+ */
+ public double computeInvokeRelevance(Invoke invoke) {
+ double invokeProbability = nodeProbabilities.applyAsDouble(invoke.asNode());
+ assert !Double.isNaN(invokeProbability);
+
+ double relevance = (invokeProbability / getFastPathMinProbability()) * Math.min(1.0, getScopeRelevanceWithinParent());
+ assert !Double.isNaN(relevance);
+ return relevance;
+ }
+ }
+
+ /**
+ * Computes the minimum probability along the most probable path within the scope. During
+ * iteration, the method returns immediately once a loop exit is discovered.
+ */
+ private double computeFastPathMinProbability(FixedNode scopeStart) {
+ ArrayList pathBeginNodes = new ArrayList<>();
+ pathBeginNodes.add(scopeStart);
+ double minPathProbability = nodeProbabilities.applyAsDouble(scopeStart);
+ boolean isLoopScope = scopeStart instanceof LoopBeginNode;
+
+ do {
+ Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
+ do {
+ if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
+ return minPathProbability;
+ } else if (current instanceof LoopBeginNode && current != scopeStart) {
+ current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
+ minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+ } else if (current instanceof ControlSplitNode) {
+ current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
+ minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
+ } else {
+ assert current.successors().count() <= 1;
+ current = current.successors().first();
+ }
+ } while (current != null);
+ } while (!pathBeginNodes.isEmpty());
+
+ return minPathProbability;
+ }
+
+ private double getMinPathProbability(FixedNode current, double minPathProbability) {
+ return current == null ? minPathProbability : Math.min(minPathProbability, nodeProbabilities.applyAsDouble(current));
+ }
+
+ /**
+ * Returns the most probable successor. If multiple successors share the maximum probability,
+ * one is returned and the others are enqueued in pathBeginNodes.
+ */
+ private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) {
+ Node maxSux = null;
+ double maxProbability = 0.0;
+ int pathBeginCount = pathBeginNodes.size();
+
+ for (Node sux : controlSplit.successors()) {
+ double probability = controlSplit.probability((BeginNode) sux);
+ if (probability > maxProbability) {
+ maxProbability = probability;
+ maxSux = sux;
+ truncate(pathBeginNodes, pathBeginCount);
+ } else if (probability == maxProbability) {
+ pathBeginNodes.add((FixedNode) sux);
+ }
+ }
+
+ return maxSux;
+ }
+
+ /**
+ * Returns the most probable loop exit. If multiple successors share the maximum probability,
+ * one is returned and the others are enqueued in pathBeginNodes.
+ */
+ private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) {
+ Node maxSux = null;
+ double maxProbability = 0.0;
+ int pathBeginCount = pathBeginNodes.size();
+
+ for (LoopExitNode sux : loopBegin.loopExits()) {
+ double probability = nodeProbabilities.applyAsDouble(sux);
+ if (probability > maxProbability) {
+ maxProbability = probability;
+ maxSux = sux;
+ truncate(pathBeginNodes, pathBeginCount);
+ } else if (probability == maxProbability) {
+ pathBeginNodes.add(sux);
+ }
+ }
+
+ return maxSux;
+ }
+
+ private static void truncate(ArrayList pathBeginNodes, int pathBeginCount) {
+ for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
+ pathBeginNodes.remove(pathBeginNodes.size() - 1);
+ }
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningPhase.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,866 @@
+/*
+ * Copyright (c) 2011, 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 com.oracle.graal.phases.common.inlining;
+
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.phases.common.inlining.InliningPhase.Options.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.Graph.Mark;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.options.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.InliningUtil.InlineInfo;
+import com.oracle.graal.phases.common.inlining.InliningUtil.Inlineable;
+import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableGraph;
+import com.oracle.graal.phases.common.inlining.InliningUtil.InlineableMacroNode;
+import com.oracle.graal.phases.common.inlining.InliningUtil.InliningPolicy;
+import com.oracle.graal.phases.graph.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+
+public class InliningPhase extends AbstractInliningPhase {
+
+ static class Options {
+
+ // @formatter:off
+ @Option(help = "Unconditionally inline intrinsics")
+ public static final OptionValue AlwaysInlineIntrinsics = new OptionValue<>(false);
+ // @formatter:on
+ }
+
+ private final InliningPolicy inliningPolicy;
+ private final CanonicalizerPhase canonicalizer;
+
+ private int inliningCount;
+ private int maxMethodPerInlining = Integer.MAX_VALUE;
+
+ // Metrics
+ private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
+ private static final DebugMetric metricInliningConsidered = Debug.metric("InliningConsidered");
+ private static final DebugMetric metricInliningStoppedByMaxDesiredSize = Debug.metric("InliningStoppedByMaxDesiredSize");
+ private static final DebugMetric metricInliningRuns = Debug.metric("InliningRuns");
+
+ public InliningPhase(CanonicalizerPhase canonicalizer) {
+ this(new GreedyInliningPolicy(null), canonicalizer);
+ }
+
+ public InliningPhase(Map hints, CanonicalizerPhase canonicalizer) {
+ this(new GreedyInliningPolicy(hints), canonicalizer);
+ }
+
+ public InliningPhase(InliningPolicy policy, CanonicalizerPhase canonicalizer) {
+ this.inliningPolicy = policy;
+ this.canonicalizer = canonicalizer;
+ }
+
+ public void setMaxMethodsPerInlining(int max) {
+ maxMethodPerInlining = max;
+ }
+
+ public int getInliningCount() {
+ return inliningCount;
+ }
+
+ @Override
+ protected void run(final StructuredGraph graph, final HighTierContext context) {
+ final InliningData data = new InliningData(graph, context.getAssumptions());
+ ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
+
+ while (data.hasUnprocessedGraphs()) {
+ final MethodInvocation currentInvocation = data.currentInvocation();
+ GraphInfo graphInfo = data.currentGraph();
+ if (!currentInvocation.isRoot() &&
+ !inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), currentInvocation.callee(), data.inliningDepth(), currentInvocation.probability(),
+ currentInvocation.relevance(), false)) {
+ int remainingGraphs = currentInvocation.totalGraphs() - currentInvocation.processedGraphs();
+ assert remainingGraphs > 0;
+ data.popGraphs(remainingGraphs);
+ data.popInvocation();
+ } else if (graphInfo.hasRemainingInvokes() && inliningPolicy.continueInlining(graphInfo.graph())) {
+ processNextInvoke(data, graphInfo, context);
+ } else {
+ data.popGraph();
+ if (!currentInvocation.isRoot()) {
+ assert currentInvocation.callee().invoke().asNode().isAlive();
+ currentInvocation.incrementProcessedGraphs();
+ if (currentInvocation.processedGraphs() == currentInvocation.totalGraphs()) {
+ data.popInvocation();
+ final MethodInvocation parentInvoke = data.currentInvocation();
+ try (Scope s = Debug.scope("Inlining", data.inliningContext())) {
+ tryToInline(probabilities, data.currentGraph(), currentInvocation, parentInvoke, data.inliningDepth() + 1, context);
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+ }
+ }
+ }
+
+ assert data.inliningDepth() == 0;
+ assert data.graphCount() == 0;
+ }
+
+ /**
+ * Process the next invoke and enqueue all its graphs for processing.
+ */
+ private void processNextInvoke(InliningData data, GraphInfo graphInfo, HighTierContext context) {
+ Invoke invoke = graphInfo.popInvoke();
+ MethodInvocation callerInvocation = data.currentInvocation();
+ Assumptions parentAssumptions = callerInvocation.assumptions();
+ InlineInfo info = InliningUtil.getInlineInfo(data, invoke, maxMethodPerInlining, context.getReplacements(), parentAssumptions, context.getOptimisticOptimizations());
+
+ if (info != null) {
+ double invokeProbability = graphInfo.invokeProbability(invoke);
+ double invokeRelevance = graphInfo.invokeRelevance(invoke);
+ MethodInvocation calleeInvocation = data.pushInvocation(info, parentAssumptions, invokeProbability, invokeRelevance);
+
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable elem = getInlineableElement(info.methodAt(i), info.invoke(), context.replaceAssumptions(calleeInvocation.assumptions()));
+ info.setInlinableElement(i, elem);
+ if (elem instanceof InlineableGraph) {
+ data.pushGraph(((InlineableGraph) elem).getGraph(), invokeProbability * info.probabilityAt(i), invokeRelevance * info.relevanceAt(i));
+ } else {
+ assert elem instanceof InlineableMacroNode;
+ data.pushDummyGraph();
+ }
+ }
+ }
+ }
+
+ private void tryToInline(ToDoubleFunction probabilities, GraphInfo callerGraphInfo, MethodInvocation calleeInfo, MethodInvocation parentInvocation, int inliningDepth,
+ HighTierContext context) {
+ InlineInfo callee = calleeInfo.callee();
+ Assumptions callerAssumptions = parentInvocation.assumptions();
+
+ if (inliningPolicy.isWorthInlining(probabilities, context.getReplacements(), callee, inliningDepth, calleeInfo.probability(), calleeInfo.relevance(), true)) {
+ doInline(callerGraphInfo, calleeInfo, callerAssumptions, context);
+ } else if (context.getOptimisticOptimizations().devirtualizeInvokes()) {
+ callee.tryToDevirtualizeInvoke(context.getMetaAccess(), callerAssumptions);
+ }
+ metricInliningConsidered.increment();
+ }
+
+ private void doInline(GraphInfo callerGraphInfo, MethodInvocation calleeInfo, Assumptions callerAssumptions, HighTierContext context) {
+ StructuredGraph callerGraph = callerGraphInfo.graph();
+ Mark markBeforeInlining = callerGraph.getMark();
+ InlineInfo callee = calleeInfo.callee();
+ try {
+ try (Scope scope = Debug.scope("doInline", callerGraph)) {
+ List invokeUsages = callee.invoke().asNode().usages().snapshot();
+ callee.inline(new Providers(context), callerAssumptions);
+ callerAssumptions.record(calleeInfo.assumptions());
+ metricInliningRuns.increment();
+ Debug.dump(callerGraph, "after %s", callee);
+
+ if (OptCanonicalizer.getValue()) {
+ Mark markBeforeCanonicalization = callerGraph.getMark();
+ canonicalizer.applyIncremental(callerGraph, context, invokeUsages, markBeforeInlining);
+
+ // process invokes that are possibly created during canonicalization
+ for (Node newNode : callerGraph.getNewNodes(markBeforeCanonicalization)) {
+ if (newNode instanceof Invoke) {
+ callerGraphInfo.pushInvoke((Invoke) newNode);
+ }
+ }
+ }
+
+ callerGraphInfo.computeProbabilities();
+
+ inliningCount++;
+ metricInliningPerformed.increment();
+ }
+ } catch (BailoutException bailout) {
+ throw bailout;
+ } catch (AssertionError | RuntimeException e) {
+ throw new GraalInternalError(e).addContext(callee.toString());
+ } catch (GraalInternalError e) {
+ throw e.addContext(callee.toString());
+ }
+ }
+
+ private Inlineable getInlineableElement(final ResolvedJavaMethod method, Invoke invoke, HighTierContext context) {
+ Class extends FixedWithNextNode> macroNodeClass = InliningUtil.getMacroNodeClass(context.getReplacements(), method);
+ if (macroNodeClass != null) {
+ return new InlineableMacroNode(macroNodeClass);
+ } else {
+ return new InlineableGraph(buildGraph(method, invoke, context));
+ }
+ }
+
+ private StructuredGraph buildGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context) {
+ final StructuredGraph newGraph;
+ final boolean parseBytecodes;
+
+ // TODO (chaeubl): copying the graph is only necessary if it is modified or if it contains
+ // any invokes
+ StructuredGraph intrinsicGraph = InliningUtil.getIntrinsicGraph(context.getReplacements(), method);
+ if (intrinsicGraph != null) {
+ newGraph = intrinsicGraph.copy();
+ parseBytecodes = false;
+ } else {
+ StructuredGraph cachedGraph = getCachedGraph(method, context);
+ if (cachedGraph != null) {
+ newGraph = cachedGraph.copy();
+ parseBytecodes = false;
+ } else {
+ newGraph = new StructuredGraph(method);
+ parseBytecodes = true;
+ }
+ }
+
+ try (Scope s = Debug.scope("InlineGraph", newGraph)) {
+ if (parseBytecodes) {
+ parseBytecodes(newGraph, context);
+ }
+
+ boolean callerHasMoreInformationAboutArguments = false;
+ NodeInputList args = invoke.callTarget().arguments();
+ for (ParameterNode param : newGraph.getNodes(ParameterNode.class).snapshot()) {
+ ValueNode arg = args.get(param.index());
+ if (arg.isConstant()) {
+ Constant constant = arg.asConstant();
+ newGraph.replaceFloating(param, ConstantNode.forConstant(constant, context.getMetaAccess(), newGraph));
+ callerHasMoreInformationAboutArguments = true;
+ } else {
+ Stamp joinedStamp = param.stamp().join(arg.stamp());
+ if (joinedStamp != null && !joinedStamp.equals(param.stamp())) {
+ param.setStamp(joinedStamp);
+ callerHasMoreInformationAboutArguments = true;
+ }
+ }
+ }
+
+ if (!callerHasMoreInformationAboutArguments) {
+ // TODO (chaeubl): if args are not more concrete, inlining should be avoided
+ // in most cases or we could at least use the previous graph size + invoke
+ // probability to check the inlining
+ }
+
+ if (OptCanonicalizer.getValue()) {
+ canonicalizer.apply(newGraph, context);
+ }
+
+ return newGraph;
+ } catch (Throwable e) {
+ throw Debug.handle(e);
+ }
+ }
+
+ private static StructuredGraph getCachedGraph(ResolvedJavaMethod method, HighTierContext context) {
+ if (context.getGraphCache() != null) {
+ StructuredGraph cachedGraph = context.getGraphCache().get(method);
+ if (cachedGraph != null) {
+ return cachedGraph;
+ }
+ }
+ return null;
+ }
+
+ private StructuredGraph parseBytecodes(StructuredGraph newGraph, HighTierContext context) {
+ boolean hasMatureProfilingInfo = newGraph.method().getProfilingInfo().isMature();
+
+ if (context.getGraphBuilderSuite() != null) {
+ context.getGraphBuilderSuite().apply(newGraph, context);
+ }
+ assert newGraph.start().next() != null : "graph needs to be populated during PhasePosition.AFTER_PARSING";
+
+ new DeadCodeEliminationPhase().apply(newGraph);
+
+ if (OptCanonicalizer.getValue()) {
+ canonicalizer.apply(newGraph, context);
+ }
+
+ if (hasMatureProfilingInfo && context.getGraphCache() != null) {
+ context.getGraphCache().put(newGraph.method(), newGraph.copy());
+ }
+ return newGraph;
+ }
+
+ private abstract static class AbstractInliningPolicy implements InliningPolicy {
+
+ protected final Map hints;
+
+ public AbstractInliningPolicy(Map hints) {
+ this.hints = hints;
+ }
+
+ protected double computeMaximumSize(double relevance, int configuredMaximum) {
+ double inlineRatio = Math.min(RelevanceCapForInlining.getValue(), relevance);
+ return configuredMaximum * inlineRatio;
+ }
+
+ protected double getInliningBonus(InlineInfo info) {
+ if (hints != null && hints.containsKey(info.invoke())) {
+ return hints.get(info.invoke());
+ }
+ return 1;
+ }
+
+ protected boolean isIntrinsic(Replacements replacements, InlineInfo info) {
+ if (AlwaysInlineIntrinsics.getValue()) {
+ return onlyIntrinsics(replacements, info);
+ } else {
+ return onlyForcedIntrinsics(replacements, info);
+ }
+ }
+
+ private static boolean onlyIntrinsics(Replacements replacements, InlineInfo info) {
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean onlyForcedIntrinsics(Replacements replacements, InlineInfo info) {
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ if (!InliningUtil.canIntrinsify(replacements, info.methodAt(i))) {
+ return false;
+ }
+ if (!replacements.isForcedSubstitution(info.methodAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected static int previousLowLevelGraphSize(InlineInfo info) {
+ int size = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ ResolvedJavaMethod m = info.methodAt(i);
+ ProfilingInfo profile = m.getProfilingInfo();
+ int compiledGraphSize = profile.getCompilerIRSize(StructuredGraph.class);
+ if (compiledGraphSize > 0) {
+ size += compiledGraphSize;
+ }
+ }
+ return size;
+ }
+
+ protected static int determineNodeCount(InlineInfo info) {
+ int nodes = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable elem = info.inlineableElementAt(i);
+ if (elem != null) {
+ nodes += elem.getNodeCount();
+ }
+ }
+ return nodes;
+ }
+
+ protected static double determineInvokeProbability(ToDoubleFunction probabilities, InlineInfo info) {
+ double invokeProbability = 0;
+ for (int i = 0; i < info.numberOfMethods(); i++) {
+ Inlineable callee = info.inlineableElementAt(i);
+ Iterable invokes = callee.getInvokes();
+ if (invokes.iterator().hasNext()) {
+ for (Invoke invoke : invokes) {
+ invokeProbability += probabilities.applyAsDouble(invoke.asNode());
+ }
+ }
+ }
+ return invokeProbability;
+ }
+ }
+
+ public static class GreedyInliningPolicy extends AbstractInliningPolicy {
+
+ public GreedyInliningPolicy(Map hints) {
+ super(hints);
+ }
+
+ public boolean continueInlining(StructuredGraph currentGraph) {
+ if (currentGraph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+ InliningUtil.logInliningDecision("inlining is cut off by MaximumDesiredSize");
+ metricInliningStoppedByMaxDesiredSize.increment();
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+ boolean fullyProcessed) {
+ if (InlineEverything.getValue()) {
+ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
+ }
+
+ if (isIntrinsic(replacements, info)) {
+ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
+ }
+
+ if (info.shouldInline()) {
+ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
+ }
+
+ double inliningBonus = getInliningBonus(info);
+ int nodes = determineNodeCount(info);
+ int lowLevelGraphSize = previousLowLevelGraphSize(info);
+
+ if (SmallCompiledLowLevelGraphSize.getValue() > 0 && lowLevelGraphSize > SmallCompiledLowLevelGraphSize.getValue() * inliningBonus) {
+ return InliningUtil.logNotInlinedMethod(info, inliningDepth, "too large previous low-level graph (low-level-nodes: %d, relevance=%f, probability=%f, bonus=%f, nodes=%d)",
+ lowLevelGraphSize, relevance, probability, inliningBonus, nodes);
+ }
+
+ if (nodes < TrivialInliningSize.getValue() * inliningBonus) {
+ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
+ }
+
+ /*
+ * TODO (chaeubl): invoked methods that are on important paths but not yet compiled ->
+ * will be compiled anyways and it is likely that we are the only caller... might be
+ * useful to inline those methods but increases bootstrap time (maybe those methods are
+ * also getting queued in the compilation queue concurrently)
+ */
+ double invokes = determineInvokeProbability(probabilities, info);
+ if (LimitInlinedInvokes.getValue() > 0 && fullyProcessed && invokes > LimitInlinedInvokes.getValue() * inliningBonus) {
+ return InliningUtil.logNotInlinedMethod(info, inliningDepth, "callee invoke probability is too high (invokeP=%f, relevance=%f, probability=%f, bonus=%f, nodes=%d)", invokes,
+ relevance, probability, inliningBonus, nodes);
+ }
+
+ double maximumNodes = computeMaximumSize(relevance, (int) (MaximumInliningSize.getValue() * inliningBonus));
+ if (nodes <= maximumNodes) {
+ return InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability,
+ inliningBonus, nodes, maximumNodes);
+ }
+
+ return InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes,
+ maximumNodes);
+ }
+ }
+
+ public static final class InlineEverythingPolicy implements InliningPolicy {
+
+ public boolean continueInlining(StructuredGraph graph) {
+ if (graph.getNodeCount() >= MaximumDesiredSize.getValue()) {
+ throw new BailoutException("Inline all calls failed. The resulting graph is too large.");
+ }
+ return true;
+ }
+
+ public boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance,
+ boolean fullyProcessed) {
+ return true;
+ }
+ }
+
+ private static class InliningIterator {
+
+ private final FixedNode start;
+ private final Deque nodeQueue;
+ private final NodeBitMap queuedNodes;
+
+ public InliningIterator(FixedNode start, NodeBitMap visitedFixedNodes) {
+ this.start = start;
+ this.nodeQueue = new ArrayDeque<>();
+ this.queuedNodes = visitedFixedNodes;
+ assert start.isAlive();
+ }
+
+ public LinkedList apply() {
+ LinkedList invokes = new LinkedList<>();
+ FixedNode current;
+ forcedQueue(start);
+
+ while ((current = nextQueuedNode()) != null) {
+ assert current.isAlive();
+
+ if (current instanceof Invoke && ((Invoke) current).callTarget() instanceof MethodCallTargetNode) {
+ if (current != start) {
+ invokes.addLast((Invoke) current);
+ }
+ queueSuccessors(current);
+ } else if (current instanceof LoopBeginNode) {
+ queueSuccessors(current);
+ } else if (current instanceof LoopEndNode) {
+ // nothing todo
+ } else if (current instanceof MergeNode) {
+ queueSuccessors(current);
+ } else if (current instanceof FixedWithNextNode) {
+ queueSuccessors(current);
+ } else if (current instanceof EndNode) {
+ queueMerge((EndNode) current);
+ } else if (current instanceof ControlSinkNode) {
+ // nothing todo
+ } else if (current instanceof ControlSplitNode) {
+ queueSuccessors(current);
+ } else {
+ assert false : current;
+ }
+ }
+
+ return invokes;
+ }
+
+ private void queueSuccessors(FixedNode x) {
+ for (Node node : x.successors()) {
+ queue(node);
+ }
+ }
+
+ private void queue(Node node) {
+ if (node != null && !queuedNodes.isMarked(node)) {
+ forcedQueue(node);
+ }
+ }
+
+ private void forcedQueue(Node node) {
+ queuedNodes.mark(node);
+ nodeQueue.addFirst((FixedNode) node);
+ }
+
+ private FixedNode nextQueuedNode() {
+ if (nodeQueue.isEmpty()) {
+ return null;
+ }
+
+ FixedNode result = nodeQueue.removeFirst();
+ assert queuedNodes.isMarked(result);
+ return result;
+ }
+
+ private void queueMerge(AbstractEndNode end) {
+ MergeNode merge = end.merge();
+ if (!queuedNodes.isMarked(merge) && visitedAllEnds(merge)) {
+ queuedNodes.mark(merge);
+ nodeQueue.add(merge);
+ }
+ }
+
+ private boolean visitedAllEnds(MergeNode merge) {
+ for (int i = 0; i < merge.forwardEndCount(); i++) {
+ if (!queuedNodes.isMarked(merge.forwardEndAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Holds the data for building the callee graphs recursively: graphs and invocations (each
+ * invocation can have multiple graphs).
+ */
+ static class InliningData {
+
+ private static final GraphInfo DummyGraphInfo = new GraphInfo(null, new LinkedList(), 1.0, 1.0);
+
+ /**
+ * Call hierarchy from outer most call (i.e., compilation unit) to inner most callee.
+ */
+ private final ArrayDeque graphQueue;
+ private final ArrayDeque invocationQueue;
+
+ private int maxGraphs;
+
+ public InliningData(StructuredGraph rootGraph, Assumptions rootAssumptions) {
+ this.graphQueue = new ArrayDeque<>();
+ this.invocationQueue = new ArrayDeque<>();
+ this.maxGraphs = 1;
+
+ invocationQueue.push(new MethodInvocation(null, rootAssumptions, 1.0, 1.0));
+ pushGraph(rootGraph, 1.0, 1.0);
+ }
+
+ public int graphCount() {
+ return graphQueue.size();
+ }
+
+ public void pushGraph(StructuredGraph graph, double probability, double relevance) {
+ assert !contains(graph);
+ NodeBitMap visitedFixedNodes = graph.createNodeBitMap();
+ LinkedList invokes = new InliningIterator(graph.start(), visitedFixedNodes).apply();
+ assert invokes.size() == count(graph.getInvokes());
+ graphQueue.push(new GraphInfo(graph, invokes, probability, relevance));
+ assert graphQueue.size() <= maxGraphs;
+ }
+
+ public void pushDummyGraph() {
+ graphQueue.push(DummyGraphInfo);
+ }
+
+ public boolean hasUnprocessedGraphs() {
+ return !graphQueue.isEmpty();
+ }
+
+ public GraphInfo currentGraph() {
+ return graphQueue.peek();
+ }
+
+ public void popGraph() {
+ graphQueue.pop();
+ assert graphQueue.size() <= maxGraphs;
+ }
+
+ public void popGraphs(int count) {
+ assert count >= 0;
+ for (int i = 0; i < count; i++) {
+ graphQueue.pop();
+ }
+ }
+
+ private static final Object[] NO_CONTEXT = {};
+
+ /**
+ * Gets the call hierarchy of this inlining from outer most call to inner most callee.
+ */
+ public Object[] inliningContext() {
+ if (!Debug.isDumpEnabled()) {
+ return NO_CONTEXT;
+ }
+ Object[] result = new Object[graphQueue.size()];
+ int i = 0;
+ for (GraphInfo g : graphQueue) {
+ result[i++] = g.graph.method();
+ }
+ return result;
+ }
+
+ public MethodInvocation currentInvocation() {
+ return invocationQueue.peekFirst();
+ }
+
+ public MethodInvocation pushInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+ MethodInvocation methodInvocation = new MethodInvocation(info, new Assumptions(assumptions.useOptimisticAssumptions()), probability, relevance);
+ invocationQueue.addFirst(methodInvocation);
+ maxGraphs += info.numberOfMethods();
+ assert graphQueue.size() <= maxGraphs;
+ return methodInvocation;
+ }
+
+ public void popInvocation() {
+ maxGraphs -= invocationQueue.peekFirst().callee.numberOfMethods();
+ assert graphQueue.size() <= maxGraphs;
+ invocationQueue.removeFirst();
+ }
+
+ public int countRecursiveInlining(ResolvedJavaMethod method) {
+ int count = 0;
+ for (GraphInfo graphInfo : graphQueue) {
+ if (method.equals(graphInfo.method())) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ public int inliningDepth() {
+ assert invocationQueue.size() > 0;
+ return invocationQueue.size() - 1;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder("Invocations: ");
+
+ for (MethodInvocation invocation : invocationQueue) {
+ if (invocation.callee() != null) {
+ result.append(invocation.callee().numberOfMethods());
+ result.append("x ");
+ result.append(invocation.callee().invoke());
+ result.append("; ");
+ }
+ }
+
+ result.append("\nGraphs: ");
+ for (GraphInfo graph : graphQueue) {
+ result.append(graph.graph());
+ result.append("; ");
+ }
+
+ return result.toString();
+ }
+
+ private boolean contains(StructuredGraph graph) {
+ for (GraphInfo info : graphQueue) {
+ if (info.graph() == graph) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static int count(Iterable invokes) {
+ int count = 0;
+ Iterator iterator = invokes.iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ count++;
+ }
+ return count;
+ }
+ }
+
+ private static class MethodInvocation {
+
+ private final InlineInfo callee;
+ private final Assumptions assumptions;
+ private final double probability;
+ private final double relevance;
+
+ private int processedGraphs;
+
+ public MethodInvocation(InlineInfo info, Assumptions assumptions, double probability, double relevance) {
+ this.callee = info;
+ this.assumptions = assumptions;
+ this.probability = probability;
+ this.relevance = relevance;
+ }
+
+ public void incrementProcessedGraphs() {
+ processedGraphs++;
+ assert processedGraphs <= callee.numberOfMethods();
+ }
+
+ public int processedGraphs() {
+ assert processedGraphs <= callee.numberOfMethods();
+ return processedGraphs;
+ }
+
+ public int totalGraphs() {
+ return callee.numberOfMethods();
+ }
+
+ public InlineInfo callee() {
+ return callee;
+ }
+
+ public Assumptions assumptions() {
+ return assumptions;
+ }
+
+ public double probability() {
+ return probability;
+ }
+
+ public double relevance() {
+ return relevance;
+ }
+
+ public boolean isRoot() {
+ return callee == null;
+ }
+
+ @Override
+ public String toString() {
+ if (isRoot()) {
+ return "";
+ }
+ CallTargetNode callTarget = callee.invoke().callTarget();
+ if (callTarget instanceof MethodCallTargetNode) {
+ ResolvedJavaMethod calleeMethod = ((MethodCallTargetNode) callTarget).targetMethod();
+ return MetaUtil.format("Invoke#%H.%n(%p)", calleeMethod);
+ } else {
+ return "Invoke#" + callTarget.targetName();
+ }
+ }
+ }
+
+ /**
+ * Information about a graph that will potentially be inlined. This includes tracking the
+ * invocations in graph that will subject to inlining themselves.
+ */
+ private static class GraphInfo {
+
+ private final StructuredGraph graph;
+ private final LinkedList remainingInvokes;
+ private final double probability;
+ private final double relevance;
+
+ private final ToDoubleFunction probabilities;
+ private final ComputeInliningRelevance computeInliningRelevance;
+
+ public GraphInfo(StructuredGraph graph, LinkedList invokes, double probability, double relevance) {
+ this.graph = graph;
+ this.remainingInvokes = invokes;
+ this.probability = probability;
+ this.relevance = relevance;
+
+ if (graph != null && (graph.hasNode(InvokeNode.class) || graph.hasNode(InvokeWithExceptionNode.class))) {
+ probabilities = new FixedNodeProbabilityCache();
+ computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities);
+ computeProbabilities();
+ } else {
+ probabilities = null;
+ computeInliningRelevance = null;
+ }
+ }
+
+ /**
+ * Gets the method associated with the {@linkplain #graph() graph} represented by this
+ * object.
+ */
+ public ResolvedJavaMethod method() {
+ return graph.method();
+ }
+
+ public boolean hasRemainingInvokes() {
+ return !remainingInvokes.isEmpty();
+ }
+
+ /**
+ * The graph about which this object contains inlining information.
+ */
+ public StructuredGraph graph() {
+ return graph;
+ }
+
+ public Invoke popInvoke() {
+ return remainingInvokes.removeFirst();
+ }
+
+ public void pushInvoke(Invoke invoke) {
+ remainingInvokes.push(invoke);
+ }
+
+ public void computeProbabilities() {
+ computeInliningRelevance.compute();
+ }
+
+ public double invokeProbability(Invoke invoke) {
+ return probability * probabilities.applyAsDouble(invoke.asNode());
+ }
+
+ public double invokeRelevance(Invoke invoke) {
+ return Math.min(CapInheritedRelevance.getValue(), relevance) * computeInliningRelevance.getRelevance(invoke);
+ }
+
+ @Override
+ public String toString() {
+ return (graph != null ? MetaUtil.format("%H.%n(%p)", method()) : "") + remainingInvokes;
+ }
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/InliningUtil.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,1610 @@
+/*
+ * Copyright (c) 2012, 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 com.oracle.graal.phases.common.inlining;
+
+import static com.oracle.graal.api.meta.DeoptimizationAction.*;
+import static com.oracle.graal.api.meta.DeoptimizationReason.*;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.compiler.common.type.StampFactory.*;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.Assumptions.Assumption;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.meta.JavaTypeProfile.ProfiledType;
+import com.oracle.graal.api.meta.ResolvedJavaType.Representation;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.calc.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.debug.Debug.Scope;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Graph.DuplicationReplacement;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.calc.*;
+import com.oracle.graal.nodes.extended.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+import com.oracle.graal.nodes.util.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.InliningPhase.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
+
+public class InliningUtil {
+
+ private static final DebugMetric metricInliningTailDuplication = Debug.metric("InliningTailDuplication");
+ private static final String inliningDecisionsScopeString = "InliningDecisions";
+ /**
+ * Meters the size (in bytecodes) of all methods processed during compilation (i.e., top level
+ * and all inlined methods), irrespective of how many bytecodes in each method are actually
+ * parsed (which may be none for methods whose IR is retrieved from a cache).
+ */
+ public static final DebugMetric InlinedBytecodes = Debug.metric("InlinedBytecodes");
+
+ public interface InliningPolicy {
+
+ boolean continueInlining(StructuredGraph graph);
+
+ boolean isWorthInlining(ToDoubleFunction probabilities, Replacements replacements, InlineInfo info, int inliningDepth, double probability, double relevance, boolean fullyProcessed);
+ }
+
+ public interface Inlineable {
+
+ int getNodeCount();
+
+ Iterable getInvokes();
+ }
+
+ public static class InlineableGraph implements Inlineable {
+
+ private final StructuredGraph graph;
+
+ public InlineableGraph(StructuredGraph graph) {
+ this.graph = graph;
+ }
+
+ @Override
+ public int getNodeCount() {
+ return graph.getNodeCount();
+ }
+
+ @Override
+ public Iterable getInvokes() {
+ return graph.getInvokes();
+ }
+
+ public StructuredGraph getGraph() {
+ return graph;
+ }
+ }
+
+ public static class InlineableMacroNode implements Inlineable {
+
+ private final Class extends FixedWithNextNode> macroNodeClass;
+
+ public InlineableMacroNode(Class extends FixedWithNextNode> macroNodeClass) {
+ this.macroNodeClass = macroNodeClass;
+ }
+
+ @Override
+ public int getNodeCount() {
+ return 1;
+ }
+
+ @Override
+ public Iterable getInvokes() {
+ return Collections.emptyList();
+ }
+
+ public Class extends FixedWithNextNode> getMacroNodeClass() {
+ return macroNodeClass;
+ }
+ }
+
+ /**
+ * Print a HotSpot-style inlining message to the console.
+ */
+ private static void printInlining(final InlineInfo info, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+ printInlining(info.methodAt(0), info.invoke(), inliningDepth, success, msg, args);
+ }
+
+ /**
+ * Print a HotSpot-style inlining message to the console.
+ */
+ private static void printInlining(final ResolvedJavaMethod method, final Invoke invoke, final int inliningDepth, final boolean success, final String msg, final Object... args) {
+ if (HotSpotPrintInlining.getValue()) {
+ // 1234567
+ TTY.print(" "); // print timestamp
+ // 1234
+ TTY.print(" "); // print compilation number
+ // % s ! b n
+ TTY.print("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' ');
+ TTY.print(" "); // more indent
+ TTY.print(" "); // initial inlining indent
+ for (int i = 0; i < inliningDepth; i++) {
+ TTY.print(" ");
+ }
+ TTY.println(String.format("@ %d %s %s%s", invoke.bci(), methodName(method, null), success ? "" : "not inlining ", String.format(msg, args)));
+ }
+ }
+
+ public static boolean logInlinedMethod(InlineInfo info, int inliningDepth, boolean allowLogging, String msg, Object... args) {
+ return logInliningDecision(info, inliningDepth, allowLogging, true, msg, args);
+ }
+
+ public static boolean logNotInlinedMethod(InlineInfo info, int inliningDepth, String msg, Object... args) {
+ return logInliningDecision(info, inliningDepth, true, false, msg, args);
+ }
+
+ public static boolean logInliningDecision(InlineInfo info, int inliningDepth, boolean allowLogging, boolean success, String msg, final Object... args) {
+ if (allowLogging) {
+ printInlining(info, inliningDepth, success, msg, args);
+ if (shouldLogInliningDecision()) {
+ logInliningDecision(methodName(info), success, msg, args);
+ }
+ }
+ return success;
+ }
+
+ public static void logInliningDecision(final String msg, final Object... args) {
+ try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+ // Can't use log here since we are varargs
+ if (Debug.isLogEnabled()) {
+ Debug.logv(msg, args);
+ }
+ }
+ }
+
+ private static boolean logNotInlinedMethod(Invoke invoke, String msg) {
+ if (shouldLogInliningDecision()) {
+ String methodString = invoke.toString() + (invoke.callTarget() == null ? " callTarget=null" : invoke.callTarget().targetName());
+ logInliningDecision(methodString, false, msg, new Object[0]);
+ }
+ return false;
+ }
+
+ private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
+ return logNotInlinedMethodAndReturnNull(invoke, inliningDepth, method, msg, new Object[0]);
+ }
+
+ private static InlineInfo logNotInlinedMethodAndReturnNull(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg, Object... args) {
+ printInlining(method, invoke, inliningDepth, false, msg, args);
+ if (shouldLogInliningDecision()) {
+ String methodString = methodName(method, invoke);
+ logInliningDecision(methodString, false, msg, args);
+ }
+ return null;
+ }
+
+ private static boolean logNotInlinedMethodAndReturnFalse(Invoke invoke, int inliningDepth, ResolvedJavaMethod method, String msg) {
+ printInlining(method, invoke, inliningDepth, false, msg, new Object[0]);
+ if (shouldLogInliningDecision()) {
+ String methodString = methodName(method, invoke);
+ logInliningDecision(methodString, false, msg, new Object[0]);
+ }
+ return false;
+ }
+
+ private static void logInliningDecision(final String methodString, final boolean success, final String msg, final Object... args) {
+ String inliningMsg = "inlining " + methodString + ": " + msg;
+ if (!success) {
+ inliningMsg = "not " + inliningMsg;
+ }
+ logInliningDecision(inliningMsg, args);
+ }
+
+ public static boolean shouldLogInliningDecision() {
+ try (Scope s = Debug.scope(inliningDecisionsScopeString)) {
+ return Debug.isLogEnabled();
+ }
+ }
+
+ private static String methodName(ResolvedJavaMethod method, Invoke invoke) {
+ if (invoke != null && invoke.stateAfter() != null) {
+ return methodName(invoke.stateAfter(), invoke.bci()) + ": " + MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+ } else {
+ return MetaUtil.format("%H.%n(%p):%r", method) + " (" + method.getCodeSize() + " bytes)";
+ }
+ }
+
+ private static String methodName(InlineInfo info) {
+ if (info == null) {
+ return "null";
+ } else if (info.invoke() != null && info.invoke().stateAfter() != null) {
+ return methodName(info.invoke().stateAfter(), info.invoke().bci()) + ": " + info.toString();
+ } else {
+ return info.toString();
+ }
+ }
+
+ private static String methodName(FrameState frameState, int bci) {
+ StringBuilder sb = new StringBuilder();
+ if (frameState.outerFrameState() != null) {
+ sb.append(methodName(frameState.outerFrameState(), frameState.outerFrameState().bci));
+ sb.append("->");
+ }
+ sb.append(MetaUtil.format("%h.%n", frameState.method()));
+ sb.append("@").append(bci);
+ return sb.toString();
+ }
+
+ /**
+ * Represents an opportunity for inlining at a given invoke, with the given weight and level.
+ * The weight is the amortized weight of the additional code - so smaller is better. The level
+ * is the number of nested inlinings that lead to this invoke.
+ */
+ public interface InlineInfo {
+
+ /**
+ * The graph containing the {@link #invoke() invocation} that may be inlined.
+ */
+ StructuredGraph graph();
+
+ /**
+ * The invocation that may be inlined.
+ */
+ Invoke invoke();
+
+ /**
+ * Returns the number of methods that may be inlined by the {@link #invoke() invocation}.
+ * This may be more than one in the case of a invocation profile showing a number of "hot"
+ * concrete methods dispatched to by the invocation.
+ */
+ int numberOfMethods();
+
+ ResolvedJavaMethod methodAt(int index);
+
+ Inlineable inlineableElementAt(int index);
+
+ double probabilityAt(int index);
+
+ double relevanceAt(int index);
+
+ void setInlinableElement(int index, Inlineable inlineableElement);
+
+ /**
+ * Performs the inlining described by this object and returns the node that represents the
+ * return value of the inlined method (or null for void methods and methods that have no
+ * non-exceptional exit).
+ */
+ void inline(Providers providers, Assumptions assumptions);
+
+ /**
+ * Try to make the call static bindable to avoid interface and virtual method calls.
+ */
+ void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions);
+
+ boolean shouldInline();
+ }
+
+ public abstract static class AbstractInlineInfo implements InlineInfo {
+
+ protected final Invoke invoke;
+
+ public AbstractInlineInfo(Invoke invoke) {
+ this.invoke = invoke;
+ }
+
+ @Override
+ public StructuredGraph graph() {
+ return invoke.asNode().graph();
+ }
+
+ @Override
+ public Invoke invoke() {
+ return invoke;
+ }
+
+ protected static void inline(Invoke invoke, ResolvedJavaMethod concrete, Inlineable inlineable, Assumptions assumptions, boolean receiverNullCheck) {
+ if (inlineable instanceof InlineableGraph) {
+ StructuredGraph calleeGraph = ((InlineableGraph) inlineable).getGraph();
+ InliningUtil.inline(invoke, calleeGraph, receiverNullCheck);
+ } else {
+ assert inlineable instanceof InlineableMacroNode;
+
+ Class extends FixedWithNextNode> macroNodeClass = ((InlineableMacroNode) inlineable).getMacroNodeClass();
+ inlineMacroNode(invoke, concrete, macroNodeClass);
+ }
+
+ InlinedBytecodes.add(concrete.getCodeSize());
+ assumptions.recordMethodContents(concrete);
+ }
+ }
+
+ public static void replaceInvokeCallTarget(Invoke invoke, StructuredGraph graph, InvokeKind invokeKind, ResolvedJavaMethod targetMethod) {
+ MethodCallTargetNode oldCallTarget = (MethodCallTargetNode) invoke.callTarget();
+ MethodCallTargetNode newCallTarget = graph.add(new MethodCallTargetNode(invokeKind, targetMethod, oldCallTarget.arguments().toArray(new ValueNode[0]), oldCallTarget.returnType()));
+ invoke.asNode().replaceFirstInput(oldCallTarget, newCallTarget);
+ }
+
+ /**
+ * Represents an inlining opportunity where the compiler can statically determine a monomorphic
+ * target method and therefore is able to determine the called method exactly.
+ */
+ public static class ExactInlineInfo extends AbstractInlineInfo {
+
+ protected final ResolvedJavaMethod concrete;
+ private Inlineable inlineableElement;
+ private boolean suppressNullCheck;
+
+ public ExactInlineInfo(Invoke invoke, ResolvedJavaMethod concrete) {
+ super(invoke);
+ this.concrete = concrete;
+ assert concrete != null;
+ }
+
+ public void suppressNullCheck() {
+ suppressNullCheck = true;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ inline(invoke, concrete, inlineableElement, assumptions, !suppressNullCheck);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ // nothing todo, can already be bound statically
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return 1;
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index == 0;
+ return concrete;
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public String toString() {
+ return "exact " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index == 0;
+ return inlineableElement;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index == 0;
+ this.inlineableElement = inlineableElement;
+ }
+
+ public boolean shouldInline() {
+ return concrete.shouldBeInlined();
+ }
+ }
+
+ /**
+ * Represents an inlining opportunity for which profiling information suggests a monomorphic
+ * receiver, but for which the receiver type cannot be proven. A type check guard will be
+ * generated if this inlining is performed.
+ */
+ private static class TypeGuardInlineInfo extends AbstractInlineInfo {
+
+ private final ResolvedJavaMethod concrete;
+ private final ResolvedJavaType type;
+ private Inlineable inlineableElement;
+
+ public TypeGuardInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, ResolvedJavaType type) {
+ super(invoke);
+ this.concrete = concrete;
+ this.type = type;
+ assert type.isArray() || !type.isAbstract() : type;
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return 1;
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index == 0;
+ return concrete;
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index == 0;
+ return inlineableElement;
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ assert index == 0;
+ return 1.0;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index == 0;
+ this.inlineableElement = inlineableElement;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ createGuard(graph(), providers.getMetaAccess());
+ inline(invoke, concrete, inlineableElement, assumptions, false);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ createGuard(graph(), metaAccess);
+ replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+ }
+
+ private void createGuard(StructuredGraph graph, MetaAccessProvider metaAccess) {
+ ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke);
+ ConstantNode typeHub = ConstantNode.forConstant(type.getEncoding(Representation.ObjectHub), metaAccess, graph);
+ LoadHubNode receiverHub = graph.unique(new LoadHubNode(nonNullReceiver, typeHub.getKind()));
+
+ CompareNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub);
+ FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
+ assert invoke.predecessor() != null;
+
+ ValueNode anchoredReceiver = createAnchoredReceiver(graph, guard, type, nonNullReceiver, true);
+ invoke.callTarget().replaceFirstInput(nonNullReceiver, anchoredReceiver);
+
+ graph.addBeforeFixed(invoke.asNode(), guard);
+ }
+
+ @Override
+ public String toString() {
+ return "type-checked with type " + type.getName() + " and method " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+
+ public boolean shouldInline() {
+ return concrete.shouldBeInlined();
+ }
+ }
+
+ /**
+ * Polymorphic inlining of m methods with n type checks (n ≥ m) in case that the profiling
+ * information suggests a reasonable amount of different receiver types and different methods.
+ * If an unknown type is encountered a deoptimization is triggered.
+ */
+ private static class MultiTypeGuardInlineInfo extends AbstractInlineInfo {
+
+ private final List concretes;
+ private final double[] methodProbabilities;
+ private final double maximumMethodProbability;
+ private final ArrayList typesToConcretes;
+ private final ArrayList ptypes;
+ private final ArrayList concretesProbabilities;
+ private final double notRecordedTypeProbability;
+ private final Inlineable[] inlineableElements;
+
+ public MultiTypeGuardInlineInfo(Invoke invoke, ArrayList concretes, ArrayList concretesProbabilities, ArrayList ptypes,
+ ArrayList typesToConcretes, double notRecordedTypeProbability) {
+ super(invoke);
+ assert concretes.size() > 0 : "must have at least one method";
+ assert ptypes.size() == typesToConcretes.size() : "array lengths must match";
+
+ this.concretesProbabilities = concretesProbabilities;
+ this.concretes = concretes;
+ this.ptypes = ptypes;
+ this.typesToConcretes = typesToConcretes;
+ this.notRecordedTypeProbability = notRecordedTypeProbability;
+ this.inlineableElements = new Inlineable[concretes.size()];
+ this.methodProbabilities = computeMethodProbabilities();
+ this.maximumMethodProbability = maximumMethodProbability();
+ assert maximumMethodProbability > 0;
+ }
+
+ private double[] computeMethodProbabilities() {
+ double[] result = new double[concretes.size()];
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ int concrete = typesToConcretes.get(i);
+ double probability = ptypes.get(i).getProbability();
+ result[concrete] += probability;
+ }
+ return result;
+ }
+
+ private double maximumMethodProbability() {
+ double max = 0;
+ for (int i = 0; i < methodProbabilities.length; i++) {
+ max = Math.max(max, methodProbabilities[i]);
+ }
+ return max;
+ }
+
+ @Override
+ public int numberOfMethods() {
+ return concretes.size();
+ }
+
+ @Override
+ public ResolvedJavaMethod methodAt(int index) {
+ assert index >= 0 && index < concretes.size();
+ return concretes.get(index);
+ }
+
+ @Override
+ public Inlineable inlineableElementAt(int index) {
+ assert index >= 0 && index < concretes.size();
+ return inlineableElements[index];
+ }
+
+ @Override
+ public double probabilityAt(int index) {
+ return methodProbabilities[index];
+ }
+
+ @Override
+ public double relevanceAt(int index) {
+ return probabilityAt(index) / maximumMethodProbability;
+ }
+
+ @Override
+ public void setInlinableElement(int index, Inlineable inlineableElement) {
+ assert index >= 0 && index < concretes.size();
+ inlineableElements[index] = inlineableElement;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ if (hasSingleMethod()) {
+ inlineSingleMethod(graph(), providers.getMetaAccess(), assumptions);
+ } else {
+ inlineMultipleMethods(graph(), providers, assumptions);
+ }
+ }
+
+ public boolean shouldInline() {
+ for (ResolvedJavaMethod method : concretes) {
+ if (method.shouldBeInlined()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasSingleMethod() {
+ return concretes.size() == 1 && !shouldFallbackToInvoke();
+ }
+
+ private boolean shouldFallbackToInvoke() {
+ return notRecordedTypeProbability > 0;
+ }
+
+ private void inlineMultipleMethods(StructuredGraph graph, Providers providers, Assumptions assumptions) {
+ int numberOfMethods = concretes.size();
+ FixedNode continuation = invoke.next();
+
+ ValueNode originalReceiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+ // setup merge and phi nodes for results and exceptions
+ MergeNode returnMerge = graph.add(new MergeNode());
+ returnMerge.setStateAfter(invoke.stateAfter());
+
+ PhiNode returnValuePhi = null;
+ if (invoke.asNode().getKind() != Kind.Void) {
+ returnValuePhi = graph.addWithoutUnique(new ValuePhiNode(invoke.asNode().stamp().unrestricted(), returnMerge));
+ }
+
+ MergeNode exceptionMerge = null;
+ PhiNode exceptionObjectPhi = null;
+ if (invoke instanceof InvokeWithExceptionNode) {
+ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+
+ exceptionMerge = graph.add(new MergeNode());
+
+ FixedNode exceptionSux = exceptionEdge.next();
+ graph.addBeforeFixed(exceptionSux, exceptionMerge);
+ exceptionObjectPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(Kind.Object), exceptionMerge));
+ exceptionMerge.setStateAfter(exceptionEdge.stateAfter().duplicateModified(invoke.stateAfter().bci, true, Kind.Object, exceptionObjectPhi));
+ }
+
+ // create one separate block for each invoked method
+ BeginNode[] successors = new BeginNode[numberOfMethods + 1];
+ for (int i = 0; i < numberOfMethods; i++) {
+ successors[i] = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, true);
+ }
+
+ // create the successor for an unknown type
+ FixedNode unknownTypeSux;
+ if (shouldFallbackToInvoke()) {
+ unknownTypeSux = createInvocationBlock(graph, invoke, returnMerge, returnValuePhi, exceptionMerge, exceptionObjectPhi, false);
+ } else {
+ unknownTypeSux = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated));
+ }
+ successors[successors.length - 1] = BeginNode.begin(unknownTypeSux);
+
+ // replace the invoke exception edge
+ if (invoke instanceof InvokeWithExceptionNode) {
+ InvokeWithExceptionNode invokeWithExceptionNode = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithExceptionNode.exceptionEdge();
+ exceptionEdge.replaceAtUsages(exceptionObjectPhi);
+ exceptionEdge.setNext(null);
+ GraphUtil.killCFG(invokeWithExceptionNode.exceptionEdge());
+ }
+
+ assert invoke.asNode().isAlive();
+
+ // replace the invoke with a switch on the type of the actual receiver
+ boolean methodDispatch = createDispatchOnTypeBeforeInvoke(graph, successors, false, providers.getMetaAccess());
+
+ assert invoke.next() == continuation;
+ invoke.setNext(null);
+ returnMerge.setNext(continuation);
+ invoke.asNode().replaceAtUsages(returnValuePhi);
+ invoke.asNode().replaceAndDelete(null);
+
+ ArrayList replacementNodes = new ArrayList<>();
+
+ // do the actual inlining for every invoke
+ for (int i = 0; i < numberOfMethods; i++) {
+ BeginNode node = successors[i];
+ Invoke invokeForInlining = (Invoke) node.next();
+
+ ResolvedJavaType commonType;
+ if (methodDispatch) {
+ commonType = concretes.get(i).getDeclaringClass();
+ } else {
+ commonType = getLeastCommonType(i);
+ }
+
+ ValueNode receiver = ((MethodCallTargetNode) invokeForInlining.callTarget()).receiver();
+ boolean exact = (getTypeCount(i) == 1 && !methodDispatch);
+ GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, node, commonType, receiver, exact);
+ invokeForInlining.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+
+ inline(invokeForInlining, methodAt(i), inlineableElementAt(i), assumptions, false);
+
+ replacementNodes.add(anchoredReceiver);
+ }
+ if (shouldFallbackToInvoke()) {
+ replacementNodes.add(null);
+ }
+
+ if (OptTailDuplication.getValue()) {
+ /*
+ * We might want to perform tail duplication at the merge after a type switch, if
+ * there are invokes that would benefit from the improvement in type information.
+ */
+ FixedNode current = returnMerge;
+ int opportunities = 0;
+ do {
+ if (current instanceof InvokeNode && ((InvokeNode) current).callTarget() instanceof MethodCallTargetNode &&
+ ((MethodCallTargetNode) ((InvokeNode) current).callTarget()).receiver() == originalReceiver) {
+ opportunities++;
+ } else if (current.inputs().contains(originalReceiver)) {
+ opportunities++;
+ }
+ current = ((FixedWithNextNode) current).next();
+ } while (current instanceof FixedWithNextNode);
+
+ if (opportunities > 0) {
+ metricInliningTailDuplication.increment();
+ Debug.log("MultiTypeGuardInlineInfo starting tail duplication (%d opportunities)", opportunities);
+ PhaseContext phaseContext = new PhaseContext(providers, assumptions);
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase(!ImmutableCode.getValue());
+ TailDuplicationPhase.tailDuplicate(returnMerge, TailDuplicationPhase.TRUE_DECISION, replacementNodes, phaseContext, canonicalizer);
+ }
+ }
+ }
+
+ private int getTypeCount(int concreteMethodIndex) {
+ int count = 0;
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ if (typesToConcretes.get(i) == concreteMethodIndex) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ private ResolvedJavaType getLeastCommonType(int concreteMethodIndex) {
+ ResolvedJavaType commonType = null;
+ for (int i = 0; i < typesToConcretes.size(); i++) {
+ if (typesToConcretes.get(i) == concreteMethodIndex) {
+ if (commonType == null) {
+ commonType = ptypes.get(i).getType();
+ } else {
+ commonType = commonType.findLeastCommonAncestor(ptypes.get(i).getType());
+ }
+ }
+ }
+ assert commonType != null;
+ return commonType;
+ }
+
+ private ResolvedJavaType getLeastCommonType() {
+ ResolvedJavaType result = getLeastCommonType(0);
+ for (int i = 1; i < concretes.size(); i++) {
+ result = result.findLeastCommonAncestor(getLeastCommonType(i));
+ }
+ return result;
+ }
+
+ private void inlineSingleMethod(StructuredGraph graph, MetaAccessProvider metaAccess, Assumptions assumptions) {
+ assert concretes.size() == 1 && inlineableElements.length == 1 && ptypes.size() > 1 && !shouldFallbackToInvoke() && notRecordedTypeProbability == 0;
+
+ BeginNode calleeEntryNode = graph.add(new BeginNode());
+
+ BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+ BeginNode[] successors = new BeginNode[]{calleeEntryNode, unknownTypeSux};
+ createDispatchOnTypeBeforeInvoke(graph, successors, false, metaAccess);
+
+ calleeEntryNode.setNext(invoke.asNode());
+
+ inline(invoke, methodAt(0), inlineableElementAt(0), assumptions, false);
+ }
+
+ private boolean createDispatchOnTypeBeforeInvoke(StructuredGraph graph, BeginNode[] successors, boolean invokeIsOnlySuccessor, MetaAccessProvider metaAccess) {
+ assert ptypes.size() >= 1;
+ ValueNode nonNullReceiver = nonNullReceiver(invoke);
+ Kind hubKind = ((MethodCallTargetNode) invoke.callTarget()).targetMethod().getDeclaringClass().getEncoding(Representation.ObjectHub).getKind();
+ LoadHubNode hub = graph.unique(new LoadHubNode(nonNullReceiver, hubKind));
+
+ if (!invokeIsOnlySuccessor && chooseMethodDispatch()) {
+ assert successors.length == concretes.size() + 1;
+ assert concretes.size() > 0;
+ Debug.log("Method check cascade with %d methods", concretes.size());
+
+ ValueNode[] constantMethods = new ValueNode[concretes.size()];
+ double[] probability = new double[concretes.size()];
+ for (int i = 0; i < concretes.size(); ++i) {
+ ResolvedJavaMethod firstMethod = concretes.get(i);
+ Constant firstMethodConstant = firstMethod.getEncoding();
+
+ ValueNode firstMethodConstantNode = ConstantNode.forConstant(firstMethodConstant, metaAccess, graph);
+ constantMethods[i] = firstMethodConstantNode;
+ double concretesProbability = concretesProbabilities.get(i);
+ assert concretesProbability >= 0.0;
+ probability[i] = concretesProbability;
+ if (i > 0) {
+ double prevProbability = probability[i - 1];
+ if (prevProbability == 1.0) {
+ probability[i] = 1.0;
+ } else {
+ probability[i] = Math.min(1.0, Math.max(0.0, probability[i] / (1.0 - prevProbability)));
+ }
+ }
+ }
+
+ FixedNode lastSucc = successors[concretes.size()];
+ for (int i = concretes.size() - 1; i >= 0; --i) {
+ LoadMethodNode method = graph.add(new LoadMethodNode(concretes.get(i), hub, constantMethods[i].getKind()));
+ CompareNode methodCheck = CompareNode.createCompareNode(graph, Condition.EQ, method, constantMethods[i]);
+ IfNode ifNode = graph.add(new IfNode(methodCheck, successors[i], lastSucc, probability[i]));
+ method.setNext(ifNode);
+ lastSucc = method;
+ }
+
+ FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+ pred.setNext(lastSucc);
+ return true;
+ } else {
+ Debug.log("Type switch with %d types", concretes.size());
+ }
+
+ ResolvedJavaType[] keys = new ResolvedJavaType[ptypes.size()];
+ double[] keyProbabilities = new double[ptypes.size() + 1];
+ int[] keySuccessors = new int[ptypes.size() + 1];
+ for (int i = 0; i < ptypes.size(); i++) {
+ keys[i] = ptypes.get(i).getType();
+ keyProbabilities[i] = ptypes.get(i).getProbability();
+ keySuccessors[i] = invokeIsOnlySuccessor ? 0 : typesToConcretes.get(i);
+ assert keySuccessors[i] < successors.length - 1 : "last successor is the unknownTypeSux";
+ }
+ keyProbabilities[keyProbabilities.length - 1] = notRecordedTypeProbability;
+ keySuccessors[keySuccessors.length - 1] = successors.length - 1;
+
+ TypeSwitchNode typeSwitch = graph.add(new TypeSwitchNode(hub, successors, keys, keyProbabilities, keySuccessors));
+ FixedWithNextNode pred = (FixedWithNextNode) invoke.asNode().predecessor();
+ pred.setNext(typeSwitch);
+ return false;
+ }
+
+ private boolean chooseMethodDispatch() {
+ for (ResolvedJavaMethod concrete : concretes) {
+ if (!concrete.isInVirtualMethodTable()) {
+ return false;
+ }
+ }
+
+ if (concretes.size() == 1 && this.notRecordedTypeProbability > 0) {
+ // Always chose method dispatch if there is a single concrete method and the call
+ // site is megamorphic.
+ return true;
+ }
+
+ if (concretes.size() == ptypes.size()) {
+ // Always prefer types over methods if the number of types is smaller than the
+ // number of methods.
+ return false;
+ }
+
+ return chooseMethodDispatchCostBased();
+ }
+
+ private boolean chooseMethodDispatchCostBased() {
+ double remainder = 1.0 - this.notRecordedTypeProbability;
+ double costEstimateMethodDispatch = remainder;
+ for (int i = 0; i < concretes.size(); ++i) {
+ if (i != 0) {
+ costEstimateMethodDispatch += remainder;
+ }
+ remainder -= concretesProbabilities.get(i);
+ }
+
+ double costEstimateTypeDispatch = 0.0;
+ remainder = 1.0;
+ for (int i = 0; i < ptypes.size(); ++i) {
+ if (i != 0) {
+ costEstimateTypeDispatch += remainder;
+ }
+ remainder -= ptypes.get(i).getProbability();
+ }
+ costEstimateTypeDispatch += notRecordedTypeProbability;
+ return costEstimateMethodDispatch < costEstimateTypeDispatch;
+ }
+
+ private static BeginNode createInvocationBlock(StructuredGraph graph, Invoke invoke, MergeNode returnMerge, PhiNode returnValuePhi, MergeNode exceptionMerge, PhiNode exceptionObjectPhi,
+ boolean useForInlining) {
+ Invoke duplicatedInvoke = duplicateInvokeForInlining(graph, invoke, exceptionMerge, exceptionObjectPhi, useForInlining);
+ BeginNode calleeEntryNode = graph.add(new BeginNode());
+ calleeEntryNode.setNext(duplicatedInvoke.asNode());
+
+ AbstractEndNode endNode = graph.add(new EndNode());
+ duplicatedInvoke.setNext(endNode);
+ returnMerge.addForwardEnd(endNode);
+
+ if (returnValuePhi != null) {
+ returnValuePhi.addInput(duplicatedInvoke.asNode());
+ }
+ return calleeEntryNode;
+ }
+
+ private static Invoke duplicateInvokeForInlining(StructuredGraph graph, Invoke invoke, MergeNode exceptionMerge, PhiNode exceptionObjectPhi, boolean useForInlining) {
+ Invoke result = (Invoke) invoke.asNode().copyWithInputs();
+ Node callTarget = result.callTarget().copyWithInputs();
+ result.asNode().replaceFirstInput(result.callTarget(), callTarget);
+ result.setUseForInlining(useForInlining);
+
+ Kind kind = invoke.asNode().getKind();
+ if (kind != Kind.Void) {
+ FrameState stateAfter = invoke.stateAfter();
+ stateAfter = stateAfter.duplicate(stateAfter.bci);
+ stateAfter.replaceFirstInput(invoke.asNode(), result.asNode());
+ result.setStateAfter(stateAfter);
+ }
+
+ if (invoke instanceof InvokeWithExceptionNode) {
+ assert exceptionMerge != null && exceptionObjectPhi != null;
+
+ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+ ExceptionObjectNode exceptionEdge = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+ FrameState stateAfterException = exceptionEdge.stateAfter();
+
+ ExceptionObjectNode newExceptionEdge = (ExceptionObjectNode) exceptionEdge.copyWithInputs();
+ // set new state (pop old exception object, push new one)
+ newExceptionEdge.setStateAfter(stateAfterException.duplicateModified(stateAfterException.bci, stateAfterException.rethrowException(), Kind.Object, newExceptionEdge));
+
+ AbstractEndNode endNode = graph.add(new EndNode());
+ newExceptionEdge.setNext(endNode);
+ exceptionMerge.addForwardEnd(endNode);
+ exceptionObjectPhi.addInput(newExceptionEdge);
+
+ ((InvokeWithExceptionNode) result).setExceptionEdge(newExceptionEdge);
+ }
+ return result;
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ if (hasSingleMethod()) {
+ devirtualizeWithTypeSwitch(graph(), InvokeKind.Special, concretes.get(0), metaAccess);
+ } else {
+ tryToDevirtualizeMultipleMethods(graph(), metaAccess);
+ }
+ }
+
+ private void tryToDevirtualizeMultipleMethods(StructuredGraph graph, MetaAccessProvider metaAccess) {
+ MethodCallTargetNode methodCallTarget = (MethodCallTargetNode) invoke.callTarget();
+ if (methodCallTarget.invokeKind() == InvokeKind.Interface) {
+ ResolvedJavaMethod targetMethod = methodCallTarget.targetMethod();
+ ResolvedJavaType leastCommonType = getLeastCommonType();
+ // check if we have a common base type that implements the interface -> in that case
+ // we have a vtable entry for the interface method and can use a less expensive
+ // virtual call
+ if (!leastCommonType.isInterface() && targetMethod.getDeclaringClass().isAssignableFrom(leastCommonType)) {
+ ResolvedJavaMethod baseClassTargetMethod = leastCommonType.resolveMethod(targetMethod);
+ if (baseClassTargetMethod != null) {
+ devirtualizeWithTypeSwitch(graph, InvokeKind.Virtual, leastCommonType.resolveMethod(targetMethod), metaAccess);
+ }
+ }
+ }
+ }
+
+ private void devirtualizeWithTypeSwitch(StructuredGraph graph, InvokeKind kind, ResolvedJavaMethod target, MetaAccessProvider metaAccess) {
+ BeginNode invocationEntry = graph.add(new BeginNode());
+ BeginNode unknownTypeSux = createUnknownTypeSuccessor(graph);
+ BeginNode[] successors = new BeginNode[]{invocationEntry, unknownTypeSux};
+ createDispatchOnTypeBeforeInvoke(graph, successors, true, metaAccess);
+
+ invocationEntry.setNext(invoke.asNode());
+ ValueNode receiver = ((MethodCallTargetNode) invoke.callTarget()).receiver();
+ GuardedValueNode anchoredReceiver = createAnchoredReceiver(graph, invocationEntry, target.getDeclaringClass(), receiver, false);
+ invoke.callTarget().replaceFirstInput(receiver, anchoredReceiver);
+ replaceInvokeCallTarget(invoke, graph, kind, target);
+ }
+
+ private static BeginNode createUnknownTypeSuccessor(StructuredGraph graph) {
+ return BeginNode.begin(graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TypeCheckedInliningViolated)));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(shouldFallbackToInvoke() ? "megamorphic" : "polymorphic");
+ builder.append(", ");
+ builder.append(concretes.size());
+ builder.append(" methods [ ");
+ for (int i = 0; i < concretes.size(); i++) {
+ builder.append(MetaUtil.format(" %H.%n(%p):%r", concretes.get(i)));
+ }
+ builder.append(" ], ");
+ builder.append(ptypes.size());
+ builder.append(" type checks [ ");
+ for (int i = 0; i < ptypes.size(); i++) {
+ builder.append(" ");
+ builder.append(ptypes.get(i).getType().getName());
+ builder.append(ptypes.get(i).getProbability());
+ }
+ builder.append(" ]");
+ return builder.toString();
+ }
+ }
+
+ /**
+ * Represents an inlining opportunity where the current class hierarchy leads to a monomorphic
+ * target method, but for which an assumption has to be registered because of non-final classes.
+ */
+ private static class AssumptionInlineInfo extends ExactInlineInfo {
+
+ private final Assumption takenAssumption;
+
+ public AssumptionInlineInfo(Invoke invoke, ResolvedJavaMethod concrete, Assumption takenAssumption) {
+ super(invoke, concrete);
+ this.takenAssumption = takenAssumption;
+ }
+
+ @Override
+ public void inline(Providers providers, Assumptions assumptions) {
+ assumptions.record(takenAssumption);
+ super.inline(providers, assumptions);
+ }
+
+ @Override
+ public void tryToDevirtualizeInvoke(MetaAccessProvider metaAccess, Assumptions assumptions) {
+ assumptions.record(takenAssumption);
+ replaceInvokeCallTarget(invoke, graph(), InvokeKind.Special, concrete);
+ }
+
+ @Override
+ public String toString() {
+ return "assumption " + MetaUtil.format("%H.%n(%p):%r", concrete);
+ }
+ }
+
+ /**
+ * Determines if inlining is possible at the given invoke node.
+ *
+ * @param invoke the invoke that should be inlined
+ * @return an instance of InlineInfo, or null if no inlining is possible at the given invoke
+ */
+ public static InlineInfo getInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, Assumptions assumptions, OptimisticOptimizations optimisticOpts) {
+ if (!checkInvokeConditions(invoke)) {
+ return null;
+ }
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ ResolvedJavaMethod targetMethod = callTarget.targetMethod();
+
+ if (callTarget.invokeKind() == InvokeKind.Special || targetMethod.canBeStaticallyBound()) {
+ return getExactInlineInfo(data, invoke, replacements, optimisticOpts, targetMethod);
+ }
+
+ assert callTarget.invokeKind() == InvokeKind.Virtual || callTarget.invokeKind() == InvokeKind.Interface;
+
+ ResolvedJavaType holder = targetMethod.getDeclaringClass();
+ if (!(callTarget.receiver().stamp() instanceof ObjectStamp)) {
+ return null;
+ }
+ ObjectStamp receiverStamp = (ObjectStamp) callTarget.receiver().stamp();
+ if (receiverStamp.alwaysNull()) {
+ // Don't inline if receiver is known to be null
+ return null;
+ }
+ if (receiverStamp.type() != null) {
+ // the invoke target might be more specific than the holder (happens after inlining:
+ // parameters lose their declared type...)
+ ResolvedJavaType receiverType = receiverStamp.type();
+ if (receiverType != null && holder.isAssignableFrom(receiverType)) {
+ holder = receiverType;
+ if (receiverStamp.isExactType()) {
+ assert targetMethod.getDeclaringClass().isAssignableFrom(holder) : holder + " subtype of " + targetMethod.getDeclaringClass() + " for " + targetMethod;
+ ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
+ if (resolvedMethod != null) {
+ return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
+ }
+ }
+ }
+ }
+
+ if (holder.isArray()) {
+ // arrays can be treated as Objects
+ ResolvedJavaMethod resolvedMethod = holder.resolveMethod(targetMethod);
+ if (resolvedMethod != null) {
+ return getExactInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod);
+ }
+ }
+
+ if (assumptions.useOptimisticAssumptions()) {
+ ResolvedJavaType uniqueSubtype = holder.findUniqueConcreteSubtype();
+ if (uniqueSubtype != null) {
+ ResolvedJavaMethod resolvedMethod = uniqueSubtype.resolveMethod(targetMethod);
+ if (resolvedMethod != null) {
+ return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, resolvedMethod, new Assumptions.ConcreteSubtype(holder, uniqueSubtype));
+ }
+ }
+
+ ResolvedJavaMethod concrete = holder.findUniqueConcreteMethod(targetMethod);
+ if (concrete != null) {
+ return getAssumptionInlineInfo(data, invoke, replacements, optimisticOpts, concrete, new Assumptions.ConcreteMethod(targetMethod, holder, concrete));
+ }
+ }
+
+ // type check based inlining
+ return getTypeCheckedInlineInfo(data, invoke, maxNumberOfMethods, replacements, targetMethod, optimisticOpts);
+ }
+
+ private static InlineInfo getAssumptionInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod concrete,
+ Assumption takenAssumption) {
+ assert !concrete.isAbstract();
+ if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
+ return null;
+ }
+ return new AssumptionInlineInfo(invoke, concrete, takenAssumption);
+ }
+
+ private static InlineInfo getExactInlineInfo(InliningData data, Invoke invoke, Replacements replacements, OptimisticOptimizations optimisticOpts, ResolvedJavaMethod targetMethod) {
+ assert !targetMethod.isAbstract();
+ if (!checkTargetConditions(data, replacements, invoke, targetMethod, optimisticOpts)) {
+ return null;
+ }
+ return new ExactInlineInfo(invoke, targetMethod);
+ }
+
+ private static InlineInfo getTypeCheckedInlineInfo(InliningData data, Invoke invoke, int maxNumberOfMethods, Replacements replacements, ResolvedJavaMethod targetMethod,
+ OptimisticOptimizations optimisticOpts) {
+ JavaTypeProfile typeProfile;
+ ValueNode receiver = invoke.callTarget().arguments().get(0);
+ if (receiver instanceof TypeProfileProxyNode) {
+ TypeProfileProxyNode typeProfileProxyNode = (TypeProfileProxyNode) receiver;
+ typeProfile = typeProfileProxyNode.getProfile();
+ } else {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no type profile exists");
+ }
+
+ ProfiledType[] ptypes = typeProfile.getTypes();
+ if (ptypes == null || ptypes.length <= 0) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types in profile");
+ }
+
+ double notRecordedTypeProbability = typeProfile.getNotRecordedProbability();
+ if (ptypes.length == 1 && notRecordedTypeProbability == 0) {
+ if (!optimisticOpts.inlineMonomorphicCalls()) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining monomorphic calls is disabled");
+ }
+
+ ResolvedJavaType type = ptypes[0].getType();
+ assert type.isArray() || !type.isAbstract();
+ ResolvedJavaMethod concrete = type.resolveMethod(targetMethod);
+ if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
+ return null;
+ }
+ return new TypeGuardInlineInfo(invoke, concrete, type);
+ } else {
+ invoke.setPolymorphic(true);
+
+ if (!optimisticOpts.inlinePolymorphicCalls() && notRecordedTypeProbability == 0) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining polymorphic calls is disabled (%d types)", ptypes.length);
+ }
+ if (!optimisticOpts.inlineMegamorphicCalls() && notRecordedTypeProbability > 0) {
+ // due to filtering impossible types, notRecordedTypeProbability can be > 0 although
+ // the number of types is lower than what can be recorded in a type profile
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "inlining megamorphic calls is disabled (%d types, %f %% not recorded types)", ptypes.length,
+ notRecordedTypeProbability * 100);
+ }
+
+ // Find unique methods and their probabilities.
+ ArrayList concreteMethods = new ArrayList<>();
+ ArrayList concreteMethodsProbabilities = new ArrayList<>();
+ for (int i = 0; i < ptypes.length; i++) {
+ ResolvedJavaMethod concrete = ptypes[i].getType().resolveMethod(targetMethod);
+ if (concrete == null) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "could not resolve method");
+ }
+ int index = concreteMethods.indexOf(concrete);
+ double curProbability = ptypes[i].getProbability();
+ if (index < 0) {
+ index = concreteMethods.size();
+ concreteMethods.add(concrete);
+ concreteMethodsProbabilities.add(curProbability);
+ } else {
+ concreteMethodsProbabilities.set(index, concreteMethodsProbabilities.get(index) + curProbability);
+ }
+ }
+
+ if (concreteMethods.size() > maxNumberOfMethods) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "polymorphic call with more than %d target methods", maxNumberOfMethods);
+ }
+
+ // Clear methods that fall below the threshold.
+ if (notRecordedTypeProbability > 0) {
+ ArrayList newConcreteMethods = new ArrayList<>();
+ ArrayList newConcreteMethodsProbabilities = new ArrayList<>();
+ for (int i = 0; i < concreteMethods.size(); ++i) {
+ if (concreteMethodsProbabilities.get(i) >= MegamorphicInliningMinMethodProbability.getValue()) {
+ newConcreteMethods.add(concreteMethods.get(i));
+ newConcreteMethodsProbabilities.add(concreteMethodsProbabilities.get(i));
+ }
+ }
+
+ if (newConcreteMethods.size() == 0) {
+ // No method left that is worth inlining.
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no methods remaining after filtering less frequent methods (%d methods previously)",
+ concreteMethods.size());
+ }
+
+ concreteMethods = newConcreteMethods;
+ concreteMethodsProbabilities = newConcreteMethodsProbabilities;
+ }
+
+ // Clean out types whose methods are no longer available.
+ ArrayList usedTypes = new ArrayList<>();
+ ArrayList typesToConcretes = new ArrayList<>();
+ for (ProfiledType type : ptypes) {
+ ResolvedJavaMethod concrete = type.getType().resolveMethod(targetMethod);
+ int index = concreteMethods.indexOf(concrete);
+ if (index == -1) {
+ notRecordedTypeProbability += type.getProbability();
+ } else {
+ assert type.getType().isArray() || !type.getType().isAbstract() : type + " " + concrete;
+ usedTypes.add(type);
+ typesToConcretes.add(index);
+ }
+ }
+
+ if (usedTypes.size() == 0) {
+ // No type left that is worth checking for.
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "no types remaining after filtering less frequent types (%d types previously)", ptypes.length);
+ }
+
+ for (ResolvedJavaMethod concrete : concreteMethods) {
+ if (!checkTargetConditions(data, replacements, invoke, concrete, optimisticOpts)) {
+ return logNotInlinedMethodAndReturnNull(invoke, data.inliningDepth(), targetMethod, "it is a polymorphic method call and at least one invoked method cannot be inlined");
+ }
+ }
+ return new MultiTypeGuardInlineInfo(invoke, concreteMethods, concreteMethodsProbabilities, usedTypes, typesToConcretes, notRecordedTypeProbability);
+ }
+ }
+
+ private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ResolvedJavaType commonType, ValueNode receiver, boolean exact) {
+ return createAnchoredReceiver(graph, anchor, receiver, exact ? StampFactory.exactNonNull(commonType) : StampFactory.declaredNonNull(commonType));
+ }
+
+ private static GuardedValueNode createAnchoredReceiver(StructuredGraph graph, GuardingNode anchor, ValueNode receiver, Stamp stamp) {
+ // to avoid that floating reads on receiver fields float above the type check
+ return graph.unique(new GuardedValueNode(receiver, anchor, stamp));
+ }
+
+ // TODO (chaeubl): cleanup this method
+ private static boolean checkInvokeConditions(Invoke invoke) {
+ if (invoke.predecessor() == null || !invoke.asNode().isAlive()) {
+ return logNotInlinedMethod(invoke, "the invoke is dead code");
+ } else if (!(invoke.callTarget() instanceof MethodCallTargetNode)) {
+ return logNotInlinedMethod(invoke, "the invoke has already been lowered, or has been created as a low-level node");
+ } else if (((MethodCallTargetNode) invoke.callTarget()).targetMethod() == null) {
+ return logNotInlinedMethod(invoke, "target method is null");
+ } else if (invoke.stateAfter() == null) {
+ // TODO (chaeubl): why should an invoke not have a state after?
+ return logNotInlinedMethod(invoke, "the invoke has no after state");
+ } else if (!invoke.useForInlining()) {
+ return logNotInlinedMethod(invoke, "the invoke is marked to be not used for inlining");
+ } else if (((MethodCallTargetNode) invoke.callTarget()).receiver() != null && ((MethodCallTargetNode) invoke.callTarget()).receiver().isConstant() &&
+ ((MethodCallTargetNode) invoke.callTarget()).receiver().asConstant().isNull()) {
+ return logNotInlinedMethod(invoke, "receiver is null");
+ } else {
+ return true;
+ }
+ }
+
+ private static boolean checkTargetConditions(InliningData data, Replacements replacements, Invoke invoke, ResolvedJavaMethod method, OptimisticOptimizations optimisticOpts) {
+ if (method == null) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method is not resolved");
+ } else if (method.isNative() && (!Intrinsify.getValue() || !InliningUtil.canIntrinsify(replacements, method))) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is a non-intrinsic native method");
+ } else if (method.isAbstract()) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is an abstract method");
+ } else if (!method.getDeclaringClass().isInitialized()) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the method's class is not initialized");
+ } else if (!method.canBeInlined()) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it is marked non-inlinable");
+ } else if (data.countRecursiveInlining(method) > MaximumRecursiveInlining.getValue()) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "it exceeds the maximum recursive inlining depth");
+ } else if (new OptimisticOptimizations(method.getProfilingInfo()).lessOptimisticThan(optimisticOpts)) {
+ return logNotInlinedMethodAndReturnFalse(invoke, data.inliningDepth(), method, "the callee uses less optimistic optimizations than caller");
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Performs an actual inlining, thereby replacing the given invoke with the given inlineGraph.
+ *
+ * @param invoke the invoke that will be replaced
+ * @param inlineGraph the graph that the invoke will be replaced with
+ * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings,
+ * false if no such check is required
+ */
+ public static Map inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+ final NodeInputList parameters = invoke.callTarget().arguments();
+ FixedNode invokeNode = invoke.asNode();
+ StructuredGraph graph = invokeNode.graph();
+ assert inlineGraph.getGuardsStage().ordinal() >= graph.getGuardsStage().ordinal();
+ assert !invokeNode.graph().isAfterFloatingReadPhase() : "inline isn't handled correctly after floating reads phase";
+
+ FrameState stateAfter = invoke.stateAfter();
+ assert stateAfter == null || stateAfter.isAlive();
+ if (receiverNullCheck && !((MethodCallTargetNode) invoke.callTarget()).isStatic()) {
+ nonNullReceiver(invoke);
+ }
+
+ ArrayList nodes = new ArrayList<>(inlineGraph.getNodes().count());
+ ArrayList returnNodes = new ArrayList<>(4);
+ UnwindNode unwindNode = null;
+ final StartNode entryPointNode = inlineGraph.start();
+ FixedNode firstCFGNode = entryPointNode.next();
+ if (firstCFGNode == null) {
+ throw new IllegalStateException("Inlined graph is in invalid state");
+ }
+ for (Node node : inlineGraph.getNodes()) {
+ if (node == entryPointNode || node == entryPointNode.stateAfter() || node instanceof ParameterNode) {
+ // Do nothing.
+ } else {
+ nodes.add(node);
+ if (node instanceof ReturnNode) {
+ returnNodes.add((ReturnNode) node);
+ } else if (node instanceof UnwindNode) {
+ assert unwindNode == null;
+ unwindNode = (UnwindNode) node;
+ }
+ }
+ }
+
+ final BeginNode prevBegin = BeginNode.prevBegin(invokeNode);
+ DuplicationReplacement localReplacement = new DuplicationReplacement() {
+
+ public Node replacement(Node node) {
+ if (node instanceof ParameterNode) {
+ return parameters.get(((ParameterNode) node).index());
+ } else if (node == entryPointNode) {
+ return prevBegin;
+ }
+ return node;
+ }
+ };
+
+ assert invokeNode.successors().first() != null : invoke;
+ assert invokeNode.predecessor() != null;
+
+ Map duplicates = graph.addDuplicates(nodes, inlineGraph, inlineGraph.getNodeCount(), localReplacement);
+ FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode);
+ invokeNode.replaceAtPredecessor(firstCFGNodeDuplicate);
+
+ FrameState stateAtExceptionEdge = null;
+ if (invoke instanceof InvokeWithExceptionNode) {
+ InvokeWithExceptionNode invokeWithException = ((InvokeWithExceptionNode) invoke);
+ if (unwindNode != null) {
+ assert unwindNode.predecessor() != null;
+ assert invokeWithException.exceptionEdge().successors().count() == 1;
+ ExceptionObjectNode obj = (ExceptionObjectNode) invokeWithException.exceptionEdge();
+ stateAtExceptionEdge = obj.stateAfter();
+ UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+ obj.replaceAtUsages(unwindDuplicate.exception());
+ unwindDuplicate.clearInputs();
+ Node n = obj.next();
+ obj.setNext(null);
+ unwindDuplicate.replaceAndDelete(n);
+ } else {
+ invokeWithException.killExceptionEdge();
+ }
+
+ // get rid of memory kill
+ BeginNode begin = invokeWithException.next();
+ if (begin instanceof KillingBeginNode) {
+ BeginNode newBegin = new BeginNode();
+ graph.addAfterFixed(begin, graph.add(newBegin));
+ begin.replaceAtUsages(newBegin);
+ graph.removeFixed(begin);
+ }
+ } else {
+ if (unwindNode != null) {
+ UnwindNode unwindDuplicate = (UnwindNode) duplicates.get(unwindNode);
+ DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+ unwindDuplicate.replaceAndDelete(deoptimizeNode);
+ }
+ }
+
+ if (stateAfter != null) {
+ processFrameStates(invoke, inlineGraph, duplicates, stateAtExceptionEdge);
+ int callerLockDepth = stateAfter.nestedLockDepth();
+ if (callerLockDepth != 0) {
+ for (MonitorIdNode original : inlineGraph.getNodes(MonitorIdNode.class)) {
+ MonitorIdNode monitor = (MonitorIdNode) duplicates.get(original);
+ monitor.setLockDepth(monitor.getLockDepth() + callerLockDepth);
+ }
+ }
+ } else {
+ assert checkContainsOnlyInvalidOrAfterFrameState(duplicates);
+ }
+ if (!returnNodes.isEmpty()) {
+ FixedNode n = invoke.next();
+ invoke.setNext(null);
+ if (returnNodes.size() == 1) {
+ ReturnNode returnNode = (ReturnNode) duplicates.get(returnNodes.get(0));
+ Node returnValue = returnNode.result();
+ invokeNode.replaceAtUsages(returnValue);
+ returnNode.clearInputs();
+ returnNode.replaceAndDelete(n);
+ } else {
+ ArrayList returnDuplicates = new ArrayList<>(returnNodes.size());
+ for (ReturnNode returnNode : returnNodes) {
+ returnDuplicates.add((ReturnNode) duplicates.get(returnNode));
+ }
+ MergeNode merge = graph.add(new MergeNode());
+ merge.setStateAfter(stateAfter);
+ ValueNode returnValue = mergeReturns(merge, returnDuplicates);
+ invokeNode.replaceAtUsages(returnValue);
+ merge.setNext(n);
+ }
+ }
+
+ invokeNode.replaceAtUsages(null);
+ GraphUtil.killCFG(invokeNode);
+
+ return duplicates;
+ }
+
+ protected static void processFrameStates(Invoke invoke, StructuredGraph inlineGraph, Map duplicates, FrameState stateAtExceptionEdge) {
+ FrameState stateAtReturn = invoke.stateAfter();
+ FrameState outerFrameState = null;
+ Kind invokeReturnKind = invoke.asNode().getKind();
+ for (FrameState original : inlineGraph.getNodes(FrameState.class)) {
+ FrameState frameState = (FrameState) duplicates.get(original);
+ if (frameState != null && frameState.isAlive()) {
+ if (frameState.bci == BytecodeFrame.AFTER_BCI) {
+ /*
+ * pop return kind from invoke's stateAfter and replace with this frameState's
+ * return value (top of stack)
+ */
+ FrameState stateAfterReturn = stateAtReturn;
+ if (invokeReturnKind != Kind.Void && frameState.stackSize() > 0 && stateAfterReturn.stackAt(0) != frameState.stackAt(0)) {
+ stateAfterReturn = stateAtReturn.duplicateModified(invokeReturnKind, frameState.stackAt(0));
+ }
+ frameState.replaceAndDelete(stateAfterReturn);
+ } else if (stateAtExceptionEdge != null && isStateAfterException(frameState)) {
+ /*
+ * pop exception object from invoke's stateAfter and replace with this
+ * frameState's exception object (top of stack)
+ */
+ FrameState stateAfterException = stateAtExceptionEdge;
+ if (frameState.stackSize() > 0 && stateAtExceptionEdge.stackAt(0) != frameState.stackAt(0)) {
+ stateAfterException = stateAtExceptionEdge.duplicateModified(Kind.Object, frameState.stackAt(0));
+ }
+ frameState.replaceAndDelete(stateAfterException);
+ } else if (frameState.bci == BytecodeFrame.UNWIND_BCI || frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI) {
+ handleMissingAfterExceptionFrameState(frameState);
+ } else {
+ // only handle the outermost frame states
+ if (frameState.outerFrameState() == null) {
+ assert frameState.bci != BytecodeFrame.BEFORE_BCI : frameState;
+ assert frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI || frameState.method().equals(inlineGraph.method());
+ assert frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI && frameState.bci != BytecodeFrame.BEFORE_BCI && frameState.bci != BytecodeFrame.AFTER_EXCEPTION_BCI &&
+ frameState.bci != BytecodeFrame.UNWIND_BCI : frameState.bci;
+ if (outerFrameState == null) {
+ outerFrameState = stateAtReturn.duplicateModified(invoke.bci(), stateAtReturn.rethrowException(), invokeReturnKind);
+ outerFrameState.setDuringCall(true);
+ }
+ frameState.setOuterFrameState(outerFrameState);
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean isStateAfterException(FrameState frameState) {
+ return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.method().isSynchronized());
+ }
+
+ protected static void handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState) {
+ Graph graph = nonReplaceableFrameState.graph();
+ NodeWorkList workList = graph.createNodeWorkList();
+ workList.add(nonReplaceableFrameState);
+ for (Node node : workList) {
+ FrameState fs = (FrameState) node;
+ for (Node usage : fs.usages().snapshot()) {
+ if (!usage.isAlive()) {
+ continue;
+ }
+ if (usage instanceof FrameState) {
+ workList.add(usage);
+ } else {
+ StateSplit stateSplit = (StateSplit) usage;
+ FixedNode fixedStateSplit = stateSplit.asNode();
+ if (fixedStateSplit instanceof MergeNode) {
+ MergeNode merge = (MergeNode) fixedStateSplit;
+ while (merge.isAlive()) {
+ AbstractEndNode end = merge.forwardEnds().first();
+ DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+ end.replaceAtPredecessor(deoptimizeNode);
+ GraphUtil.killCFG(end);
+ }
+ } else {
+ FixedNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
+ if (fixedStateSplit instanceof BeginNode) {
+ deoptimizeNode = BeginNode.begin(deoptimizeNode);
+ }
+ fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
+ GraphUtil.killCFG(fixedStateSplit);
+ }
+ }
+ }
+ }
+ }
+
+ public static ValueNode mergeReturns(MergeNode merge, List extends ReturnNode> returnNodes) {
+ PhiNode returnValuePhi = null;
+
+ for (ReturnNode returnNode : returnNodes) {
+ // create and wire up a new EndNode
+ EndNode endNode = merge.graph().add(new EndNode());
+ merge.addForwardEnd(endNode);
+
+ if (returnNode.result() != null) {
+ if (returnValuePhi == null) {
+ returnValuePhi = merge.graph().addWithoutUnique(new ValuePhiNode(returnNode.result().stamp().unrestricted(), merge));
+ }
+ returnValuePhi.addInput(returnNode.result());
+ }
+ returnNode.clearInputs();
+ returnNode.replaceAndDelete(endNode);
+
+ }
+ return returnValuePhi;
+ }
+
+ private static boolean checkContainsOnlyInvalidOrAfterFrameState(Map duplicates) {
+ for (Node node : duplicates.values()) {
+ if (node instanceof FrameState) {
+ FrameState frameState = (FrameState) node;
+ assert frameState.bci == BytecodeFrame.AFTER_BCI || frameState.bci == BytecodeFrame.INVALID_FRAMESTATE_BCI : node.toString(Verbosity.Debugger);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Gets the receiver for an invoke, adding a guard if necessary to ensure it is non-null.
+ */
+ public static ValueNode nonNullReceiver(Invoke invoke) {
+ MethodCallTargetNode callTarget = (MethodCallTargetNode) invoke.callTarget();
+ assert !callTarget.isStatic() : callTarget.targetMethod();
+ StructuredGraph graph = callTarget.graph();
+ ValueNode firstParam = callTarget.arguments().get(0);
+ if (firstParam.getKind() == Kind.Object && !StampTool.isObjectNonNull(firstParam)) {
+ IsNullNode condition = graph.unique(new IsNullNode(firstParam));
+ Stamp stamp = firstParam.stamp().join(objectNonNull());
+ GuardingPiNode nonNullReceiver = graph.add(new GuardingPiNode(firstParam, condition, true, NullCheckException, InvalidateReprofile, stamp));
+ graph.addBeforeFixed(invoke.asNode(), nonNullReceiver);
+ callTarget.replaceFirstInput(firstParam, nonNullReceiver);
+ return nonNullReceiver;
+ }
+ return firstParam;
+ }
+
+ public static boolean canIntrinsify(Replacements replacements, ResolvedJavaMethod target) {
+ return getIntrinsicGraph(replacements, target) != null || getMacroNodeClass(replacements, target) != null;
+ }
+
+ public static StructuredGraph getIntrinsicGraph(Replacements replacements, ResolvedJavaMethod target) {
+ return replacements.getMethodSubstitution(target);
+ }
+
+ public static Class extends FixedWithNextNode> getMacroNodeClass(Replacements replacements, ResolvedJavaMethod target) {
+ return replacements.getMacroSubstitution(target);
+ }
+
+ public static FixedWithNextNode inlineMacroNode(Invoke invoke, ResolvedJavaMethod concrete, Class extends FixedWithNextNode> macroNodeClass) throws GraalInternalError {
+ StructuredGraph graph = invoke.asNode().graph();
+ if (!concrete.equals(((MethodCallTargetNode) invoke.callTarget()).targetMethod())) {
+ assert ((MethodCallTargetNode) invoke.callTarget()).invokeKind() != InvokeKind.Static;
+ InliningUtil.replaceInvokeCallTarget(invoke, graph, InvokeKind.Special, concrete);
+ }
+
+ FixedWithNextNode macroNode = createMacroNodeInstance(macroNodeClass, invoke);
+
+ CallTargetNode callTarget = invoke.callTarget();
+ if (invoke instanceof InvokeNode) {
+ graph.replaceFixedWithFixed((InvokeNode) invoke, graph.add(macroNode));
+ } else {
+ InvokeWithExceptionNode invokeWithException = (InvokeWithExceptionNode) invoke;
+ invokeWithException.killExceptionEdge();
+ graph.replaceSplitWithFixed(invokeWithException, graph.add(macroNode), invokeWithException.next());
+ }
+ GraphUtil.killWithUnusedFloatingInputs(callTarget);
+ return macroNode;
+ }
+
+ private static FixedWithNextNode createMacroNodeInstance(Class extends FixedWithNextNode> macroNodeClass, Invoke invoke) throws GraalInternalError {
+ try {
+ return macroNodeClass.getConstructor(Invoke.class).newInstance(invoke);
+ } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+ throw new GraalGraphInternalError(e).addContext(invoke.asNode()).addContext("macroSubstitution", macroNodeClass);
+ }
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeInliningRelevanceClosure.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 2013, 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 com.oracle.graal.phases.graph;
-
-import java.util.*;
-
-import com.oracle.graal.compiler.common.cfg.*;
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
-
-public class ComputeInliningRelevanceClosure {
-
- private static final double EPSILON = 1d / Integer.MAX_VALUE;
-
- private final StructuredGraph graph;
- private final NodesToDoubles nodeProbabilities;
- private final NodesToDoubles nodeRelevances;
-
- public ComputeInliningRelevanceClosure(StructuredGraph graph, NodesToDoubles nodeProbabilities) {
- this.graph = graph;
- this.nodeProbabilities = nodeProbabilities;
- this.nodeRelevances = new NodesToDoubles(graph.getNodeCount());
- }
-
- public NodesToDoubles apply() {
- new ComputeInliningRelevanceIterator(graph).apply();
- return nodeRelevances;
- }
-
- private class ComputeInliningRelevanceIterator extends ScopedPostOrderNodeIterator {
-
- private final HashMap scopes;
- private double currentProbability;
- private double parentRelevance;
-
- public ComputeInliningRelevanceIterator(StructuredGraph graph) {
- super(graph);
- this.scopes = computeScopesAndProbabilities();
- }
-
- @Override
- protected void initializeScope() {
- Scope scope = scopes.get(currentScopeStart);
- parentRelevance = getParentScopeRelevance(scope);
- currentProbability = scope.probability;
- }
-
- private double getParentScopeRelevance(Scope scope) {
- if (scope.start instanceof LoopBeginNode) {
- assert scope.parent != null;
- double parentProbability = 0;
- for (AbstractEndNode end : ((LoopBeginNode) scope.start).forwardEnds()) {
- parentProbability += nodeProbabilities.get(end);
- }
- return parentProbability / scope.parent.probability;
- } else {
- assert scope.parent == null;
- return 1.0;
- }
- }
-
- @Override
- protected void invoke(Invoke invoke) {
- double probability = nodeProbabilities.get(invoke.asNode());
- assert !Double.isNaN(probability);
-
- double relevance = (probability / currentProbability) * Math.min(1.0, parentRelevance);
- nodeRelevances.put(invoke.asNode(), relevance);
- assert !Double.isNaN(relevance);
- }
-
- private HashMap computeScopesAndProbabilities() {
- HashMap result = new HashMap<>();
-
- for (Scope scope : computeScopes()) {
- double lowestPathProbability = computeLowestPathProbability(scope);
- scope.probability = Math.max(EPSILON, lowestPathProbability);
- result.put(scope.start, scope);
- }
-
- return result;
- }
-
- private Scope[] computeScopes() {
- ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false);
-
- List> loops = cfg.getLoops();
- HashMap, Scope> processedScopes = new HashMap<>();
- Scope[] result = new Scope[loops.size() + 1];
- Scope methodScope = new Scope(graph.start(), null);
- processedScopes.put(null, methodScope);
-
- result[0] = methodScope;
- for (int i = 0; i < loops.size(); i++) {
- result[i + 1] = createScope(loops.get(i), processedScopes);
- }
-
- return result;
- }
-
- private Scope createScope(Loop loop, HashMap, Scope> processedLoops) {
- Scope parent = processedLoops.get(loop.parent);
- if (parent == null) {
- parent = createScope(loop.parent, processedLoops);
- }
- Scope result = new Scope(loop.header.getBeginNode(), parent);
- processedLoops.put(loop, result);
- return result;
- }
- }
-
- private double computeLowestPathProbability(Scope scope) {
- FixedNode scopeStart = scope.start;
- ArrayList pathBeginNodes = new ArrayList<>();
- pathBeginNodes.add(scopeStart);
- double minPathProbability = nodeProbabilities.get(scopeStart);
- boolean isLoopScope = scopeStart instanceof LoopBeginNode;
-
- do {
- Node current = pathBeginNodes.remove(pathBeginNodes.size() - 1);
- do {
- if (isLoopScope && current instanceof LoopExitNode && ((LoopBeginNode) scopeStart).loopExits().contains((LoopExitNode) current)) {
- return minPathProbability;
- } else if (current instanceof LoopBeginNode && current != scopeStart) {
- current = getMaxProbabilityLoopExit((LoopBeginNode) current, pathBeginNodes);
- minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
- } else if (current instanceof ControlSplitNode) {
- current = getMaxProbabilitySux((ControlSplitNode) current, pathBeginNodes);
- minPathProbability = getMinPathProbability((FixedNode) current, minPathProbability);
- } else {
- assert current.successors().count() <= 1;
- current = current.successors().first();
- }
- } while (current != null);
- } while (!pathBeginNodes.isEmpty());
-
- return minPathProbability;
- }
-
- private double getMinPathProbability(FixedNode current, double minPathProbability) {
- if (current != null && nodeProbabilities.get(current) < minPathProbability) {
- return nodeProbabilities.get(current);
- }
- return minPathProbability;
- }
-
- private static Node getMaxProbabilitySux(ControlSplitNode controlSplit, ArrayList pathBeginNodes) {
- Node maxSux = null;
- double maxProbability = 0.0;
- int pathBeginCount = pathBeginNodes.size();
-
- for (Node sux : controlSplit.successors()) {
- double probability = controlSplit.probability((BeginNode) sux);
- if (probability > maxProbability) {
- maxProbability = probability;
- maxSux = sux;
- truncate(pathBeginNodes, pathBeginCount);
- } else if (probability == maxProbability) {
- pathBeginNodes.add((FixedNode) sux);
- }
- }
-
- return maxSux;
- }
-
- private Node getMaxProbabilityLoopExit(LoopBeginNode loopBegin, ArrayList pathBeginNodes) {
- Node maxSux = null;
- double maxProbability = 0.0;
- int pathBeginCount = pathBeginNodes.size();
-
- for (LoopExitNode sux : loopBegin.loopExits()) {
- double probability = nodeProbabilities.get(sux);
- if (probability > maxProbability) {
- maxProbability = probability;
- maxSux = sux;
- truncate(pathBeginNodes, pathBeginCount);
- } else if (probability == maxProbability) {
- pathBeginNodes.add(sux);
- }
- }
-
- return maxSux;
- }
-
- private static void truncate(ArrayList pathBeginNodes, int pathBeginCount) {
- for (int i = pathBeginNodes.size() - pathBeginCount; i > 0; i--) {
- pathBeginNodes.remove(pathBeginNodes.size() - 1);
- }
- }
-
- private static class Scope {
-
- public final FixedNode start;
- public final Scope parent;
- public double probability;
-
- public Scope(FixedNode start, Scope parent) {
- this.start = start;
- this.parent = parent;
- }
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ComputeProbabilityClosure.java Fri May 02 02:45:26 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,295 +0,0 @@
-/*
- * Copyright (c) 2011, 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 com.oracle.graal.phases.graph;
-
-import java.util.*;
-
-import com.oracle.graal.graph.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.util.*;
-import com.oracle.graal.phases.util.*;
-
-/**
- * Computes probabilities for nodes in a graph.
- *
- * The computation of absolute probabilities works in three steps:
- *
- * - {@link PropagateProbability} traverses the graph in post order (merges after their ends, ...)
- * and keeps track of the "probability state". Whenever it encounters a {@link ControlSplitNode} it
- * uses the split's probability information to divide the probability upon the successors. Whenever
- * it encounters an {@link Invoke} it assumes that the exception edge is unlikely and propagates the
- * whole probability to the normal successor. Whenever it encounters a {@link MergeNode} it sums up
- * the probability of all predecessors. It also maintains a set of active loops (whose
- * {@link LoopBeginNode} has been visited) and builds def/use information for step 2.
- *
- * - {@link PropagateLoopFrequency} propagates the loop frequencies and multiplies each
- * {@link FixedNode}'s probability with its loop frequency.
- *
- */
-public class ComputeProbabilityClosure {
-
- private static final double EPSILON = Double.MIN_NORMAL;
-
- private final StructuredGraph graph;
- private final NodesToDoubles nodeProbabilities;
- private final Set loopInfos;
- private final Map> mergeLoops;
-
- public ComputeProbabilityClosure(StructuredGraph graph) {
- this.graph = graph;
- this.nodeProbabilities = new NodesToDoubles(graph.getNodeCount());
- this.loopInfos = new ArraySet<>();
- this.mergeLoops = new IdentityHashMap<>();
- }
-
- public NodesToDoubles apply() {
- // adjustControlSplitProbabilities();
- new PropagateProbability(graph.start()).apply();
- computeLoopFactors();
- new PropagateLoopFrequency(graph.start()).apply();
- // assert verifyProbabilities();
- return nodeProbabilities;
- }
-
- private void computeLoopFactors() {
- for (LoopInfo info : loopInfos) {
- double frequency = info.loopFrequency(nodeProbabilities);
- assert frequency != -1;
- }
- }
-
- public static class LoopInfo {
-
- public final LoopBeginNode loopBegin;
-
- public final NodeMap> requires;
-
- private double loopFrequency = -1.0;
- public boolean ended = false;
-
- public LoopInfo(LoopBeginNode loopBegin) {
- this.loopBegin = loopBegin;
- this.requires = loopBegin.graph().createNodeMap();
- }
-
- public double loopFrequency(NodesToDoubles nodeProbabilities) {
- // loopFrequency is initialized with -1.0
- if (loopFrequency < 0.0 && ended) {
- double backEdgeProb = 0.0;
- for (LoopEndNode le : loopBegin.loopEnds()) {
- double factor = 1;
- Set requireds = requires.get(le);
- for (LoopInfo required : requireds) {
- double t = required.loopFrequency(nodeProbabilities);
- if (t == -1) {
- return -1;
- }
- factor = multiplySaturate(factor, t);
- }
- backEdgeProb += nodeProbabilities.get(le) * factor;
- }
- double entryProb = nodeProbabilities.get(loopBegin);
- double d = entryProb - backEdgeProb;
- if (d <= EPSILON) {
- d = EPSILON;
- }
- loopFrequency = entryProb / d;
- loopBegin.setLoopFrequency(loopFrequency);
- }
- return loopFrequency;
- }
- }
-
- /**
- * Multiplies a and b and saturates the result to 1/{@link Double#MIN_NORMAL}.
- *
- * @param a
- * @param b
- * @return a times b saturated to 1/{@link Double#MIN_NORMAL}
- */
- public static double multiplySaturate(double a, double b) {
- double r = a * b;
- if (r > 1 / Double.MIN_NORMAL) {
- return 1 / Double.MIN_NORMAL;
- }
- return r;
- }
-
- private class Probability extends MergeableState implements Cloneable {
-
- public double probability;
- public Set loops;
- public LoopInfo loopInfo;
-
- public Probability(double probability, Set loops) {
- assert probability >= 0.0;
- this.probability = probability;
- this.loops = new ArraySet<>(4);
- if (loops != null) {
- this.loops.addAll(loops);
- }
- }
-
- @Override
- public Probability clone() {
- return new Probability(probability, loops);
- }
-
- @Override
- public boolean merge(MergeNode merge, List withStates) {
- if (merge.forwardEndCount() > 1) {
- Set intersection = new ArraySet<>(loops);
- for (Probability other : withStates) {
- intersection.retainAll(other.loops);
- }
- for (LoopInfo info : loops) {
- if (!intersection.contains(info)) {
- double loopFrequency = info.loopFrequency(nodeProbabilities);
- if (loopFrequency == -1) {
- return false;
- }
- probability = multiplySaturate(probability, loopFrequency);
- assert probability >= 0;
- }
- }
- for (Probability other : withStates) {
- double prob = other.probability;
- for (LoopInfo info : other.loops) {
- if (!intersection.contains(info)) {
- double loopFrequency = info.loopFrequency(nodeProbabilities);
- if (loopFrequency == -1) {
- return false;
- }
- prob = multiplySaturate(prob, loopFrequency);
- assert prob >= 0;
- }
- }
- probability += prob;
- assert probability >= 0;
- }
- loops = intersection;
- mergeLoops.put(merge, new ArraySet<>(intersection));
- probability = Math.max(0.0, probability);
- }
- return true;
- }
-
- @Override
- public void loopBegin(LoopBeginNode loopBegin) {
- loopInfo = new LoopInfo(loopBegin);
- loopInfos.add(loopInfo);
- loops.add(loopInfo);
- }
-
- @Override
- public void loopEnds(LoopBeginNode loopBegin, List loopEndStates) {
- assert loopInfo != null;
- List loopEnds = loopBegin.orderedLoopEnds();
- int i = 0;
- for (Probability proba : loopEndStates) {
- LoopEndNode loopEnd = loopEnds.get(i++);
- Set requires = loopInfo.requires.get(loopEnd);
- if (requires == null) {
- requires = new HashSet<>();
- loopInfo.requires.set(loopEnd, requires);
- }
- for (LoopInfo innerLoop : proba.loops) {
- if (innerLoop != loopInfo && !this.loops.contains(innerLoop)) {
- requires.add(innerLoop);
- }
- }
- }
- loopInfo.ended = true;
- }
-
- @Override
- public void afterSplit(BeginNode node) {
- assert node.predecessor() != null;
- Node pred = node.predecessor();
- ControlSplitNode x = (ControlSplitNode) pred;
- double nodeProbability = x.probability(node);
- assert nodeProbability >= 0.0 : "Node " + x + " provided negative probability for begin " + node + ": " + nodeProbability;
- probability *= nodeProbability;
- assert probability >= 0.0;
- }
- }
-
- private class PropagateProbability extends PostOrderNodeIterator {
-
- public PropagateProbability(FixedNode start) {
- super(start, new Probability(1d, null));
- }
-
- @Override
- protected void node(FixedNode node) {
- nodeProbabilities.put(node, state.probability);
- }
- }
-
- private class LoopCount extends MergeableState implements Cloneable {
-
- public double count;
-
- public LoopCount(double count) {
- this.count = count;
- }
-
- @Override
- public LoopCount clone() {
- return new LoopCount(count);
- }
-
- @Override
- public boolean merge(MergeNode merge, List withStates) {
- assert merge.forwardEndCount() == withStates.size() + 1;
- if (merge.forwardEndCount() > 1) {
- Set loops = mergeLoops.get(merge);
- assert loops != null;
- double countProd = 1;
- for (LoopInfo loop : loops) {
- countProd = multiplySaturate(countProd, loop.loopFrequency(nodeProbabilities));
- }
- count = countProd;
- }
- return true;
- }
-
- @Override
- public void loopBegin(LoopBeginNode loopBegin) {
- count = multiplySaturate(count, loopBegin.loopFrequency());
- }
- }
-
- private class PropagateLoopFrequency extends PostOrderNodeIterator {
-
- public PropagateLoopFrequency(FixedNode start) {
- super(start, new LoopCount(1d));
- }
-
- @Override
- protected void node(FixedNode node) {
- nodeProbabilities.put(node, nodeProbabilities.get(node) * state.count);
- }
-
- }
-}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/FixedNodeProbabilityCache.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.graal.phases.graph;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+
+/**
+ * Compute probabilities for fixed nodes on the fly and cache at {@link BeginNode}s and
+ * {@link ControlSplitNode}s.
+ */
+public class FixedNodeProbabilityCache implements ToDoubleFunction {
+
+ private static final DebugMetric metricComputeNodeProbability = Debug.metric("ComputeNodeProbability");
+
+ private final IdentityHashMap cache = new IdentityHashMap<>();
+
+ public double applyAsDouble(FixedNode node) {
+ metricComputeNodeProbability.increment();
+
+ FixedNode current = node;
+ while (true) {
+ Node predecessor = current.predecessor();
+ if (current instanceof BeginNode) {
+ if (predecessor == null) {
+ break;
+ } else if (predecessor.successors().count() != 1) {
+ assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor;
+ break;
+ }
+ }
+ current = (FixedNode) predecessor;
+ }
+
+ Double cachedValue = cache.get(current);
+ if (cachedValue != null) {
+ return cachedValue;
+ }
+
+ double probability;
+ if (current.predecessor() == null) {
+ if (current instanceof MergeNode) {
+ probability = ((MergeNode) current).forwardEnds().stream().mapToDouble(end -> applyAsDouble(end)).sum();
+ if (current instanceof LoopBeginNode) {
+ probability *= ((LoopBeginNode) current).loopFrequency();
+ }
+ } else if (current instanceof StartNode) {
+ probability = 1D;
+ } else {
+ // this should only appear for dead code
+ probability = 1D;
+ }
+ } else {
+ ControlSplitNode split = (ControlSplitNode) current.predecessor();
+ probability = split.probability((BeginNode) current) * applyAsDouble(split);
+ }
+ cache.put(current, probability);
+ return probability;
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/graph/ReentrantNodeIterator.java Sat May 03 21:46:35 2014 +0200
@@ -47,7 +47,7 @@
/**
* Determine whether iteration should continue in the current state.
- *
+ *
* @param currentState
*/
protected boolean continueIteration(StateT currentState) {
@@ -60,11 +60,7 @@
}
public static LoopInfo processLoop(NodeIteratorClosure closure, LoopBeginNode loop, StateT initialState) {
- HashSet boundary = new HashSet<>();
- for (LoopExitNode exit : loop.loopExits()) {
- boundary.add(exit);
- }
- Map blockEndStates = apply(closure, loop, initialState, boundary);
+ Map blockEndStates = apply(closure, loop, initialState, loop);
LoopInfo info = new LoopInfo<>();
for (LoopEndNode end : loop.loopEnds()) {
@@ -80,7 +76,11 @@
return info;
}
- public static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState, Set boundary) {
+ public static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState) {
+ return apply(closure, start, initialState, null);
+ }
+
+ private static Map apply(NodeIteratorClosure closure, FixedNode start, StateT initialState, LoopBeginNode boundary) {
Deque nodeQueue = new ArrayDeque<>();
IdentityHashMap blockEndStates = new IdentityHashMap<>();
@@ -88,7 +88,7 @@
FixedNode current = start;
do {
while (current instanceof FixedWithNextNode) {
- if (boundary != null && boundary.contains(current)) {
+ if (boundary != null && current instanceof LoopExitNode && ((LoopExitNode) current).loopBegin() == boundary) {
blockEndStates.put(current, state);
current = null;
} else {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/BinaryGraphPrinter.java Sat May 03 21:46:35 2014 +0200
@@ -29,6 +29,7 @@
import java.nio.channels.*;
import java.util.*;
import java.util.Map.Entry;
+import java.util.function.*;
import com.oracle.graal.api.meta.*;
import com.oracle.graal.compiler.common.cfg.*;
@@ -36,7 +37,6 @@
import com.oracle.graal.graph.NodeClass.Position;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.cfg.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.phases.graph.*;
import com.oracle.graal.phases.schedule.*;
@@ -394,10 +394,10 @@
}
private void writeNodes(Graph graph) throws IOException {
- NodesToDoubles probabilities = null;
+ ToDoubleFunction probabilities = null;
if (PrintGraphProbabilities.getValue()) {
try {
- probabilities = new ComputeProbabilityClosure((StructuredGraph) graph).apply();
+ probabilities = new FixedNodeProbabilityCache();
} catch (Throwable t) {
}
}
@@ -408,8 +408,8 @@
for (Node node : graph.getNodes()) {
NodeClass nodeClass = node.getNodeClass();
node.getDebugProperties(props);
- if (probabilities != null && node instanceof FixedNode && probabilities.contains((FixedNode) node)) {
- props.put("probability", probabilities.get((FixedNode) node));
+ if (probabilities != null && node instanceof FixedNode) {
+ props.put("probability", probabilities.applyAsDouble((FixedNode) node));
}
writeInt(getNodeId(node));
writePoolObject(nodeClass);
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/ArraysSubstitutionsTest.java Sat May 03 21:46:35 2014 +0200
@@ -31,6 +31,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.replacements.*;
import com.oracle.graal.replacements.nodes.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/MethodSubstitutionTest.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.replacements.test;
import static org.junit.Assert.*;
-
import com.oracle.graal.api.code.*;
import com.oracle.graal.api.replacements.*;
import com.oracle.graal.compiler.test.*;
@@ -33,6 +32,7 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
/**
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/CollapseFrameForSingleSideEffectPhase.java Sat May 03 21:46:35 2014 +0200
@@ -36,11 +36,11 @@
/**
* This phase ensures that there's a single {@linkplain BytecodeFrame#AFTER_BCI collapsed frame
* state} per path.
- *
+ *
* Removes other frame states from {@linkplain StateSplit#hasSideEffect() non-side-effecting} nodes
* in the graph, and replaces them with {@linkplain BytecodeFrame#INVALID_FRAMESTATE_BCI invalid
* frame states}.
- *
+ *
* The invalid frame states ensure that no deoptimization to a snippet frame state will happen.
*/
public class CollapseFrameForSingleSideEffectPhase extends Phase {
@@ -112,7 +112,7 @@
@Override
protected void run(StructuredGraph graph) {
CollapseFrameForSingleSideEffectClosure closure = new CollapseFrameForSingleSideEffectClosure();
- ReentrantNodeIterator.apply(closure, graph.start(), new IterationState(), null);
+ ReentrantNodeIterator.apply(closure, graph.start(), new IterationState());
closure.finishProcessing(graph);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/GraphKit.java Sat May 03 21:46:35 2014 +0200
@@ -35,6 +35,7 @@
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.replacements.ReplacementsImpl.FrameStateProcessing;
import com.oracle.graal.word.phases.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ReplacementsImpl.java Sat May 03 21:46:35 2014 +0200
@@ -49,6 +49,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.replacements.Snippet.DefaultSnippetInliningPolicy;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/SnippetTemplate.java Sat May 03 21:46:35 2014 +0200
@@ -23,7 +23,6 @@
package com.oracle.graal.replacements;
import static com.oracle.graal.api.meta.LocationIdentity.*;
-
import static com.oracle.graal.api.meta.MetaUtil.*;
import static com.oracle.graal.debug.Debug.*;
import static java.util.FormattableFlags.*;
@@ -54,6 +53,7 @@
import com.oracle.graal.nodes.util.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.common.FloatingReadPhase.MemoryMapImpl;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.replacements.Snippet.ConstantParameter;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/nodes/MacroNode.java Sat May 03 21:46:35 2014 +0200
@@ -35,6 +35,7 @@
import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.replacements.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java
--- a/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle.hotspot/src/com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime.java Sat May 03 21:46:35 2014 +0200
@@ -45,14 +45,14 @@
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.printer.*;
import com.oracle.graal.runtime.*;
import com.oracle.graal.truffle.*;
import com.oracle.truffle.api.*;
-import com.oracle.truffle.api.CompilerDirectives.*;
+import com.oracle.truffle.api.CompilerDirectives.SlowPath;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.impl.*;
import com.oracle.truffle.api.nodes.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java
--- a/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle.test/src/com/oracle/graal/truffle/test/PartialEvaluationTest.java Sat May 03 21:46:35 2014 +0200
@@ -37,6 +37,7 @@
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.printer.*;
import com.oracle.graal.truffle.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java Sat May 03 21:46:35 2014 +0200
@@ -48,6 +48,7 @@
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.truffle.nodes.asserts.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCacheImpl.java Sat May 03 21:46:35 2014 +0200
@@ -43,6 +43,7 @@
import com.oracle.graal.nodes.util.*;
import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
import com.oracle.graal.phases.util.*;
import com.oracle.graal.truffle.phases.*;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceIntrinsicsPhase.java Sat May 03 21:46:35 2014 +0200
@@ -28,7 +28,7 @@
import com.oracle.graal.nodes.java.MethodCallTargetNode.InvokeKind;
import com.oracle.graal.nodes.spi.*;
import com.oracle.graal.phases.*;
-import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
/**
* Compiler phase for intrinsifying the access to the Truffle virtual frame.
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/EffectsPhase.java Sat May 03 21:46:35 2014 +0200
@@ -24,6 +24,8 @@
import static com.oracle.graal.debug.Debug.*;
+import java.util.*;
+
import com.oracle.graal.debug.*;
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.graph.*;
@@ -46,7 +48,7 @@
}
private final int maxIterations;
- private final CanonicalizerPhase canonicalizer;
+ protected final CanonicalizerPhase canonicalizer;
public EffectsPhase(int maxIterations, CanonicalizerPhase canonicalizer) {
this.maxIterations = maxIterations;
@@ -85,19 +87,24 @@
new DeadCodeEliminationPhase().apply(graph);
+ Set changedNodes = listener.getChangedNodes();
for (Node node : graph.getNodes()) {
if (node instanceof Simplifiable) {
- listener.getChangedNodes().add(node);
+ changedNodes.add(node);
}
}
- if (canonicalizer != null) {
- canonicalizer.applyIncremental(graph, context, listener.getChangedNodes());
- }
+ postIteration(graph, context, changedNodes);
}
changed = true;
}
return changed;
}
+ protected void postIteration(final StructuredGraph graph, final PhaseContextT context, Set changedNodes) {
+ if (canonicalizer != null) {
+ canonicalizer.applyIncremental(graph, context, changedNodes);
+ }
+ }
+
protected abstract Closure> createEffectsClosure(PhaseContextT context, SchedulePhase schedule);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/IterativeInliningPhase.java Sat May 03 21:46:35 2014 +0200
@@ -31,7 +31,8 @@
import com.oracle.graal.debug.Debug.Scope;
import com.oracle.graal.nodes.*;
import com.oracle.graal.phases.common.*;
-import com.oracle.graal.phases.common.cfs.IterativeFlowSensitiveReductionPhase;
+import com.oracle.graal.phases.common.cfs.*;
+import com.oracle.graal.phases.common.inlining.*;
import com.oracle.graal.phases.tiers.*;
public class IterativeInliningPhase extends AbstractInliningPhase {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapePhase.java Sat May 03 21:46:35 2014 +0200
@@ -26,14 +26,15 @@
import static com.oracle.graal.virtual.phases.ea.PartialEscapePhase.Options.*;
import java.util.*;
+import java.util.function.*;
import com.oracle.graal.graph.*;
import com.oracle.graal.nodes.*;
import com.oracle.graal.nodes.java.*;
import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.nodes.util.*;
import com.oracle.graal.nodes.virtual.*;
import com.oracle.graal.options.*;
+import com.oracle.graal.phases.*;
import com.oracle.graal.phases.common.*;
import com.oracle.graal.phases.graph.*;
import com.oracle.graal.phases.schedule.*;
@@ -42,7 +43,6 @@
public class PartialEscapePhase extends EffectsPhase {
static class Options {
-
//@formatter:off
@Option(help = "")
public static final OptionValue OptEarlyReadElimination = new OptionValue<>(true);
@@ -50,14 +50,28 @@
}
private final boolean readElimination;
+ private final BasePhase cleanupPhase;
public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer) {
- this(iterative, OptEarlyReadElimination.getValue(), canonicalizer);
+ this(iterative, OptEarlyReadElimination.getValue(), canonicalizer, null);
+ }
+
+ public PartialEscapePhase(boolean iterative, CanonicalizerPhase canonicalizer, BasePhase cleanupPhase) {
+ this(iterative, OptEarlyReadElimination.getValue(), canonicalizer, cleanupPhase);
}
- public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer) {
+ public PartialEscapePhase(boolean iterative, boolean readElimination, CanonicalizerPhase canonicalizer, BasePhase cleanupPhase) {
super(iterative ? EscapeAnalysisIterations.getValue() : 1, canonicalizer);
this.readElimination = readElimination;
+ this.cleanupPhase = cleanupPhase;
+ }
+
+ @Override
+ protected void postIteration(StructuredGraph graph, PhaseContext context, Set changedNodes) {
+ super.postIteration(graph, context, changedNodes);
+ if (cleanupPhase != null) {
+ cleanupPhase.apply(graph, context);
+ }
}
@Override
@@ -79,7 +93,7 @@
}
public static Map getHints(StructuredGraph graph) {
- NodesToDoubles probabilities = new ComputeProbabilityClosure(graph).apply();
+ ToDoubleFunction probabilities = new FixedNodeProbabilityCache();
Map hints = null;
for (CommitAllocationNode commit : graph.getNodes().filter(CommitAllocationNode.class)) {
double sum = 0;
@@ -87,14 +101,14 @@
for (Node commitUsage : commit.usages()) {
for (Node usage : commitUsage.usages()) {
if (usage instanceof FixedNode) {
- sum += probabilities.get((FixedNode) usage);
+ sum += probabilities.applyAsDouble((FixedNode) usage);
} else {
if (usage instanceof MethodCallTargetNode) {
- invokeSum += probabilities.get(((MethodCallTargetNode) usage).invoke().asNode());
+ invokeSum += probabilities.applyAsDouble(((MethodCallTargetNode) usage).invoke().asNode());
}
for (Node secondLevelUage : usage.usages()) {
if (secondLevelUage instanceof FixedNode) {
- sum += probabilities.get(((FixedNode) secondLevelUage));
+ sum += probabilities.applyAsDouble(((FixedNode) secondLevelUage));
}
}
}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/LazyClassLoadingTest.java Sat May 03 21:46:35 2014 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, 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 com.oracle.truffle.api.dsl.test;
+
+import java.lang.reflect.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.LazyClassLoadingTestFactory.TestNodeFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
+
+public class LazyClassLoadingTest {
+ @Test
+ public void test() {
+ String testClassName = getClass().getName();
+ String factoryClassName = testClassName + "Factory";
+ String nodeFactoryClassName = factoryClassName + "$TestNodeFactory";
+
+ Assert.assertFalse(isLoaded(factoryClassName + "$TestNode"));
+ Assert.assertFalse(isLoaded(nodeFactoryClassName));
+
+ NodeFactory factory = TestNodeFactory.getInstance();
+
+ Assert.assertTrue(isLoaded(nodeFactoryClassName));
+ Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestBaseNode"));
+
+ TestHelper.createRoot(factory);
+
+ Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestBaseNode"));
+ Assert.assertTrue(isLoaded(nodeFactoryClassName + "$TestUninitializedNode"));
+ Assert.assertFalse(isLoaded(nodeFactoryClassName + "$TestGenericNode"));
+ }
+
+ private boolean isLoaded(String className) {
+ ClassLoader classLoader = getClass().getClassLoader();
+ Method m;
+ try {
+ m = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
+ m.setAccessible(true);
+ return m.invoke(classLoader, className) != null;
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ @NodeChildren({@NodeChild("left"), @NodeChild("right")})
+ abstract static class TestNode extends ValueNode {
+ @Specialization(order = 1)
+ int add(int left, int right) {
+ return 42;
+ }
+
+ @Specialization(order = 2)
+ int add(boolean left, boolean right) {
+ return 21;
+ }
+
+ @Specialization(order = 4)
+ String add(boolean left, int right) {
+ return "(boolean,int)";
+ }
+ }
+}
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java
--- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/ChildNodeTest.java Sat May 03 21:46:35 2014 +0200
@@ -36,10 +36,8 @@
*
*
* Child nodes are stored in the class of the parent node in fields that are marked with the
- * {@link Child} annotation. Before such a field is assigned, {@link Node#adoptChild} must be
- * called. This method automatically establishes a link from the child to the parent. The
- * {@link Node#getParent()} method allows access to this field. Every node also provides the ability
- * to iterate over its children using {@link Node#getChildren()}.
+ * {@link Child} annotation. The {@link Node#getParent()} method allows access to this field. Every
+ * node also provides the ability to iterate over its children using {@link Node#getChildren()}.
*
*
*
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/instrument/impl/DefaultVisualizer.java Sat May 03 21:46:35 2014 +0200
@@ -24,8 +24,6 @@
*/
package com.oracle.truffle.api.instrument.impl;
-import java.io.*;
-
import com.oracle.truffle.api.*;
import com.oracle.truffle.api.frame.*;
import com.oracle.truffle.api.instrument.*;
@@ -53,16 +51,7 @@
section = node.getEncapsulatingSourceSection();
estimated = true;
}
-
- String sourceString;
- if (section == null || section.getSource() == null) {
- sourceString = "";
- } else {
- String sourceName = new File(section.getSource().getName()).getName();
- int startLine = section.getStartLine();
- sourceString = String.format("%s:%d%s", sourceName, startLine, estimated ? "~" : "");
- }
- return sourceString;
+ return section.getShortDescription() + (estimated ? "~" : "");
}
public String displayMethodName(Node node) {
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/Node.java Sat May 03 21:46:35 2014 +0200
@@ -134,31 +134,6 @@
* @param newChildren the array of new children whose parent should be updated
* @return the array of new children
*/
- @SuppressWarnings("static-method")
- @Deprecated
- protected final T[] adoptChildren(final T[] newChildren) {
- return newChildren;
- }
-
- /**
- * Method that updates the link to the parent in the specified new child node to this node.
- *
- * @param newChild the new child whose parent should be updated
- * @return the new child
- */
- @SuppressWarnings("static-method")
- @Deprecated
- protected final T adoptChild(final T newChild) {
- return newChild;
- }
-
- /**
- * Method that updates the link to the parent in the array of specified new child nodes to this
- * node.
- *
- * @param newChildren the array of new children whose parent should be updated
- * @return the array of new children
- */
protected final T[] insert(final T[] newChildren) {
CompilerDirectives.transferToInterpreterAndInvalidate();
assert newChildren != null;
diff -r 5ecbed00da23 -r ff5cacf47b68 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Fri May 02 02:45:26 2014 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Sat May 03 21:46:35 2014 +0200
@@ -49,6 +49,8 @@
private static final String EXECUTE_POLYMORPHIC_NAME = "executePolymorphic0";
private static final String UPDATE_TYPES_NAME = "updateTypes";
+ private static final String COPY_WITH_CONSTRUCTOR_NAME = "copyWithConstructor";
+ private static final String CREATE_SPECIALIZATION_NAME = "createSpecialization";
public NodeCodeGenerator(ProcessorContext context) {
super(context);
@@ -834,7 +836,7 @@
if (node.getSpecializations().isEmpty()) {
body.nullLiteral();
} else {
- body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0)));
+ body.startCall(nodeSpecializationClassName(node.getSpecializations().get(0)), CREATE_SPECIALIZATION_NAME);
for (VariableElement var : method.getParameters()) {
body.string(var.getSimpleName().toString());
}
@@ -865,7 +867,7 @@
if (found == null) {
body.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
} else {
- body.startReturn().startNew(nodeSpecializationClassName(found)).startGroup().cast(baseClassName(node)).string(THIS_NODE_LOCAL_VAR_NAME).end().end().end();
+ body.startReturn().startCall(nodeSpecializationClassName(found), CREATE_SPECIALIZATION_NAME).startGroup().string(THIS_NODE_LOCAL_VAR_NAME).end().end().end();
}
return method;
}
@@ -952,7 +954,6 @@
if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) {
clazz.add(createGenericExecute(node, rootGroup));
}
-
}
protected boolean needsInvokeCopyConstructorMethod() {
@@ -960,7 +961,7 @@
}
protected CodeExecutableElement createCopy(TypeMirror baseType, SpecializationData specialization) {
- CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, "copyWithConstructor");
+ CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), baseType, COPY_WITH_CONSTRUCTOR_NAME);
if (specialization == null) {
method.getModifiers().add(ABSTRACT);
} else {
@@ -968,7 +969,7 @@
builder.startReturn();
builder.startNew(getElement().asType());
builder.string("this");
- for (ActualParameter param : getImplicitTypeParamters(specialization)) {
+ for (ActualParameter param : getImplicitTypeParameters(specialization)) {
builder.string(implicitTypeName(param));
}
builder.end().end();
@@ -1738,7 +1739,7 @@
} else {
replaceCall.startCall("replace");
}
- replaceCall.startGroup().startNew(className).string(source);
+ replaceCall.startGroup().cast(baseClassName(current.getNode())).startCall(className, CREATE_SPECIALIZATION_NAME).string(source);
for (ActualParameter param : current.getSignatureParameters()) {
NodeChildData child = param.getSpecification().getExecution().getChild();
List types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
@@ -1762,7 +1763,7 @@
String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
CodeTreeBuilder builder = parent.create();
- builder.declaration(getElement().asType(), "currentCopy", currentNode + ".copyWithConstructor()");
+ builder.declaration(getElement().asType(), "currentCopy", currentNode + "." + COPY_WITH_CONSTRUCTOR_NAME + "()");
for (ActualParameter param : getModel().getSignatureParameters()) {
NodeExecutionData execution = param.getSpecification().getExecution();
builder.startStatement().tree(createAccessChild(execution, "currentCopy")).string(" = ").nullLiteral().end();
@@ -1928,7 +1929,7 @@
}
}
- protected final List getImplicitTypeParamters(SpecializationData model) {
+ protected final List getImplicitTypeParameters(SpecializationData model) {
List parameter = new ArrayList<>();
for (ActualParameter param : model.getSignatureParameters()) {
NodeChildData child = param.getSpecification().getExecution().getChild();
@@ -2546,6 +2547,18 @@
if (needsInvokeCopyConstructorMethod()) {
clazz.add(createCopy(nodeGen.asType(), specialization));
}
+
+ if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) {
+ clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization));
+ } else {
+ for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
+ if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) {
+ // skip copy constructor - not used
+ continue;
+ }
+ clazz.add(createConstructorFactoryMethod(specialization, constructor));
+ }
+ }
}
protected void createConstructors(CodeTypeElement clazz) {
@@ -2579,7 +2592,7 @@
}
}
if (superConstructor != null) {
- for (ActualParameter param : getImplicitTypeParamters(getModel())) {
+ for (ActualParameter param : getImplicitTypeParameters(getModel())) {
clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
@@ -2911,6 +2924,40 @@
return builder.getRoot();
}
+ protected CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) {
+ List implicitTypeParams = getImplicitTypeParameters(specialization);
+ CodeVariableElement[] parameters = new CodeVariableElement[implicitTypeParams.size() + 1];
+ int i = 0;
+ String baseName = "current";
+ parameters[i++] = new CodeVariableElement(specialization.getNode().getNodeType(), baseName);
+ for (ActualParameter implicitTypeParam : implicitTypeParams) {
+ parameters[i++] = new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam));
+ }
+ CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), CREATE_SPECIALIZATION_NAME, parameters);
+ CodeTreeBuilder builder = method.createBuilder();
+ builder.startReturn();
+ builder.startNew(getElement().asType());
+ builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end();
+ for (ActualParameter param : implicitTypeParams) {
+ builder.string(implicitTypeName(param));
+ }
+ builder.end().end();
+ return method;
+ }
+
+ protected CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) {
+ List extends VariableElement> parameters = constructor.getParameters();
+ CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), CREATE_SPECIALIZATION_NAME,
+ parameters.toArray(new CodeVariableElement[parameters.size()]));
+ CodeTreeBuilder builder = method.createBuilder();
+ builder.startReturn();
+ builder.startNew(getElement().asType());
+ for (VariableElement param : parameters) {
+ builder.string(((CodeVariableElement) param).getName());
+ }
+ builder.end().end();
+ return method;
+ }
}
private interface CodeBlock {
diff -r 5ecbed00da23 -r ff5cacf47b68 mx/projects
--- a/mx/projects Fri May 02 02:45:26 2014 +0200
+++ b/mx/projects Sat May 03 21:46:35 2014 +0200
@@ -315,7 +315,7 @@
# graal.alloc
project@com.oracle.graal.alloc@subDir=graal
project@com.oracle.graal.alloc@sourceDirs=src
-project@com.oracle.graal.alloc@dependencies=com.oracle.graal.nodes
+project@com.oracle.graal.alloc@dependencies=com.oracle.graal.compiler.common
project@com.oracle.graal.alloc@checkstyle=com.oracle.graal.graph
project@com.oracle.graal.alloc@javaCompliance=1.8
project@com.oracle.graal.alloc@workingSets=Graal
diff -r 5ecbed00da23 -r ff5cacf47b68 src/gpu/hsail/vm/gpu_hsail.cpp
--- a/src/gpu/hsail/vm/gpu_hsail.cpp Fri May 02 02:45:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.cpp Sat May 03 21:46:35 2014 +0200
@@ -67,7 +67,7 @@
JNINativeMethod Hsail::HSAIL_methods[] = {
{CC"initialize", CC"()Z", FN_PTR(Hsail::initialize)},
{CC"generateKernel", CC"([B" STRING ")J", FN_PTR(Hsail::generate_kernel)},
- {CC"executeKernel0", CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT"["JLTHREAD"I)Z", FN_PTR(Hsail::execute_kernel_void_1d)},
+ {CC"executeKernel0", CC"("HS_INSTALLED_CODE"I["OBJECT"["OBJECT"["JLTHREAD"I[I)Z", FN_PTR(Hsail::execute_kernel_void_1d)},
};
void * Hsail::_device_context = NULL;
@@ -147,7 +147,7 @@
}
GPU_VMENTRY(jboolean, Hsail::execute_kernel_void_1d, (JNIEnv* env, jclass, jobject kernel_handle, jint dimX, jobject args, jobject oops_save,
- jobject donor_threads, jint allocBytesPerWorkitem))
+ jobject donor_threads, jint allocBytesPerWorkitem, jobject oop_map_array))
ResourceMark rm;
jlong nmethodValue = InstalledCode::address(kernel_handle);
@@ -163,7 +163,7 @@
SharedRuntime::throw_and_post_jvmti_exception(JavaThread::current(), vmSymbols::com_oracle_graal_api_code_InvalidInstalledCodeException(), NULL);
}
- return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, oops_save, donor_threads, allocBytesPerWorkitem, CHECK_0);
+return execute_kernel_void_1d_internal((address) kernel, dimX, args, mh, nm, oops_save, donor_threads, allocBytesPerWorkitem, oop_map_array, CHECK_0);
GPU_END
static void showRanges(jboolean *a, int len) {
@@ -215,9 +215,141 @@
tty->print_cr("(%p, %p, %p), siz=%ld, free=%ld (%f%%)", start, top, end, tlabSize, tlabFree, freePct);
}
+class OopSaver : public StackObj {
+private:
+ objArrayOop _oopsSaveArray;
+ typeArrayOop _oopMapArray;
+ jobject _oops_save;
+ jobject _oop_map_array;
+ int _last_pcoffset;
+ int _last_idx;
+ int _saveAreaCounts;
-jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oops_save,
- jobject donor_threads, int allocBytesPerWorkitem, TRAPS) {
+ enum {
+ SAVEAREACOUNTS_OFST=0,
+ SPAN_OFST=1,
+ HEADERSIZE=2
+ };
+ int mapPcOffsetToIndex(int pcOffset) {
+ if (pcOffset == _last_pcoffset) {
+ return _last_idx;
+ }
+ int span = _oopMapArray->int_at(SPAN_OFST);
+ for (int idx = HEADERSIZE; idx < _oopMapArray->length(); idx += span) {
+ int ofst = _oopMapArray->int_at(idx);
+ if (ofst == pcOffset) {
+ _last_pcoffset = pcOffset;
+ _last_idx = idx + 1;
+ return _last_idx;
+ }
+ }
+ ShouldNotReachHere();
+ return -1;
+ }
+
+public:
+ OopSaver(jobject oops_save, jobject oop_map_array) {
+ _oops_save = oops_save;
+ _oop_map_array = oop_map_array;
+ _last_pcoffset = -1;
+ _saveAreaCounts = getSaveAreaCounts(oop_map_array);
+ resolveArrays();
+ }
+
+ void resolveArrays() {
+ _oopsSaveArray = (objArrayOop) JNIHandles::resolve(_oops_save);
+ _oopMapArray = (typeArrayOop) JNIHandles::resolve(_oop_map_array);
+ }
+
+ void * getOopForBit(HSAILFrame * hsailFrame, int bit) {
+ assert(isOop(hsailFrame, bit), "");
+ void *oop;
+ if (bit < hsailFrame->num_d_regs()) {
+ // d register
+ oop = (void*) hsailFrame->get_d_reg(bit);
+ } else {
+ // stack slot
+ int stackOffset = (bit - hsailFrame->num_d_regs()) * 8; // 8 bytes per stack slot
+ oop = (void *) hsailFrame->get_stackslot64(stackOffset);
+ }
+ return oop;
+ }
+
+ void putOopForBit(HSAILFrame * hsailFrame, int bit, void *oop) {
+ assert(isOop(hsailFrame, bit), "");
+ if (bit < hsailFrame->num_d_regs()) {
+ // d register
+ hsailFrame->put_d_reg(bit, (jlong) oop);
+ } else {
+ // stack slot
+ int stackOffset = (bit - hsailFrame->num_d_regs()) * 8; // 8 bytes per stack slot
+ hsailFrame->put_stackslot64(stackOffset, (jlong) oop);
+ }
+ }
+
+ void saveOopsFromFrame(HSAILFrame * hsailFrame, int deoptSlot){
+ // as used, no need to resolve arrays on each call
+ int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+
+ // handle the dregister and stackSlot based oops
+ for (int bit = 0; bit < oopsPerDeopt; bit++) {
+ if (isOop(hsailFrame, bit)) {
+ void* saved_oop = getOopForBit(hsailFrame, bit);
+ int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
+ _oopsSaveArray->obj_at_put(saveArrayIndex, (oop) saved_oop);
+ }
+ }
+ }
+
+ void restoreOopsToFrame(HSAILFrame * hsailFrame, int deoptSlot, int workitem){
+ // need to re-resolve on each restore
+ resolveArrays();
+ int oopsPerDeopt = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+
+ // handle the dregister and stackSlot based oops
+ for (int bit = 0; bit < oopsPerDeopt; bit++) {
+ if (isOop(hsailFrame, bit)) {
+ // the dregister or stack slot at this bit is an oop, retrieve it from array and put back in frame
+ int saveArrayIndex = deoptSlot * oopsPerDeopt + bit;
+ void * newValue = (void *) _oopsSaveArray->obj_at(saveArrayIndex);
+ void * oldValue = getOopForBit(hsailFrame, bit);
+ assert((oldValue != 0 ? newValue != 0 : newValue == 0), "bad dregValue retrieved");
+ if (newValue != oldValue) {
+ if (TraceGPUInteraction) {
+ int numDRegs = hsailFrame->num_d_regs();
+ const char *name = (bit < numDRegs ? "$d" : "stk");
+ int num = (bit < numDRegs ? bit : bit - numDRegs);
+ tty->print_cr("oop moved for %s%d, workitem %d, slot %d, old=%p, new=%p",
+ name, num, workitem, deoptSlot, oldValue, newValue);
+ }
+ putOopForBit(hsailFrame, bit, newValue);
+ }
+ }
+ }
+ }
+
+ bool isOop(HSAILFrame * hsailFrame, int bit){
+ // re-resolve on each access
+ resolveArrays();
+ if (bit > hsailFrame->num_d_regs() + hsailFrame->num_stack_slots()) {
+ return false;
+ }
+ int pcOffset = hsailFrame->pc_offset();
+ int bits_int_idx = mapPcOffsetToIndex(pcOffset) + (bit / 32);
+ int bitpos = bit % 32;
+ int bits = _oopMapArray->int_at(bits_int_idx);
+ return ((bits & (1 << bitpos)) != 0);
+ }
+
+ static int getSaveAreaCounts(jobject oopMapArrayObject) {
+ typeArrayOop oopMapArray = (typeArrayOop) JNIHandles::resolve(oopMapArrayObject);
+ return oopMapArray->int_at(SAVEAREACOUNTS_OFST);
+ }
+
+};
+
+jboolean Hsail::execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oops_save,
+ jobject donor_threads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS) {
ResourceMark rm(THREAD);
objArrayOop argsArray = (objArrayOop) JNIHandles::resolve(args);
@@ -260,9 +392,16 @@
// Reset the kernel arguments
_okra_clearargs(kernel);
+ // get how many bytes per deopt save area are required
+ int saveAreaCounts = OopSaver::getSaveAreaCounts(oop_map_array);
+ int numSRegs = saveAreaCounts & 0xff;
+ int numDRegs = (saveAreaCounts >> 8) & 0xff;
+ int numStackSlots = (saveAreaCounts >> 16);
+ int bytesPerSaveArea = numSRegs * 4 + (numDRegs + numStackSlots) * 8;
+
HSAILDeoptimizationInfo* e;
if (UseHSAILDeoptimization) {
- e = new (ResourceObj::C_HEAP, mtInternal) HSAILDeoptimizationInfo();
+ e = new (MAX_DEOPT_SLOTS, bytesPerSaveArea) HSAILDeoptimizationInfo(MAX_DEOPT_SLOTS, bytesPerSaveArea);
e->set_never_ran_array(NEW_C_HEAP_ARRAY(jboolean, dimX, mtInternal));
memset(e->never_ran_array(), 0, dimX * sizeof(jboolean));
e->set_donor_threads(donorThreads);
@@ -318,7 +457,6 @@
if (UseHSAILDeoptimization) {
kernelStats.incDeopts();
// check if any workitem requested a deopt
- // currently we only support at most one such workitem
int deoptcode = e->deopt_occurred();
if (deoptcode != 1) {
if (deoptcode == 0) {
@@ -337,40 +475,30 @@
TraceTime t3("handle deoptimizing workitems", TraceGPUInteraction);
if (TraceGPUInteraction) {
tty->print_cr("deopt happened.");
- HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[0];
+ HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(0);
tty->print_cr("first deopter was workitem %d", pdeopt->workitem());
}
// Before handling any deopting workitems, save the pointers from
// the hsail frames in oops_save so they get adjusted by any
// GC. Need to do this before leaving thread_in_vm mode.
+ OopSaver oopSaver(oops_save, oop_map_array);
// resolve handle only needed once here (not exiting vm mode)
- objArrayOop oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save);
+ oopSaver.resolveArrays();
// since slots are allocated from the beginning, we know how far to look
- assert(e->num_deopts() < MAX_DEOPT_SAVE_STATES_SIZE, "deopt save state overflow");
+ assert(e->num_deopts() < e->num_slots(), "deopt save state overflow");
for (int k = 0; k < e->num_deopts(); k++) {
- HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k];
- jint workitem = pdeopt->workitem();
- if (workitem != -1) {
- // this is a workitem that deopted
- HSAILFrame *hsailFrame = pdeopt->first_frame();
- int dregOopMap = hsailFrame->dreg_oops_map();
- for (int bit = 0; bit < 16; bit++) {
- if ((dregOopMap & (1 << bit)) != 0) {
- // the dregister at this bit is an oop, save it in the array
- int index = k * 16 + bit;
- void* saved_oop = (void*) hsailFrame->get_d_reg(bit);
- oopsSaveArray->obj_at_put(index, (oop) saved_oop);
- }
- }
- }
+ HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
+ assert (pdeopt->workitem() >= 0, "bad workitem in deopt");
+ // this is a workitem that deopted
+ oopSaver.saveOopsFromFrame(pdeopt->first_frame(), k);
}
// Handle any deopting workitems.
int count_deoptimized = 0;
for (int k = 0; k < e->num_deopts(); k++) {
- HSAILKernelDeoptimization * pdeopt = &e->_deopt_save_states[k];
+ HSAILKernelDeoptimization * pdeopt = e->get_deopt_save_state(k);
jint workitem = pdeopt->workitem();
if (workitem != -1) {
@@ -378,25 +506,8 @@
HSAILFrame *hsailFrame = pdeopt->first_frame();
// update the hsailFrame from the oopsSaveArray
- // re-resolve the handle
- oopsSaveArray = (objArrayOop) JNIHandles::resolve(oops_save);
-
- int dregOopMap = hsailFrame->dreg_oops_map();
- for (int bit = 0; bit < 16; bit++) {
- if ((dregOopMap & (1 << bit)) != 0) {
- // the dregister at this bit is an oop, retrieve it from array and put back in frame
- int index = k * 16 + bit;
- void * dregValue = (void *) oopsSaveArray->obj_at(index);
- void * oldDregValue = (void *) hsailFrame->get_d_reg(bit);
- assert((oldDregValue != 0 ? dregValue != 0 : dregValue == 0), "bad dregValue retrieved");
- if (TraceGPUInteraction) {
- if (dregValue != oldDregValue) {
- tty->print_cr("oop moved for $d%d, workitem %d, slot %d, old=%p, new=%p", bit, workitem, k, oldDregValue, dregValue);
- }
- }
- hsailFrame->put_d_reg(bit, (jlong) dregValue);
- }
- }
+ // will re-resolve the handles each time
+ oopSaver.restoreOopsToFrame(hsailFrame, k, workitem);
JavaValue result(T_VOID);
JavaCallArguments javaArgs;
@@ -410,12 +521,19 @@
javaArgs.push_int(myActionReason);
javaArgs.push_oop((oop) NULL);
if (TraceGPUInteraction) {
- int dregOopMap = hsailFrame->dreg_oops_map();
- tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d, dregOopMap=%04x", workitem, k, deoptId, hsailFrame, myActionReason, dregOopMap);
- // show the registers containing references
- for (int bit = 0; bit < 16; bit++) {
- if ((dregOopMap & (1 << bit)) != 0) {
- tty->print_cr(" oop $d%d = %p", bit, hsailFrame->get_d_reg(bit));
+ tty->print_cr("[HSAIL] Deoptimizing to host for workitem=%d (slot=%d) with deoptId=%d, frame=" INTPTR_FORMAT ", actionAndReason=%d", workitem, k, deoptId, hsailFrame, myActionReason);
+ // show the $d registers or stack slots containing references
+ int maxOopBits = hsailFrame->num_d_regs() + hsailFrame->num_stack_slots();
+ for (int bit = 0; bit < maxOopBits; bit++) {
+ if (oopSaver.isOop(hsailFrame, bit)) {
+ if (bit < hsailFrame->num_d_regs()) {
+ // show $d reg oop
+ tty->print_cr(" oop $d%d = %p", bit, oopSaver.getOopForBit(hsailFrame, bit));
+ } else {
+ // show stack slot oop
+ int stackOffset = (bit - hsailFrame->num_d_regs()) * 8; // 8 bytes per stack slot
+ tty->print_cr(" oop stk:%d = %p", stackOffset, oopSaver.getOopForBit(hsailFrame, bit));
+ }
}
}
}
@@ -461,7 +579,7 @@
}
}
TraceGPUInteraction = savedTraceGPUInteraction;
- if (TraceGPUInteraction) {
+ if (TraceGPUInteraction && (count_never_ran > 0)) {
tty->print_cr("%d workitems never ran, have been run via JavaCall", count_never_ran);
showRanges(never_ran_array, dimX);
}
diff -r 5ecbed00da23 -r ff5cacf47b68 src/gpu/hsail/vm/gpu_hsail.hpp
--- a/src/gpu/hsail/vm/gpu_hsail.hpp Fri May 02 02:45:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail.hpp Sat May 03 21:46:35 2014 +0200
@@ -51,7 +51,8 @@
};
// 8 compute units * 40 waves per cu * wavesize 64
-#define MAX_DEOPT_SAVE_STATES_SIZE (8 * 40 * 64)
+// TODO: query the device to get this number
+#define MAX_DEOPT_SLOTS (8 * 40 * 64)
class HSAILDeoptimizationInfo : public ResourceObj {
friend class VMStructs;
@@ -61,14 +62,23 @@
jint _deopt_next_index;
JavaThread** _donor_threads;
jboolean * _never_ran_array;
+ jint _num_slots;
+ jint _bytesPerSaveArea;
+ jint _deopt_span;
public:
- HSAILKernelDeoptimization _deopt_save_states[MAX_DEOPT_SAVE_STATES_SIZE];
+ HSAILKernelDeoptimization _deopt_save_states[1]; // number and size of these can vary per kernel
- inline HSAILDeoptimizationInfo() {
+ inline HSAILDeoptimizationInfo(int numSlots, int bytesPerSaveArea) {
_notice_safepoints = &Hsail::_notice_safepoints;
_deopt_occurred = 0;
_deopt_next_index = 0;
+ _num_slots = numSlots;
+ _bytesPerSaveArea = bytesPerSaveArea;
+ _deopt_span = sizeof(HSAILKernelDeoptimization) + bytesPerSaveArea;
+ if (TraceGPUInteraction) {
+ tty->print_cr("HSAILDeoptimizationInfo allocated, %d slots of size %d, total size = 0x%lx bytes", _num_slots, _deopt_span, (_num_slots * _deopt_span + sizeof(HSAILDeoptimizationInfo)));
+ }
}
inline jint deopt_occurred() {
@@ -78,6 +88,23 @@
inline jboolean *never_ran_array() { return _never_ran_array; }
inline void set_never_ran_array(jboolean *p) { _never_ran_array = p; }
inline void set_donor_threads(JavaThread **threads) { _donor_threads = threads; }
+ inline jint num_slots() {return _num_slots;}
+
+ inline HSAILKernelDeoptimization * get_deopt_save_state(int slot) {
+ // use _deopt_span to index into _deopt_states
+ char *p = (char *) _deopt_save_states;
+ p += _deopt_span * slot;
+ return (HSAILKernelDeoptimization *) p;
+ }
+
+ void * operator new (size_t hdrSize, int numSlots, int bytesPerSaveArea) {
+ size_t totalSizeBytes = hdrSize + numSlots * (sizeof(HSAILKernelDeoptimization) + bytesPerSaveArea);
+ return NEW_C_HEAP_ARRAY(char, totalSizeBytes, mtInternal);
+ }
+
+ void operator delete (void *ptr) {
+ FREE_C_HEAP_ARRAY(char, ptr, mtInternal);
+ }
};
@@ -93,7 +120,7 @@
// static native boolean executeKernel0(HotSpotInstalledCode kernel, int jobSize, Object[] args);
JNIEXPORT static jboolean execute_kernel_void_1d(JNIEnv *env, jclass, jobject hotspotInstalledCode, jint dimX, jobject args, jobject oopsSave,
- jobject donorThreads, int allocBytesPerWorkitem);
+ jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array);
// static native void getThreadPointers(Object[] donorThreads, long[] threadPointersOut);
JNIEXPORT static void get_thread_pointers(JNIEnv *env, jclass, jobject donor_threads_handle, jobject thread_ptrs_handle);
@@ -101,8 +128,8 @@
static void getNewTlabForDonorThread(ThreadLocalAllocBuffer* tlab, size_t tlabMinHsail);
static jboolean execute_kernel_void_1d_internal(address kernel, int dimX, jobject args, methodHandle& mh, nmethod *nm, jobject oopsSave,
- jobject donor_threads, int allocBytesPerWorkitem, TRAPS);
-
+ jobject donorThreads, int allocBytesPerWorkitem, jobject oop_map_array, TRAPS);
+
static void register_heap();
static GraalEnv::CodeInstallResult install_code(Handle& compiled_code, CodeBlob*& cb, Handle installed_code, Handle triggered_deoptimizations);
diff -r 5ecbed00da23 -r ff5cacf47b68 src/gpu/hsail/vm/gpu_hsail_Frame.hpp
--- a/src/gpu/hsail/vm/gpu_hsail_Frame.hpp Fri May 02 02:45:26 2014 +0200
+++ b/src/gpu/hsail/vm/gpu_hsail_Frame.hpp Sat May 03 21:46:35 2014 +0200
@@ -5,39 +5,44 @@
#include "code/debugInfo.hpp"
#include "code/location.hpp"
-// maximum registers that could be saved for now
-#define MAX_SREGS 32
-#define MAX_DREGS 16
-
class HSAILFrame {
friend class VMStructs;
private:
jint _pc_offset; // The HSAIL "pc_offset" where the exception happens
jbyte _num_s_regs;
jbyte _num_d_regs;
- jshort _dreg_oops_map; // bits = 1 if that dreg is an oop
- jlong _save_area[MAX_SREGS/2 + MAX_DREGS];
+ jshort _num_stack_slots;
+ jbyte _save_area[0]; // save area size can vary per kernel compilation
public:
// Accessors
jint pc_offset() { return _pc_offset; }
jint num_s_regs() {return _num_s_regs; }
jint num_d_regs() {return _num_d_regs; }
- jint dreg_oops_map() {return _dreg_oops_map; }
+ jint num_stack_slots() {return _num_stack_slots; }
jlong get_d_reg(int idx) {
- char *p = (char *) _save_area;
int ofst = num_s_regs() * 4 + idx * 8;
- return(*(jlong *) (p + ofst));
+ return(*(jlong *) (_save_area + ofst));
}
jint get_s_reg(int idx) {
- char *p = (char *) _save_area;
int ofst = idx * 4;
- return(*(jint *) (p + ofst));
+ return(*(jint *) (_save_area + ofst));
}
void put_d_reg(int idx, jlong val) {
- char *p = (char *) _save_area;
int ofst = num_s_regs() * 4 + idx * 8;
- (*(jlong *) (p + ofst)) = val;
+ (*(jlong *) (_save_area + ofst)) = val;
+ }
+ jint get_stackslot32(int stackOffset) {
+ int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+ return(*(jint *) (_save_area + ofst));
+ }
+ jlong get_stackslot64(int stackOffset) {
+ int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+ return(*(jlong *) (_save_area + ofst));
+ }
+ void put_stackslot64(int stackOffset, jlong val) {
+ int ofst = num_s_regs() * 4 + num_d_regs() * 8 + stackOffset;
+ (*(jlong *) (_save_area + ofst)) = val;
}
};
diff -r 5ecbed00da23 -r ff5cacf47b68 src/gpu/hsail/vm/vmStructs_hsail.hpp
--- a/src/gpu/hsail/vm/vmStructs_hsail.hpp Fri May 02 02:45:26 2014 +0200
+++ b/src/gpu/hsail/vm/vmStructs_hsail.hpp Sat May 03 21:46:35 2014 +0200
@@ -32,10 +32,11 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_GPU_HSAIL(nonstatic_field) \
+#define VM_STRUCTS_GPU_HSAIL(nonstatic_field) \
nonstatic_field(HSAILFrame, _pc_offset, jint) \
nonstatic_field(HSAILFrame, _num_s_regs, jbyte) \
- nonstatic_field(HSAILFrame, _save_area[0], jlong) \
+ nonstatic_field(HSAILFrame, _num_d_regs, jbyte) \
+ nonstatic_field(HSAILFrame, _num_stack_slots, jshort) \
\
nonstatic_field(Hsail::HSAILKernelDeoptimization, _workitemid, jint) \
nonstatic_field(Hsail::HSAILKernelDeoptimization, _actionAndReason, jint) \
@@ -47,7 +48,6 @@
nonstatic_field(Hsail::HSAILDeoptimizationInfo, _donor_threads, JavaThread**) \
nonstatic_field(Hsail::HSAILDeoptimizationInfo, _never_ran_array, jboolean *) \
nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[0], Hsail::HSAILKernelDeoptimization) \
- nonstatic_field(Hsail::HSAILDeoptimizationInfo, _deopt_save_states[1], Hsail::HSAILKernelDeoptimization)
#define VM_TYPES_GPU_HSAIL(declare_type, declare_toplevel_type) \
declare_toplevel_type(HSAILFrame) \
@@ -55,4 +55,8 @@
declare_toplevel_type(Hsail::HSAILKernelDeoptimization) \
declare_toplevel_type(Hsail::HSAILDeoptimizationInfo)
+#define VM_INT_CONSTANTS_GPU_HSAIL(declare_constant) \
+ declare_constant(sizeof(HSAILFrame)) \
+ declare_constant(sizeof(Hsail::HSAILKernelDeoptimization)) \
+
#endif // GPU_HSAIL_VM_VMSTRUCTS_HSAIL_HPP
diff -r 5ecbed00da23 -r ff5cacf47b68 src/share/vm/compiler/compileBroker.cpp
--- a/src/share/vm/compiler/compileBroker.cpp Fri May 02 02:45:26 2014 +0200
+++ b/src/share/vm/compiler/compileBroker.cpp Sat May 03 21:46:35 2014 +0200
@@ -516,7 +516,8 @@
if (_osr_bci != CompileBroker::standard_entry_bci) {
log->print(" osr_bci='%d'", _osr_bci);
}
- if (_comp_level != CompLevel_highest_tier) {
+ // Always print the level in tiered.
+ if (_comp_level != CompLevel_highest_tier || TieredCompilation) {
log->print(" level='%d'", _comp_level);
}
if (_is_blocking) {
diff -r 5ecbed00da23 -r ff5cacf47b68 src/share/vm/graal/graalCompiler.cpp
--- a/src/share/vm/graal/graalCompiler.cpp Fri May 02 02:45:26 2014 +0200
+++ b/src/share/vm/graal/graalCompiler.cpp Sat May 03 21:46:35 2014 +0200
@@ -58,12 +58,18 @@
NOT_LP64(error("check TLAB allocation code for address space conflicts"));
BufferBlob* buffer_blob = initialize_buffer_blob();
- if (buffer_blob == NULL) {
- // If we are called from JNI_CreateJavaVM we cannot use set_state yet because it takes a lock.
- // set_state(failed);
- } else {
- // set_state(initialized);
+#ifdef COMPILERGRAAL
+ if (!UseGraalCompilationQueue) {
+ // This path is used for initialization both by the native queue and the graal queue
+ // but set_state acquired a lock which might not be safe during JVM_CreateJavaVM, so
+ // only update the state flag for the native queue.
+ if (buffer_blob == NULL) {
+ set_state(failed);
+ } else {
+ set_state(initialized);
+ }
}
+#endif
JNIEnv *env = ((JavaThread *) Thread::current())->jni_environment();
jclass klass = env->FindClass("com/oracle/graal/hotspot/bridge/CompilerToVMImpl");
diff -r 5ecbed00da23 -r ff5cacf47b68 src/share/vm/graal/graalGlobals.hpp
--- a/src/share/vm/graal/graalGlobals.hpp Fri May 02 02:45:26 2014 +0200
+++ b/src/share/vm/graal/graalGlobals.hpp Sat May 03 21:46:35 2014 +0200
@@ -52,7 +52,7 @@
COMPILERGRAAL_PRESENT(product(bool, BootstrapGraal, true, \
"Bootstrap Graal before running Java main method")) \
\
- COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, false, \
+ COMPILERGRAAL_PRESENT(product(bool, UseGraalCompilationQueue, true, \
"Use non-native compilation queue for Graal")) \
\
product(bool, ForceGraalInitialization, false, \
diff -r 5ecbed00da23 -r ff5cacf47b68 src/share/vm/runtime/vmStructs.cpp
--- a/src/share/vm/runtime/vmStructs.cpp Fri May 02 02:45:26 2014 +0200
+++ b/src/share/vm/runtime/vmStructs.cpp Sat May 03 21:46:35 2014 +0200
@@ -106,6 +106,7 @@
#include "utilities/macros.hpp"
#ifdef GRAAL
# include "graal/vmStructs_graal.hpp"
+# include "hsail/vm/vmStructs_hsail.hpp"
#endif
#ifdef TARGET_ARCH_x86
# include "vmStructs_x86.hpp"
@@ -153,8 +154,6 @@
# include "vmStructs_bsd_zero.hpp"
#endif
-#include "hsail/vm/vmStructs_hsail.hpp"
-
#if INCLUDE_ALL_GCS
#include "gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp"
#include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp"
@@ -3042,7 +3041,9 @@
GENERATE_C1_UNCHECKED_STATIC_VM_STRUCT_ENTRY,
GENERATE_C2_UNCHECKED_STATIC_VM_STRUCT_ENTRY)
+#ifdef GRAAL
VM_STRUCTS_GPU_HSAIL(GENERATE_NONSTATIC_VM_STRUCT_ENTRY)
+#endif
VM_STRUCTS_OS_CPU(GENERATE_NONSTATIC_VM_STRUCT_ENTRY,
GENERATE_STATIC_VM_STRUCT_ENTRY,
@@ -3094,8 +3095,10 @@
GENERATE_C2_VM_TYPE_ENTRY,
GENERATE_C2_TOPLEVEL_VM_TYPE_ENTRY)
+#ifdef GRAAL
VM_TYPES_GPU_HSAIL(GENERATE_VM_TYPE_ENTRY,
GENERATE_TOPLEVEL_VM_TYPE_ENTRY)
+#endif
VM_TYPES_OS_CPU(GENERATE_VM_TYPE_ENTRY,
GENERATE_TOPLEVEL_VM_TYPE_ENTRY,
@@ -3120,6 +3123,8 @@
#ifdef GRAAL
VM_INT_CONSTANTS_GRAAL(GENERATE_VM_INT_CONSTANT_ENTRY,
GENERATE_PREPROCESSOR_VM_INT_CONSTANT_ENTRY)
+
+ VM_INT_CONSTANTS_GPU_HSAIL(GENERATE_VM_INT_CONSTANT_ENTRY)
#endif
#if INCLUDE_ALL_GCS
@@ -3201,7 +3206,9 @@
CHECK_NO_OP,
CHECK_NO_OP);
- VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY);
+#ifdef GRAAL
+ VM_STRUCTS_GPU_HSAIL(CHECK_NONSTATIC_VM_STRUCT_ENTRY)
+#endif
VM_STRUCTS_OS_CPU(CHECK_NONSTATIC_VM_STRUCT_ENTRY,
CHECK_STATIC_VM_STRUCT_ENTRY,
@@ -3243,8 +3250,10 @@
CHECK_C2_VM_TYPE_ENTRY,
CHECK_C2_TOPLEVEL_VM_TYPE_ENTRY);
+#ifdef GRAAL
VM_TYPES_GPU_HSAIL(CHECK_VM_TYPE_ENTRY,
CHECK_SINGLE_ARG_VM_TYPE_NO_OP);
+#endif
VM_TYPES_OS_CPU(CHECK_VM_TYPE_ENTRY,
CHECK_SINGLE_ARG_VM_TYPE_NO_OP,