# HG changeset patch # User iveresov # Date 1491514292 25200 # Node ID 0337d0617e7bf7af7939db7fc858f9b841ea2f26 # Parent b9a1aa504eb503a4a1315d6430632e290adbbec7 8178088: Update Graal Summary: Update Graal, do appropriate changes to jaotc Reviewed-by: kvn diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Thu Apr 06 14:31:32 2017 -0700 @@ -54,12 +54,9 @@ import jdk.vm.ci.meta.TriState; public class AOTBackend { - private final Main main; private final OptionValues graalOptions; - private final HotSpotBackend backend; - private final HotSpotProviders providers; private final HotSpotCodeCacheProvider codeCache; private final PhaseSuite graphBuilderSuite; @@ -81,6 +78,10 @@ return graphBuilderSuite; } + public HotSpotBackend getBackend() { + return backend; + } + private Suites getSuites() { // create suites every time, as we modify options for the compiler return backend.getSuites().getDefaultSuites(graalOptions); @@ -189,7 +190,7 @@ public void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) { // This is really not installing the method. - InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult), null, null); + InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult), null, null); String disassembly = codeCache.disassemble(installedCode); if (disassembly != null) { main.printlnDebug(disassembly); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java Thu Apr 06 14:31:32 2017 -0700 @@ -145,7 +145,7 @@ aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult); } - result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method)); + result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend())); } private String getMethodDescription() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java Thu Apr 06 14:31:32 2017 -0700 @@ -24,6 +24,7 @@ package jdk.tools.jaotc; import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -31,9 +32,11 @@ public class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo { private final HotSpotResolvedJavaMethod method; + private final Backend backend; - public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method) { + public AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) { this.method = method; + this.backend = backend; } public String getSymbolName() { @@ -46,7 +49,7 @@ } public HotSpotCompiledCode compiledCode(CompilationResult result) { - return HotSpotCompiledCodeBuilder.createCompiledCode(method, null, result); + return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), method, null, result); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java --- a/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java Thu Apr 06 14:31:32 2017 -0700 @@ -49,7 +49,7 @@ } public HotSpotCompiledCode compiledCode(CompilationResult result) { - return HotSpotCompiledCodeBuilder.createCompiledCode(null, null, result); + return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), null, null, result); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,15 +22,16 @@ */ package org.graalvm.compiler.api.directives.test; -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode; +import org.junit.Assert; +import org.junit.Test; public class ProbabilityDirectiveTest extends GraalCompilerTest { @@ -55,9 +56,21 @@ Assert.assertEquals("IfNode count", 1, ifNodes.count()); IfNode ifNode = ifNodes.first(); - AbstractBeginNode trueSuccessor = ifNode.trueSuccessor(); - Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(trueSuccessor), 0); + AbstractBeginNode oneSuccessor; + if (returnValue(ifNode.trueSuccessor()) == 1) { + oneSuccessor = ifNode.trueSuccessor(); + } else { + assert returnValue(ifNode.falseSuccessor()) == 1; + oneSuccessor = ifNode.falseSuccessor(); + } + Assert.assertEquals("branch probability of " + ifNode, 0.125, ifNode.probability(oneSuccessor), 0); return true; } + + private static int returnValue(AbstractBeginNode b) { + ControlFlowAnchorNode anchor = (ControlFlowAnchorNode) b.next(); + ReturnNode returnNode = (ReturnNode) anchor.next(); + return returnNode.result().asJavaConstant().asInt(); + } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.sparc/src/org/graalvm/compiler/asm/sparc/SPARCAssembler.java Thu Apr 06 14:31:32 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -1757,6 +1757,10 @@ return constant.isNull() || isSimm(constant.asLong(), 5); } + public static boolean isSimm5(long imm) { + return isSimm(imm, 5); + } + public static boolean isSimm13(int imm) { return isSimm(imm, 13); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java Thu Apr 06 14:31:32 2017 -0700 @@ -35,7 +35,7 @@ @SuppressWarnings("try") public static void printTraceStatistics(TraceBuilderResult result, String compilationUnitName) { try (Scope s = Debug.scope("DumpTraceStatistics")) { - if (Debug.isLogEnabled(Debug.VERBOSE_LOG_LEVEL)) { + if (Debug.isLogEnabled(Debug.VERBOSE_LEVEL)) { print(result, compilationUnitName); } } catch (Throwable e) { @@ -48,9 +48,9 @@ List traces = result.getTraces(); int numTraces = traces.size(); - try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "")) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", compilationUnitName != null ? compilationUnitName : "null"); - try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "")) { + try (Indent indent0 = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "")) { + Debug.log(Debug.VERBOSE_LEVEL, "%s", compilationUnitName != null ? compilationUnitName : "null"); + try (Indent indent1 = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "")) { printRawLine("tracenumber", "total", "min", "max", "numBlocks"); for (int i = 0; i < numTraces; i++) { AbstractBlockBase[] t = traces.get(i).getBlocks(); @@ -70,14 +70,14 @@ printLine(i, total, min, max, t.length); } } - Debug.log(Debug.VERBOSE_LOG_LEVEL, ""); + Debug.log(Debug.VERBOSE_LEVEL, ""); } - Debug.log(Debug.VERBOSE_LOG_LEVEL, ""); + Debug.log(Debug.VERBOSE_LEVEL, ""); } private static void printRawLine(Object tracenr, Object totalTime, Object minProb, Object maxProb, Object numBlocks) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString())); + Debug.log(Debug.VERBOSE_LEVEL, "%s", String.join(SEP, tracenr.toString(), totalTime.toString(), minProb.toString(), maxProb.toString(), numBlocks.toString())); } private static void printLine(int tracenr, double totalTime, double minProb, double maxProb, int numBlocks) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java Thu Apr 06 14:31:32 2017 -0700 @@ -343,116 +343,7 @@ if (lt instanceof PrimitiveConstant) { PrimitiveConstant lp = (PrimitiveConstant) lt; PrimitiveConstant rp = (PrimitiveConstant) rt; - switch (lp.getJavaKind()) { - case Boolean: - case Byte: - case Char: - case Short: - case Int: { - int x = lp.asInt(); - int y = rp.asInt(); - switch (this) { - case EQ: - return x == y; - case NE: - return x != y; - case LT: - return x < y; - case LE: - return x <= y; - case GT: - return x > y; - case GE: - return x >= y; - case AE: - return UnsignedMath.aboveOrEqual(x, y); - case BE: - return UnsignedMath.belowOrEqual(x, y); - case AT: - return UnsignedMath.aboveThan(x, y); - case BT: - return UnsignedMath.belowThan(x, y); - default: - throw new GraalError("expected condition: %s", this); - } - } - case Long: { - long x = lp.asLong(); - long y = rp.asLong(); - switch (this) { - case EQ: - return x == y; - case NE: - return x != y; - case LT: - return x < y; - case LE: - return x <= y; - case GT: - return x > y; - case GE: - return x >= y; - case AE: - return UnsignedMath.aboveOrEqual(x, y); - case BE: - return UnsignedMath.belowOrEqual(x, y); - case AT: - return UnsignedMath.aboveThan(x, y); - case BT: - return UnsignedMath.belowThan(x, y); - default: - throw new GraalError("expected condition: %s", this); - } - } - case Float: { - float x = lp.asFloat(); - float y = rp.asFloat(); - if (Float.isNaN(x) || Float.isNaN(y)) { - return unorderedIsTrue; - } - switch (this) { - case EQ: - return x == y; - case NE: - return x != y; - case LT: - return x < y; - case LE: - return x <= y; - case GT: - return x > y; - case GE: - return x >= y; - default: - throw new GraalError("expected condition: %s", this); - } - } - case Double: { - double x = lp.asDouble(); - double y = rp.asDouble(); - if (Double.isNaN(x) || Double.isNaN(y)) { - return unorderedIsTrue; - } - switch (this) { - case EQ: - return x == y; - case NE: - return x != y; - case LT: - return x < y; - case LE: - return x <= y; - case GT: - return x > y; - case GE: - return x >= y; - default: - throw new GraalError("expected condition: %s", this); - } - } - default: - throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this); - } + return foldCondition(lp, rp, unorderedIsTrue); } else { Boolean equal = constantReflection.constantEquals(lt, rt); if (equal == null) { @@ -469,6 +360,128 @@ } } + /** + * Attempts to fold a comparison between two primitive constants and return the result. + * + * @param lp the constant on the left side of the comparison + * @param rp the constant on the right side of the comparison + * @param unorderedIsTrue true if an undecided float comparison should result in "true" + * @return true if the comparison is known to be true, false if the comparison is known to be + * false + */ + public boolean foldCondition(PrimitiveConstant lp, PrimitiveConstant rp, boolean unorderedIsTrue) { + switch (lp.getJavaKind()) { + case Boolean: + case Byte: + case Char: + case Short: + case Int: { + int x = lp.asInt(); + int y = rp.asInt(); + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + case AE: + return UnsignedMath.aboveOrEqual(x, y); + case BE: + return UnsignedMath.belowOrEqual(x, y); + case AT: + return UnsignedMath.aboveThan(x, y); + case BT: + return UnsignedMath.belowThan(x, y); + default: + throw new GraalError("expected condition: %s", this); + } + } + case Long: { + long x = lp.asLong(); + long y = rp.asLong(); + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + case AE: + return UnsignedMath.aboveOrEqual(x, y); + case BE: + return UnsignedMath.belowOrEqual(x, y); + case AT: + return UnsignedMath.aboveThan(x, y); + case BT: + return UnsignedMath.belowThan(x, y); + default: + throw new GraalError("expected condition: %s", this); + } + } + case Float: { + float x = lp.asFloat(); + float y = rp.asFloat(); + if (Float.isNaN(x) || Float.isNaN(y)) { + return unorderedIsTrue; + } + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + default: + throw new GraalError("expected condition: %s", this); + } + } + case Double: { + double x = lp.asDouble(); + double y = rp.asDouble(); + if (Double.isNaN(x) || Double.isNaN(y)) { + return unorderedIsTrue; + } + switch (this) { + case EQ: + return x == y; + case NE: + return x != y; + case LT: + return x < y; + case LE: + return x <= y; + case GT: + return x > y; + case GE: + return x >= y; + default: + throw new GraalError("expected condition: %s", this); + } + } + default: + throw new GraalError("expected value kind %s while folding condition: %s", lp.getJavaKind(), this); + } + } + public Condition join(Condition other) { if (other == this) { return this; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Thu Apr 06 14:31:32 2017 -0700 @@ -154,6 +154,7 @@ return Double.isNaN(lowerBound); } + @Override public boolean isUnrestricted() { return lowerBound == Double.NEGATIVE_INFINITY && upperBound == Double.POSITIVE_INFINITY && !nonNaN; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IllegalStamp.java Thu Apr 06 14:31:32 2017 -0700 @@ -59,6 +59,11 @@ } @Override + public boolean isUnrestricted() { + return true; + } + + @Override public Stamp empty() { return this; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Thu Apr 06 14:31:32 2017 -0700 @@ -254,6 +254,7 @@ return upMask; } + @Override public boolean isUnrestricted() { return lowerBound == CodeUtil.minValue(getBits()) && upperBound == CodeUtil.maxValue(getBits()) && downMask == 0 && upMask == CodeUtil.mask(getBits()); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/Stamp.java Thu Apr 06 14:31:32 2017 -0700 @@ -126,6 +126,13 @@ } /** + * Tests whether this stamp represents all values of this kind. + */ + public boolean isUnrestricted() { + return this.equals(this.unrestricted()); + } + + /** * If this stamp represents a single value, the methods returns this single value. It returns * null otherwise. * diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/StampFactory.java Thu Apr 06 14:31:32 2017 -0700 @@ -39,33 +39,6 @@ public class StampFactory { - /* - * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a - * regular ObjectStamp. - */ - static final class NodeIntrinsicStamp extends ObjectStamp { - protected static final Stamp SINGLETON = new NodeIntrinsicStamp(); - - private NodeIntrinsicStamp() { - super(null, false, false, false); - } - - @Override - public int hashCode() { - return System.identityHashCode(this); - } - - @Override - public boolean equals(Object obj) { - return this == obj; - } - - @Override - public String toString() { - return "NodeIntrinsicStamp"; - } - } - // JaCoCo Exclude private static final Stamp[] stampCache = new Stamp[JavaKind.values().length]; @@ -143,14 +116,6 @@ return VoidStamp.getInstance(); } - /** - * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an - * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated. - */ - public static Stamp forNodeIntrinsic() { - return NodeIntrinsicStamp.SINGLETON; - } - public static Stamp intValue() { return forKind(JavaKind.Int); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/VoidStamp.java Thu Apr 06 14:31:32 2017 -0700 @@ -46,6 +46,11 @@ } @Override + public boolean isUnrestricted() { + return true; + } + + @Override public JavaKind getStackKind() { return JavaKind.Void; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -23,10 +23,10 @@ package org.graalvm.compiler.core.common.util; import java.util.ArrayList; -import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.List; -import java.util.Map; + +import org.graalvm.util.EconomicMap; +import org.graalvm.util.Equivalence; /** * Creates an array of T objects order by the occurrence frequency of each object. The most @@ -49,24 +49,24 @@ } } - protected final Map> map; + protected final EconomicMap> map; protected boolean containsNull; /** * Creates an encoder that uses object identity. */ public static FrequencyEncoder createIdentityEncoder() { - return new FrequencyEncoder<>(new IdentityHashMap<>()); + return new FrequencyEncoder<>(EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE)); } /** * Creates an encoder that uses {@link Object#equals(Object) object equality}. */ public static FrequencyEncoder createEqualityEncoder() { - return new FrequencyEncoder<>(new HashMap<>()); + return new FrequencyEncoder<>(EconomicMap.create(Equivalence.DEFAULT)); } - protected FrequencyEncoder(Map> map) { + protected FrequencyEncoder(EconomicMap> map) { this.map = map; } @@ -91,7 +91,7 @@ * Returns the index of an object in the array. The object must have been * {@link #addObject(Object) added} before. */ - public int getIndex(Object object) { + public int getIndex(T object) { if (object == null) { assert containsNull; return 0; @@ -114,7 +114,10 @@ */ public T[] encodeAll(T[] allObjects) { assert allObjects.length == getLength(); - List> sortedEntries = new ArrayList<>(map.values()); + List> sortedEntries = new ArrayList<>(allObjects.length); + for (Entry value : map.getValues()) { + sortedEntries.add(value); + } sortedEntries.sort((e1, e2) -> -Integer.compare(e1.frequency, e2.frequency)); int offset = 0; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCArithmeticLIRGenerator.java Thu Apr 06 14:31:32 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -202,7 +202,7 @@ private Variable emitUnary(Op3s op3, Value input) { Variable result = getLIRGen().newVariable(LIRKind.combine(input)); - getLIRGen().append(SPARCOP3Op.newUnary(op3, input, result)); + getLIRGen().append(SPARCOP3Op.newUnary(op3, getLIRGen().loadSimm13(input), result)); return result; } @@ -227,9 +227,9 @@ private Variable emitBinary(ValueKind resultKind, Op3s op3, Value a, Value b, LIRFrameState state) { Variable result = getLIRGen().newVariable(resultKind); if (op3.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) { - getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), a, result, state)); + getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(b), getLIRGen().loadSimm13(a), result, state)); } else { - getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), b, result, state)); + getLIRGen().append(new SPARCOP3Op(op3, getLIRGen().load(a), getLIRGen().loadSimm13(b), result, state)); } return result; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java Thu Apr 06 14:31:32 2017 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2017, 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 @@ -199,11 +199,11 @@ Condition actualCondition; if (isJavaConstant(x)) { left = load(y); - right = loadNonConst(x); + right = loadSimm13(x); actualCondition = cond.mirror(); } else { left = load(x); - right = loadNonConst(y); + right = loadSimm13(y); actualCondition = cond; } SPARCKind actualCmpKind = (SPARCKind) cmpKind; @@ -250,7 +250,7 @@ return load(value); } - private Value loadSimm13(Value value) { + public Value loadSimm13(Value value) { if (isJavaConstant(value)) { JavaConstant c = asJavaConstant(value); if (c.isNull() || SPARCAssembler.isSimm13(c)) { @@ -261,6 +261,13 @@ } @Override + public Value loadNonConst(Value value) { + // SPARC does not support a proper way of loadNonConst. Please use the appropriate + // loadSimm11 or loadSimm13 variants. + throw GraalError.shouldNotReachHere("This operation is not available for SPARC."); + } + + @Override public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) { // Emit compare SPARCKind cmpSPARCKind = (SPARCKind) cmpKind; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/BoxingEliminationTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,10 +22,6 @@ */ package org.graalvm.compiler.core.test; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - import org.graalvm.compiler.loop.DefaultLoopPolicies; import org.graalvm.compiler.loop.phases.LoopPeelingPhase; import org.graalvm.compiler.nodes.ReturnNode; @@ -37,6 +33,9 @@ import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; /** * In the following tests, the usages of local variable "a" are replaced with the integer constant @@ -162,7 +161,7 @@ sum0 = a; } else { int sum = a; - for (int i = 0; i < n; i++) { + for (int i = 1; i < n; i++) { sum += i; } sum0 = sum; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java Thu Apr 06 14:31:32 2017 -0700 @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2012, 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 org.graalvm.compiler.core.test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.junit.Ignore; +import org.junit.Test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class CompareCanonicalizerTest3 extends GraalCompilerTest { + + @SuppressWarnings("unused") private static int sink0; + @SuppressWarnings("unused") private static int sink1; + + @Test + public void test00() { + assertCanonicallyEqual("integerTestCanonicalization00", "referenceSnippet00"); + } + + public static void integerTestCanonicalization00(char a) { + if (a - 1 < a) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @SuppressWarnings("unused") + public static void referenceSnippet00(char a) { + sink1 = 0; + } + + @Ignore("Needs better stamp support for unsigned ranges") + @Test + public void test01() { + assertCanonicallyEqual("integerTestCanonicalization01", "referenceSnippet01"); + } + + public static void integerTestCanonicalization01(char a) { + if (Integer.compareUnsigned(a - 1, a) < 0) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet01(char a) { + if (a != 0) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Ignore("Needs better stamp support for unsigned ranges") + @Test + public void test1() { + assertCanonicallyEqual("integerTestCanonicalization1", "referenceSnippet1"); + } + + public static void integerTestCanonicalization1(char a) { + if (Integer.compareUnsigned(a - 2, a) < 0) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet1(char a) { + if (Integer.compareUnsigned(a, 2) >= 0) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test2() { + assertCanonicallyEqual("integerTestCanonicalization2", "referenceSnippet2"); + } + + public static void integerTestCanonicalization2(int a) { + if (a - 1 < a) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet2(int a) { + if (a != Integer.MIN_VALUE) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test3() { + assertCanonicallyEqual("integerTestCanonicalization3", "referenceSnippet3"); + } + + public static void integerTestCanonicalization3(int a) { + if (a - 2 < a) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet3(int a) { + if (a >= Integer.MIN_VALUE + 2) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test4() { + assertCanonicallyEqual("integerTestCanonicalization4", "referenceSnippet4"); + } + + public static void integerTestCanonicalization4(int a) { + if (a + 1 < a) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet4(int a) { + if (a == Integer.MAX_VALUE) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test5() { + assertCanonicallyEqual("integerTestCanonicalization5", "referenceSnippet5"); + } + + public static void integerTestCanonicalization5(int a) { + if (a + 2 < a) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet5(int a) { + if (a > Integer.MAX_VALUE - 2) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test6() { + assertCanonicallyEqual("integerTestCanonicalization6", "referenceSnippet6"); + } + + public static void integerTestCanonicalization6(int a) { + if (a < a + 1) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet6(int a) { + if (a != Integer.MAX_VALUE) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + @Test + public void test7() { + assertCanonicallyEqual("integerTestCanonicalization7", "referenceSnippet7"); + } + + public static void integerTestCanonicalization7(int a) { + if (a < a + 2) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + public static void referenceSnippet7(int a) { + if (a <= Integer.MAX_VALUE - 2) { + sink1 = 0; + } else { + sink0 = -1; + } + } + + protected void assertCanonicallyEqual(String snippet, String reference) { + StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); + PhaseContext context = new PhaseContext(getProviders()); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + canonicalizer.apply(graph, context); + StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES); + canonicalizer.apply(referenceGraph, context); + canonicalizer.apply(referenceGraph, context); + assertEquals(referenceGraph, graph, true, true); + } + + @Override + protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method); + } +} diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationMulTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,8 +32,8 @@ public class ConditionalEliminationMulTest extends GraalCompilerTest { public static void snippet01(int a) { - if (a == 2) { - if (a * 3 != 6) { + if (a == 3) { + if (a * 11 != 33) { shouldBeOptimizedAway(); } } @@ -41,7 +41,7 @@ public static void snippet02(int a) { if (a == 0) { - if (a * 3 != 0) { + if (a * 11 != 0) { shouldBeOptimizedAway(); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest1.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,25 +22,25 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.compiler.api.directives.GraalDirectives; import org.junit.Test; -import org.graalvm.compiler.api.directives.GraalDirectives; - /** * Collection of tests for * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those * that triggered bugs in this phase. */ public class ConditionalEliminationTest1 extends ConditionalEliminationTestBase { + protected static int sink3; private static final String REFERENCE_SNIPPET = "referenceSnippet"; @SuppressWarnings("all") - public static int referenceSnippet(int a) { + public static void referenceSnippet(int a) { if (a == 0) { - return 1; + sink1 = 1; } - return 0; + sink0 = 0; } @Test @@ -49,21 +49,21 @@ } @SuppressWarnings("all") - public static int test1Snippet(int a) { + public static void test1Snippet(int a) { if (a == 0) { if (a == 5) { - return 100; + sink2 = 100; } if (a > 100) { if (a == 0) { - return 200; + sink3 = 200; } } if (a != 2) { - return 1; + sink1 = 1; } } - return 0; + sink0 = 0; } @Test @@ -72,18 +72,18 @@ } @SuppressWarnings("all") - public static int test2Snippet(int a) { + public static void test2Snippet(int a) { if (a == 0) { if (a > 100) { if (a == 0) { - return 200; + sink3 = 200; } } if (a != 2) { - return 1; + sink1 = 1; } } - return 0; + sink0 = 0; } @Test @@ -92,7 +92,7 @@ } @SuppressWarnings("all") - public static int test3Snippet(int a) { + public static void test3Snippet(int a) { if (a == 0) { if (a < 1) { if (a < 2) { @@ -101,9 +101,9 @@ if (a > -2) { if (a > -3) { if (a == 1) { - return 42; + sink2 = 42; } else { - return 1; + sink1 = 1; } } } @@ -112,18 +112,18 @@ } } } - return 0; + sink0 = 0; } @SuppressWarnings("all") - public static int test4Snippet(int a, int b) { + public static void test4Snippet(int a, int b) { if (b < 1) { GraalDirectives.controlFlowAnchor(); if (b < 0) { - return 1; + sink1 = 1; } } - return 0; + sink0 = 0; } @Test @@ -132,21 +132,21 @@ } @SuppressWarnings("all") - public static int test5Snippet(int a, int b) { + public static void test5Snippet(int a, int b) { if ((b & 3) == 0) { GraalDirectives.controlFlowAnchor(); if ((b & 7) == 0) { GraalDirectives.controlFlowAnchor(); - return 1; + sink1 = 1; } } else { GraalDirectives.controlFlowAnchor(); if ((b & 1) == 0) { GraalDirectives.controlFlowAnchor(); - return 2; + sink2 = 2; } } - return 0; + sink0 = 0; } @Test diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,22 +22,16 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.compiler.api.directives.GraalDirectives; import org.junit.Ignore; import org.junit.Test; -import org.graalvm.compiler.api.directives.GraalDirectives; - /** * Collection of tests for * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those * that triggered bugs in this phase. */ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase { - public ConditionalEliminationTest11() { - // Don't disable simplification - super(false); - } - @SuppressWarnings("all") public static int referenceSnippet(int a) { if ((a & 15) != 15) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java Thu Apr 06 14:31:32 2017 -0700 @@ -34,13 +34,6 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; public class ConditionalEliminationTest13 extends ConditionalEliminationTestBase { - public ConditionalEliminationTest13() { - super(false); - } - - private static int sink0; - private static int sink1; - private static int sink2; @Override protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { @@ -317,7 +310,7 @@ super.prepareGraph(graph, canonicalizer, context, applyLowering); graph.clearAllStateAfter(); graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After preparation"); + Debug.dump(Debug.BASIC_LEVEL, graph, "After preparation"); canonicalizer.apply(graph, context); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest5.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,11 +22,10 @@ */ package org.graalvm.compiler.core.test; +import org.graalvm.compiler.api.directives.GraalDirectives; import org.junit.Ignore; import org.junit.Test; -import org.graalvm.compiler.api.directives.GraalDirectives; - /** * Collection of tests for * {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those @@ -50,20 +49,20 @@ static final class DistinctB { } - public static int reference1Snippet(Object a) { + public static void reference1Snippet(Object a) { if (a instanceof B) { - return 1; + sink1 = 1; } - return 2; + sink2 = 2; } - public static int test1Snippet(Object a) { + public static void test1Snippet(Object a) { if (a instanceof B) { if (a instanceof A) { - return 1; + sink1 = 1; } } - return 2; + sink2 = 2; } @Test @@ -71,21 +70,21 @@ testConditionalElimination("test1Snippet", "reference1Snippet"); } - public static int reference2Snippet(A a) { + public static void reference2Snippet(A a) { if (a instanceof B) { - return 1; + sink1 = 1; } - return 2; + sink2 = 2; } - public static int test2Snippet(A a) { + public static void test2Snippet(A a) { if (a instanceof B) { B newVal = (B) a; if (newVal != null) { - return 1; + sink1 = 1; } } - return 2; + sink2 = 2; } @Test @@ -94,28 +93,28 @@ } @SuppressWarnings("unused") - public static int reference3Snippet(Object a, Object b) { + public static void reference3Snippet(Object a, Object b) { if (a instanceof DistinctA) { DistinctA proxyA = (DistinctA) a; if (b instanceof DistinctB) { - return 1; + sink1 = 1; } } - return 2; + sink2 = 2; } @SuppressWarnings("all") - public static int test3Snippet(Object a, Object b) { + public static void test3Snippet(Object a, Object b) { if (a instanceof DistinctA) { DistinctA proxyA = (DistinctA) a; if (b instanceof DistinctB) { if (proxyA == b) { - return 42; + sink0 = 42; } - return 1; + sink1 = 1; } } - return 2; + sink2 = 2; } @Test @@ -123,54 +122,54 @@ testConditionalElimination("test3Snippet", "reference3Snippet", true, false); } - public static int reference4Snippet(Object a) { + public static void reference4Snippet(Object a) { if (!(a instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } - public static int test4Snippet1(Object a) { + public static void test4Snippet1(Object a) { if (!(a instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } if (!(a instanceof A)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } - public static int test4Snippet2(Object a) { + public static void test4Snippet2(Object a) { if (!(a instanceof A)) { GraalDirectives.deoptimizeAndInvalidate(); } if (!(a instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } @SuppressWarnings({"cast", "unused"}) - public static int test4Snippet3(Object a) { + public static void test4Snippet3(Object a) { Object pi = (A) a; if (!(a instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } - public static int test4Snippet4(Object a) { + public static void test4Snippet4(Object a) { if (!(a instanceof A)) { GraalDirectives.deoptimizeAndInvalidate(); } if (!(((A) a) instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } @SuppressWarnings({"cast"}) - public static int test4Snippet5(Object a) { + public static void test4Snippet5(Object a) { Object pi = (A) a; if (pi == null) { GraalDirectives.deoptimizeAndInvalidate(); @@ -178,7 +177,7 @@ if (!(a instanceof B)) { GraalDirectives.deoptimizeAndInvalidate(); } - return 1; + sink1 = 1; } @Test diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Thu Apr 06 14:31:32 2017 -0700 @@ -42,15 +42,9 @@ * that triggered bugs in this phase. */ public class ConditionalEliminationTestBase extends GraalCompilerTest { - private final boolean disableSimplification; - - protected ConditionalEliminationTestBase() { - this(true); - } - - protected ConditionalEliminationTestBase(boolean disableSimplification) { - this.disableSimplification = disableSimplification; - } + protected static int sink0; + protected static int sink1; + protected static int sink2; protected void testConditionalElimination(String snippet, String referenceSnippet) { testConditionalElimination(snippet, referenceSnippet, false, false); @@ -59,15 +53,9 @@ @SuppressWarnings("try") protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference, boolean applyLowering) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); PhaseContext context = new PhaseContext(getProviders()); CanonicalizerPhase canonicalizer1 = new CanonicalizerPhase(); - if (disableSimplification) { - /** - * Some tests break if simplification is done so only do it when needed. - */ - canonicalizer1.disableSimplification(); - } CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) { prepareGraph(graph, canonicalizer1, context, applyLowering); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DeMorganCanonicalizationTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.core.test; + +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; +import org.graalvm.compiler.nodes.calc.AndNode; +import org.graalvm.compiler.nodes.calc.NotNode; +import org.graalvm.compiler.nodes.calc.OrNode; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.junit.Assert; +import org.junit.Test; + +public class DeMorganCanonicalizationTest extends GraalCompilerTest { + + public static int or(int a, int b) { + return ~a | ~b; + } + + public static int and(int a, int b) { + return ~a & ~b; + } + + @Test + public void testAnd() { + StructuredGraph g = parseEager("and", AllowAssumptions.NO, getInitialOptions()); + new CanonicalizerPhase().apply(g, getDefaultHighTierContext()); + Assert.assertEquals(1, g.getNodes().filter(OrNode.class).count()); + Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count()); + + testAgainstExpected(g.method(), new Result(and(-1, 17), null), (Object) null, -1, 17); + testAgainstExpected(g.method(), new Result(and(-1, 1), null), (Object) null, -1, 1); + testAgainstExpected(g.method(), new Result(and(-1, -1), null), (Object) null, -1, -1); + testAgainstExpected(g.method(), new Result(and(Integer.MIN_VALUE, Integer.MIN_VALUE), null), (Object) null, Integer.MIN_VALUE, Integer.MIN_VALUE); + } + + @Test + public void testOr() { + StructuredGraph g = parseEager("or", AllowAssumptions.NO, getInitialOptions()); + new CanonicalizerPhase().apply(g, getDefaultHighTierContext()); + Assert.assertEquals(1, g.getNodes().filter(AndNode.class).count()); + Assert.assertEquals(1, g.getNodes().filter(NotNode.class).count()); + + testAgainstExpected(g.method(), new Result(or(-1, 17), null), (Object) null, -1, 17); + testAgainstExpected(g.method(), new Result(or(-1, 1), null), (Object) null, -1, 1); + testAgainstExpected(g.method(), new Result(or(-1, -1), null), (Object) null, -1, -1); + testAgainstExpected(g.method(), new Result(or(Integer.MIN_VALUE, Integer.MIN_VALUE), null), (Object) null, Integer.MIN_VALUE, Integer.MIN_VALUE); + } + +} diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DegeneratedLoopsTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -86,9 +86,9 @@ HighTierContext context = getDefaultHighTierContext(); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); new CanonicalizerPhase().apply(graph, context); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, referenceGraph, "ReferenceGraph"); + Debug.dump(Debug.BASIC_LEVEL, referenceGraph, "ReferenceGraph"); assertEquals(referenceGraph, graph); } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FindUniqueDefaultMethodTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -142,7 +142,7 @@ try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); compile(graph.method(), graph); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + Debug.dump(Debug.BASIC_LEVEL, graph, snippet); return graph; } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FloatingReadTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -82,7 +82,7 @@ } } - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering"); + Debug.dump(Debug.BASIC_LEVEL, graph, "After lowering"); Assert.assertNotNull(returnNode); Assert.assertNotNull(monitorexit); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -78,6 +78,7 @@ import org.graalvm.compiler.nodes.FullInfopointNode; import org.graalvm.compiler.nodes.InvokeNode; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; +import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.ProxyNode; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; @@ -91,6 +92,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.java.AccessFieldNode; import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; @@ -121,6 +123,7 @@ import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.JavaKind; @@ -130,7 +133,6 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.SpeculationLog; -import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.services.Services; /** @@ -410,13 +412,13 @@ String mismatchString = compareGraphStrings(expected, expectedString, graph, actualString); if (!excludeVirtual && getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "Node count not matching - expected"); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Node count not matching - actual"); + Debug.dump(Debug.BASIC_LEVEL, expected, "Node count not matching - expected"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Node count not matching - actual"); Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount() + "\n" + mismatchString); } if (!expectedString.equals(actualString)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "mismatching graphs - expected"); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "mismatching graphs - actual"); + Debug.dump(Debug.BASIC_LEVEL, expected, "mismatching graphs - expected"); + Debug.dump(Debug.BASIC_LEVEL, graph, "mismatching graphs - actual"); Assert.fail(mismatchString); } } @@ -482,22 +484,25 @@ StringBuilder result = new StringBuilder(); for (Block block : scheduleResult.getCFG().getBlocks()) { - result.append("Block " + block + " "); + result.append("Block ").append(block).append(' '); if (block == scheduleResult.getCFG().getStartBlock()) { result.append("* "); } result.append("-> "); for (Block succ : block.getSuccessors()) { - result.append(succ + " "); + result.append(succ).append(' '); } - result.append("\n"); + result.append('\n'); for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { if (node instanceof ValueNode && node.isAlive()) { - if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode)) { + if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode || node instanceof ParameterNode)) { if (node instanceof ConstantNode) { String name = checkConstants ? node.toString(Verbosity.Name) : node.getClass().getSimpleName(); - String str = name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); - constantsLines.add(str); + if (excludeVirtual) { + constantsLines.add(name); + } else { + constantsLines.add(name + " (" + filteredUsageCount(node) + ")"); + } } else { int id; if (canonicalId.get(node) != null) { @@ -507,8 +512,17 @@ canonicalId.set(node, id); } String name = node.getClass().getSimpleName(); - String str = " " + id + "|" + name + (excludeVirtual ? "\n" : " (" + filteredUsageCount(node) + ")\n"); - result.append(str); + result.append(" ").append(id).append('|').append(name); + if (node instanceof AccessFieldNode) { + result.append('#'); + result.append(((AccessFieldNode) node).field()); + } + if (!excludeVirtual) { + result.append(" ("); + result.append(filteredUsageCount(node)); + result.append(')'); + } + result.append('\n'); } } } @@ -516,14 +530,14 @@ } StringBuilder constantsLinesResult = new StringBuilder(); - constantsLinesResult.append(constantsLines.size() + " constants:\n"); + constantsLinesResult.append(constantsLines.size()).append(" constants:\n"); Collections.sort(constantsLines); for (String s : constantsLines) { constantsLinesResult.append(s); - constantsLinesResult.append("\n"); + constantsLinesResult.append('\n'); } - return constantsLines.toString() + result.toString(); + return constantsLinesResult.toString() + result.toString(); } /** @@ -545,15 +559,15 @@ StringBuilder result = new StringBuilder(); Block[] blocks = scheduleResult.getCFG().getBlocks(); for (Block block : blocks) { - result.append("Block " + block + " "); + result.append("Block ").append(block).append(' '); if (block == scheduleResult.getCFG().getStartBlock()) { result.append("* "); } result.append("-> "); for (Block succ : block.getSuccessors()) { - result.append(succ + " "); + result.append(succ).append(' '); } - result.append("\n"); + result.append('\n'); for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { result.append(String.format("%1S\n", node)); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/IfCanonicalizerTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -217,7 +217,7 @@ n.replaceFirstInput(param, constant); } } - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); for (FrameState fs : param.usages().filter(FrameState.class).snapshot()) { fs.replaceFirstInput(param, null); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LockEliminationTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,7 +25,8 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import org.junit.Test; - +import org.graalvm.compiler.loop.DefaultLoopPolicies; +import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.java.MonitorExitNode; @@ -91,6 +92,26 @@ assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count()); } + public void testUnrolledSyncSnippet(Object a) { + for (int i = 0; i < 3; i++) { + synchronized (a) { + + } + } + } + + @Test + public void testUnrolledSync() { + StructuredGraph graph = getGraph("testUnrolledSyncSnippet"); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, new PhaseContext(getProviders())); + HighTierContext context = getDefaultHighTierContext(); + new LoopFullUnrollPhase(canonicalizer, new DefaultLoopPolicies()).apply(graph, context); + new LockEliminationPhase().apply(graph); + assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count()); + assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count()); + } + private StructuredGraph getGraph(String snippet) { ResolvedJavaMethod method = getResolvedJavaMethod(snippet); StructuredGraph graph = parseEager(method, AllowAssumptions.YES); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MemoryScheduleTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -717,7 +717,7 @@ if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) { graph.clearAllStateAfter(); } - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "after removal of framestates"); + Debug.dump(Debug.BASIC_LEVEL, graph, "after removal of framestates"); new FloatingReadPhase().apply(graph); new RemoveValueProxyPhase().apply(graph); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -61,7 +61,7 @@ StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); assertDeepEquals(returnCount, graph.getNodes(ReturnNode.TYPE).count()); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NestedLoopTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -142,7 +142,7 @@ private void test(String snippet, int rootExits, int nestedExits, int innerExits) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); Assert.assertEquals(3, cfg.getLoops().size()); @@ -162,7 +162,7 @@ Assert.assertEquals(rootExits, rootLoop.getExits().size()); Assert.assertEquals(nestedExits, nestedLoop.getExits().size()); Assert.assertEquals(innerExits, innerMostLoop.getExits().size()); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); } private static boolean contains(Loop loop, Invoke node, ControlFlowGraph cfg) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/NodePropertiesTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -58,9 +58,11 @@ x = 2; sideEffect = null; } + int b = 4; sideEffect = null; + int c = b % 5; // can shift - return a * x * 4; + return a * x * c; } public static int test2Snippet(int a) { @@ -249,7 +251,7 @@ gc2.apply(g2, htc); Debug.log("Test Graph Cost --> 1.Graph cost:%f vs. 2.Graph cost:%f\n", gc1.finalCycles, gc2.finalCycles); Assert.assertTrue(gc2.finalCycles > gc1.finalCycles); - Assert.assertTrue(gc2.finalSize == gc1.finalSize + 1/* mul has 3 const input */); + Assert.assertTrue(gc2.finalSize == gc1.finalSize); } @Test diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PhiCreationTests.java Thu Apr 06 14:31:32 2017 -0700 @@ -70,7 +70,7 @@ @Test public void test3() { StructuredGraph graph = parseEager("test3Snippet", AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); } @@ -86,7 +86,7 @@ @Test public void test4() { StructuredGraph graph = parseEager("test4Snippet", AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); Assert.assertFalse(graph.getNodes().filter(ValuePhiNode.class).iterator().hasNext()); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/PushThroughIfTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -59,7 +59,7 @@ private void test(String snippet, String reference) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); for (FrameState fs : graph.getNodes(FrameState.TYPE).snapshot()) { fs.replaceAtUsages(null); GraphUtil.killWithUnusedFloatingInputs(fs); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReadAfterCheckCastTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -94,7 +94,7 @@ new FloatingReadPhase().apply(graph); canonicalizer.apply(graph, context); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After lowering"); + Debug.dump(Debug.BASIC_LEVEL, graph, "After lowering"); for (FloatingReadNode node : graph.getNodes(ParameterNode.TYPE).first().usages().filter(FloatingReadNode.class)) { // Checking that the parameter a is not directly used for the access to field diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ScalarTypeSystemTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -131,7 +131,7 @@ private void test(final String snippet, final String referenceSnippet) { // No debug scope to reduce console noise for @Test(expected = ...) tests StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); PhaseContext context = new PhaseContext(getProviders()); new CanonicalizerPhase().apply(graph, context); StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.NO); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java Thu Apr 06 14:31:32 2017 -0700 @@ -69,7 +69,7 @@ BeginNode beginNode = graph.add(new BeginNode()); returnNode.replaceAtPredecessor(beginNode); beginNode.setNext(returnNode); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST); schedulePhase.apply(graph); ScheduleResult schedule = graph.getLastSchedule(); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SimpleCFGTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -41,7 +41,7 @@ public class SimpleCFGTest extends GraalCompilerTest { private static void dumpGraph(final StructuredGraph graph) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); } @Test diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/StraighteningTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -88,7 +88,7 @@ private void test(final String snippet) { // No debug scope to reduce console noise for @Test(expected = ...) tests StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); StructuredGraph referenceGraph = parseEager(REFERENCE_SNIPPET, AllowAssumptions.YES); assertEquals(referenceGraph, graph); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TypeSystemTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -180,7 +180,7 @@ private void test(String snippet, String referenceSnippet) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); /* * When using FlowSensitiveReductionPhase instead of ConditionalEliminationPhase, * tail-duplication gets activated thus resulting in a graph with more nodes than the @@ -200,8 +200,8 @@ @Override protected void assertEquals(StructuredGraph expected, StructuredGraph graph) { if (getNodeCountExcludingUnusedConstants(expected) != getNodeCountExcludingUnusedConstants(graph)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, expected, "expected (node count)"); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "graph (node count)"); + Debug.dump(Debug.BASIC_LEVEL, expected, "expected (node count)"); + Debug.dump(Debug.BASIC_LEVEL, graph, "graph (node count)"); Assert.fail("Graphs do not have the same number of nodes: " + expected.getNodeCount() + " vs. " + graph.getNodeCount()); } } @@ -244,7 +244,7 @@ StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph " + snippet); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph " + snippet); Assert.assertFalse("shouldn't have nodes of type " + clazz, graph.getNodes().filter(clazz).iterator().hasNext()); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/VerifyDebugUsageTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -83,9 +83,28 @@ @Override protected void run(StructuredGraph graph) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph.toString()); + Debug.dump(Debug.BASIC_LEVEL, graph, "%s", graph.toString()); + } + } + + private static class InvalidDumpLevelPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.dump(Debug.VERY_DETAILED_LEVEL + 1, graph, "%s", graph); + } + } + + private static class NonConstantDumpLevelPhase extends Phase { + + @Override + protected void run(StructuredGraph graph) { + Debug.dump(getLevel(), graph, "%s", graph); } + int getLevel() { + return 10; + } } private static class InvalidVerifyUsagePhase extends Phase { @@ -126,7 +145,7 @@ @Override protected void run(StructuredGraph graph) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "error " + graph); + Debug.dump(Debug.BASIC_LEVEL, graph, "error " + graph); } } @@ -169,7 +188,7 @@ @Override protected void run(StructuredGraph graph) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", graph); + Debug.dump(Debug.BASIC_LEVEL, graph, "%s", graph); } } @@ -234,6 +253,16 @@ } @Test(expected = VerificationError.class) + public void testDumpLevelInvalid() { + testDebugUsageClass(InvalidDumpLevelPhase.class); + } + + @Test(expected = VerificationError.class) + public void testDumpNonConstantLevelInvalid() { + testDebugUsageClass(NonConstantDumpLevelPhase.class); + } + + @Test(expected = VerificationError.class) public void testLogInvalidConcat() { testDebugUsageClass(InvalidConcatLogUsagePhase.class); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -135,6 +135,7 @@ } public static Object[] array = new Object[]{1, 2, 3, 4, 5, "asdf", "asdf"}; + public static char[] charArray = new char[]{1, 2, 3, 4, 5, 'a', 'f'}; public static Object testArrayCopySnippet(int a) { Object[] tmp = new Object[]{a != 1 ? array[a] : null}; @@ -144,6 +145,18 @@ } @Test + public void testPrimitiveArraycopy() { + testPartialEscapeAnalysis("testPrimitiveArraycopySnippet", 0, 0); + } + + public static Object testPrimitiveArraycopySnippet(int a) { + char[] tmp = new char[]{a != 1 ? charArray[a] : 0}; + char[] tmp2 = new char[5]; + System.arraycopy(tmp, 0, tmp2, 4, 1); + return tmp2[4]; + } + + @Test @Ignore public void testCache() { testPartialEscapeAnalysis("testCacheSnippet", 0.75, 1); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/InliningTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -244,10 +244,10 @@ ? getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true)) : getDefaultGraphBuilderSuite(); HighTierContext context = new HighTierContext(getProviders(), graphBuilderSuite, OptimisticOptimizations.ALL); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new CanonicalizerPhase().apply(graph, context); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new CanonicalizerPhase().apply(graph, context); new DeadCodeEliminationPhase().apply(graph); return graph; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -121,7 +121,7 @@ long start = System.currentTimeMillis(); phase.apply(g, context); long end = System.currentTimeMillis(); - Debug.dump(Debug.DETAILED_LOG_LEVEL, g, "After %s", phase.contractorName()); + Debug.dump(Debug.DETAILED_LEVEL, g, "After %s", phase.contractorName()); return end - start; } @@ -138,7 +138,7 @@ next = callerGraph.getNodes(MethodCallTargetNode.TYPE).first().invoke(); EconomicSet canonicalizeNodes = InliningUtil.inlineForCanonicalization(next, calleeGraph, false, calleeMethod); canonicalizer.applyIncremental(callerGraph, context, canonicalizeNodes); - Debug.dump(Debug.DETAILED_LOG_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i); + Debug.dump(Debug.DETAILED_LEVEL, callerGraph, "After inlining %s into %s iteration %d", calleeMethod, callerMethod, i); } return callerGraph; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/GraalTutorial.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,8 @@ import org.junit.Assert; import org.junit.Test; +import java.util.regex.Pattern; + import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeDisassembler; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; @@ -56,7 +58,11 @@ byte[] bytecodes = bytecode.getCode(); Assert.assertNotNull(bytecodes); - System.out.println(new BytecodeDisassembler().disassemble(bytecode)); + Pattern disassemblyLineRE = Pattern.compile(" *\\d+: [a-z][\\w_]+"); + String disassembly = new BytecodeDisassembler().disassemble(bytecode); + for (String line : disassembly.split("\\n")) { + Assert.assertTrue(line, disassemblyLineRE.matcher(line).find()); + } } /* diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Thu Apr 06 14:31:32 2017 -0700 @@ -39,6 +39,7 @@ import org.graalvm.compiler.debug.DebugCounter; import org.graalvm.compiler.debug.DebugTimer; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.debug.MethodFilter; import org.graalvm.compiler.debug.internal.method.MethodMetricsRootScopeInfo; import org.graalvm.compiler.lir.LIR; import org.graalvm.compiler.lir.alloc.OutOfRegistersException; @@ -175,11 +176,43 @@ } catch (Throwable e) { throw Debug.handle(e); } + checkForRequestedCrash(r.graph); return r.compilationResult; } } /** + * Checks whether the {@link GraalCompilerOptions#CrashAt} option indicates that the compilation + * of {@code graph} should result in an exception. + * + * @param graph a graph currently being compiled + * @throws RuntimeException if the value of {@link GraalCompilerOptions#CrashAt} matches + * {@code graph.method()} or {@code graph.name} + */ + private static void checkForRequestedCrash(StructuredGraph graph) { + String methodPattern = GraalCompilerOptions.CrashAt.getValue(graph.getOptions()); + if (methodPattern != null) { + String crashLabel = null; + ResolvedJavaMethod method = graph.method(); + if (method == null) { + if (graph.name.contains(methodPattern)) { + crashLabel = graph.name; + } + } else { + MethodFilter[] filters = MethodFilter.parse(methodPattern); + for (MethodFilter filter : filters) { + if (filter.matches(method)) { + crashLabel = method.format("%H.%n(%p)"); + } + } + } + if (crashLabel != null) { + throw new RuntimeException("Forced crash after compiling " + crashLabel); + } + } + } + + /** * Builds the graph, optimizes it. */ @SuppressWarnings("try") @@ -190,21 +223,25 @@ if (graph.start().next() == null) { graphBuilderSuite.apply(graph, highTierContext); new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph); + Debug.dump(Debug.BASIC_LEVEL, graph, "After parsing"); } else { - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "initial state"); + Debug.dump(Debug.INFO_LEVEL, graph, "initial state"); } suites.getHighTier().apply(graph, highTierContext); graph.maybeCompress(); + Debug.dump(Debug.BASIC_LEVEL, graph, "After high tier"); MidTierContext midTierContext = new MidTierContext(providers, target, optimisticOpts, profilingInfo); suites.getMidTier().apply(graph, midTierContext); graph.maybeCompress(); + Debug.dump(Debug.BASIC_LEVEL, graph, "After mid tier"); LowTierContext lowTierContext = new LowTierContext(providers, target); suites.getLowTier().apply(graph, lowTierContext); + Debug.dump(Debug.BASIC_LEVEL, graph, "After low tier"); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); + Debug.dump(Debug.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); } catch (Throwable e) { throw Debug.handle(e); } finally { @@ -269,7 +306,7 @@ linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); lir = new LIR(schedule.getCFG(), linearScanOrder, codeEmittingOrder, graph.getOptions()); - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After linear scan order"); + Debug.dump(Debug.INFO_LEVEL, lir, "After linear scan order"); } catch (Throwable e) { throw Debug.handle(e); } @@ -283,9 +320,9 @@ new LIRGenerationPhase().apply(backend.getTarget(), lirGenRes, context); try (Scope s = Debug.scope("LIRStages", nodeLirGen, lir)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "After LIR generation"); + Debug.dump(Debug.BASIC_LEVEL, lir, "After LIR generation"); LIRGenerationResult result = emitLowLevel(backend.getTarget(), lirGenRes, lirGen, lirSuites, backend.newRegisterAllocationConfig(registerConfig, allocationRestrictedTo)); - Debug.dump(Debug.BASIC_LOG_LEVEL, lir, "Before code generation"); + Debug.dump(Debug.BASIC_LEVEL, lir, "Before code generation"); return result; } catch (Throwable e) { throw Debug.handle(e); @@ -365,7 +402,7 @@ Debug.counter("ExceptionHandlersEmitted").add(compilationResult.getExceptionHandlers().size()); } - Debug.dump(Debug.BASIC_LOG_LEVEL, compilationResult, "After code generation"); + Debug.dump(Debug.BASIC_LEVEL, compilationResult, "After code generation"); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Thu Apr 06 14:31:32 2017 -0700 @@ -46,6 +46,8 @@ public static final OptionKey ExitVMOnException = new OptionKey<>(false); @Option(help = "", type = OptionType.Debug) public static final OptionKey PrintStackTraceOnException = new OptionKey<>(false); + @Option(help = "Pattern (see MethodFilter for format) for method that will trigger an exception when compiled. " + + "This option exists to test handling compilation crashes gracefully.", type = OptionType.Debug) + public static final OptionKey CrashAt = new OptionKey<>(null); // @formatter:on - } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -91,12 +91,12 @@ listener = new HashSetNodeEventListener(); try (NodeEventScope s = graph.trackNodeEvents(listener)) { try (Scope s2 = Debug.scope("WithGraphChangeMonitoring")) { - if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** Before phase %s", getName()); + if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) { + Debug.dump(Debug.DETAILED_LEVEL, graph, "*** Before phase %s", getName()); } super.run(graph, context); - if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "*** After phase %s %s", getName(), filteredNodes); + if (Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) { + Debug.dump(Debug.DETAILED_LEVEL, graph, "*** After phase %s %s", getName(), filteredNodes); } Debug.log("*** %s %s %s\n", message, graph, filteredNodes); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/Debug.java Thu Apr 06 14:31:32 2017 -0700 @@ -122,11 +122,41 @@ return config.isDumpEnabledForMethod(); } - public static final int BASIC_LOG_LEVEL = 1; - public static final int INFO_LOG_LEVEL = 2; - public static final int VERBOSE_LOG_LEVEL = 3; - public static final int DETAILED_LOG_LEVEL = 4; - public static final int VERY_DETAILED_LOG_LEVEL = 5; + /** + * Basic debug level. + * + * For HIR dumping, only ~5 graphs per method: after parsing, after inlining, after high tier, + * after mid tier, after low tier. + */ + public static final int BASIC_LEVEL = 1; + + /** + * Informational debug level. + * + * HIR dumping: One graph after each applied top-level phase. + */ + public static final int INFO_LEVEL = 2; + + /** + * Verbose debug level. + * + * HIR dumping: One graph after each phase (including sub phases). + */ + public static final int VERBOSE_LEVEL = 3; + + /** + * Detailed debug level. + * + * HIR dumping: Graphs within phases where interesting for a phase, max ~5 per phase. + */ + public static final int DETAILED_LEVEL = 4; + + /** + * Very detailed debug level. + * + * HIR dumping: Graphs per node granularity graph change (before/after change). + */ + public static final int VERY_DETAILED_LEVEL = 5; public static boolean isDumpEnabled(int dumpLevel) { return ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel); @@ -183,7 +213,7 @@ } public static boolean isLogEnabled() { - return isLogEnabled(BASIC_LOG_LEVEL); + return isLogEnabled(BASIC_LEVEL); } public static boolean isLogEnabled(int logLevel) { @@ -420,7 +450,7 @@ } public static void log(String msg) { - log(BASIC_LOG_LEVEL, msg); + log(BASIC_LEVEL, msg); } /** @@ -435,7 +465,7 @@ } public static void log(String format, Object arg) { - log(BASIC_LOG_LEVEL, format, arg); + log(BASIC_LEVEL, format, arg); } /** @@ -451,7 +481,7 @@ } public static void log(String format, int arg) { - log(BASIC_LOG_LEVEL, format, arg); + log(BASIC_LEVEL, format, arg); } /** @@ -467,7 +497,7 @@ } public static void log(String format, Object arg1, Object arg2) { - log(BASIC_LOG_LEVEL, format, arg1, arg2); + log(BASIC_LEVEL, format, arg1, arg2); } /** @@ -480,7 +510,7 @@ } public static void log(String format, int arg1, Object arg2) { - log(BASIC_LOG_LEVEL, format, arg1, arg2); + log(BASIC_LEVEL, format, arg1, arg2); } /** @@ -493,7 +523,7 @@ } public static void log(String format, Object arg1, int arg2) { - log(BASIC_LOG_LEVEL, format, arg1, arg2); + log(BASIC_LEVEL, format, arg1, arg2); } /** @@ -506,7 +536,7 @@ } public static void log(String format, int arg1, int arg2) { - log(BASIC_LOG_LEVEL, format, arg1, arg2); + log(BASIC_LEVEL, format, arg1, arg2); } /** @@ -519,7 +549,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + log(BASIC_LEVEL, format, arg1, arg2, arg3); } /** @@ -532,7 +562,7 @@ } public static void log(String format, int arg1, int arg2, int arg3) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + log(BASIC_LEVEL, format, arg1, arg2, arg3); } /** @@ -545,7 +575,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4); } /** @@ -558,7 +588,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5); } /** @@ -571,7 +601,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); } /** @@ -584,11 +614,11 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } /** @@ -607,7 +637,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9) { @@ -617,7 +647,7 @@ } public static void log(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) { - log(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + log(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } public static void log(int logLevel, String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6, Object arg7, Object arg8, Object arg9, Object arg10) { @@ -627,7 +657,7 @@ } public static void logv(String format, Object... args) { - logv(BASIC_LOG_LEVEL, format, args); + logv(BASIC_LEVEL, format, args); } /** @@ -655,7 +685,7 @@ @Deprecated public static void log(String format, Object[] args) { assert false : "shouldn't use this"; - log(BASIC_LOG_LEVEL, format, args); + log(BASIC_LEVEL, format, args); } /** @@ -670,6 +700,14 @@ logv(logLevel, format, args); } + /** + * Forces an unconditional dump. This method exists mainly for debugging. It can also be used to + * force a graph dump from IDEs that support invoking a Java method while at a breakpoint. + */ + public static void forceDump(Object object, String format, Object... args) { + DebugScope.forceDump(object, format, args); + } + public static void dump(int dumpLevel, Object object, String msg) { if (ENABLED && DebugScope.getInstance().isDumpEnabled(dumpLevel)) { DebugScope.getInstance().dump(dumpLevel, object, msg); @@ -771,7 +809,7 @@ } public static Indent logAndIndent(String msg) { - return logAndIndent(BASIC_LOG_LEVEL, msg); + return logAndIndent(BASIC_LEVEL, msg); } /** @@ -789,7 +827,7 @@ } public static Indent logAndIndent(String format, Object arg) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg); + return logAndIndent(BASIC_LEVEL, format, arg); } /** @@ -808,7 +846,7 @@ } public static Indent logAndIndent(String format, int arg) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg); + return logAndIndent(BASIC_LEVEL, format, arg); } /** @@ -827,7 +865,7 @@ } public static Indent logAndIndent(String format, int arg1, Object arg2) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2); } /** @@ -841,7 +879,7 @@ } public static Indent logAndIndent(String format, Object arg1, int arg2) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2); } /** @@ -855,7 +893,7 @@ } public static Indent logAndIndent(String format, int arg1, int arg2) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2); } /** @@ -869,7 +907,7 @@ } public static Indent logAndIndent(String format, Object arg1, Object arg2) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2); } /** @@ -883,7 +921,7 @@ } public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3); } /** @@ -897,7 +935,7 @@ } public static Indent logAndIndent(String format, int arg1, int arg2, int arg3) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3); } /** @@ -911,7 +949,7 @@ } public static Indent logAndIndent(String format, Object arg1, int arg2, int arg3) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3); } /** @@ -925,7 +963,7 @@ } public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4); } /** @@ -939,7 +977,7 @@ } public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5); } /** @@ -953,7 +991,7 @@ } public static Indent logAndIndent(String format, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, Object arg6) { - return logAndIndent(BASIC_LOG_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); + return logAndIndent(BASIC_LEVEL, format, arg1, arg2, arg3, arg4, arg5, arg6); } /** @@ -1001,7 +1039,7 @@ @Deprecated public static void logAndIndent(String format, Object[] args) { assert false : "shouldn't use this"; - logAndIndent(BASIC_LOG_LEVEL, format, args); + logAndIndent(BASIC_LEVEL, format, args); } /** diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugFilter.java Thu Apr 06 14:31:32 2017 -0700 @@ -41,28 +41,28 @@ * A filter is a list of comma-separated terms of the form {@code [:]}. {@code * } is interpreted as a glob pattern if it contains a "*" or "?" character. Otherwise, it * is interpreted as a substring. If {@code } is empty, it matches every scope. If {@code : - * } is omitted, it defaults to {@link Debug#BASIC_LOG_LEVEL}. The term {@code ~} is - * a shorthand for {@code :0} to disable a debug facility for a pattern. + * } is omitted, it defaults to {@link Debug#BASIC_LEVEL}. The term {@code ~} is a + * shorthand for {@code :0} to disable a debug facility for a pattern. *

* The resulting log level of a scope is determined by the last matching term. If no term * matches, the log level is 0 (disabled). A filter with no terms matches every scope with a log - * level of {@link Debug#BASIC_LOG_LEVEL}. + * level of {@link Debug#BASIC_LEVEL}. * *

Examples of filters

* *
    *
  • (empty string)
    - * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. + * Matches any scope with log level {@link Debug#BASIC_LEVEL}. * *
  • {@code :1}
    * Matches any scope with log level 1. * *
  • {@code *}
    - * Matches any scope with log level {@link Debug#BASIC_LOG_LEVEL}. + * Matches any scope with log level {@link Debug#BASIC_LEVEL}. * *
  • {@code CodeGen,CodeInstall}
    * Matches scopes containing "CodeGen" or "CodeInstall", both with log level - * {@link Debug#BASIC_LOG_LEVEL}. + * {@link Debug#BASIC_LEVEL}. * *
  • {@code CodeGen:2,CodeInstall:1}
    * Matches scopes containing "CodeGen" with log level 2, or "CodeInstall" with log level 1. @@ -74,10 +74,10 @@ * Matches all scopes with log level 1, except those containing "Dead". * *
  • {@code Code*}
    - * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LOG_LEVEL}. + * Matches scopes starting with "Code" with log level {@link Debug#BASIC_LEVEL}. * *
  • {@code Code,~Dead}
    - * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LOG_LEVEL}. + * Matches scopes containing "Code" but not "Dead", with log level {@link Debug#BASIC_LEVEL}. *
*/ final class DebugFilter { @@ -108,7 +108,7 @@ level = 0; } else { pattern = t; - level = Debug.BASIC_LOG_LEVEL; + level = Debug.BASIC_LEVEL; } } else { pattern = t.substring(0, idx); @@ -119,13 +119,13 @@ } catch (NumberFormatException e) { switch (levelString) { case "basic": - level = Debug.BASIC_LOG_LEVEL; + level = Debug.BASIC_LEVEL; break; case "info": - level = Debug.INFO_LOG_LEVEL; + level = Debug.INFO_LEVEL; break; case "verbose": - level = Debug.VERBOSE_LOG_LEVEL; + level = Debug.VERBOSE_LEVEL; break; default: throw new IllegalArgumentException("Unknown dump level: \"" + levelString + "\" expected basic, info, verbose or an integer"); @@ -133,7 +133,7 @@ } } else { - level = Debug.BASIC_LOG_LEVEL; + level = Debug.BASIC_LEVEL; } } @@ -147,7 +147,7 @@ */ public int matchLevel(String input) { if (terms == null) { - return Debug.BASIC_LOG_LEVEL; + return Debug.BASIC_LEVEL; } else { int level = 0; for (Term t : terms) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugRetryableTask.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugRetryableTask.java Thu Apr 06 14:31:32 2017 -0700 @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.debug; + +import org.graalvm.compiler.debug.Debug.Scope; + +/** + * A mechanism for re-executing a task upon failure. + */ +public abstract class DebugRetryableTask extends DelegatingDebugConfig { + + /** + * Calls {@link #run} on this task and if it results in an exception, calls + * {@link #onRetry(Throwable)} and if that returns {@code true}, calls {@link #run}. + */ + @SuppressWarnings("try") + public final T execute() { + try { + return run(null); + } catch (Throwable t) { + if (onRetry(t)) { + try (Scope d = Debug.sandbox("Retrying: " + this, this)) { + return run(t); + } catch (Throwable t2) { + throw Debug.handle(t2); + } + } else { + throw t; + } + } + } + + /** + * Runs this task. + * + * @param failure the cause of the first execution to fail or {@code null} if this is the first + * execution of {@link #run(Throwable)} + */ + protected abstract T run(Throwable failure); + + /** + * Notifies this object that the initial execution failed with exception {@code t} and is about + * to be re-executed. The re-execution will use this object as the active {@link DebugConfig}. + * As such, this method can be overridden to enable more detailed debug facilities. + * + * @param t an exception that terminated the first execution of this task + * @return whether this task should be re-executed. If false, {@code t} will be re-thrown. + */ + protected boolean onRetry(Throwable t) { + return true; + } +} diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GraalDebugConfig.java Thu Apr 06 14:31:32 2017 -0700 @@ -79,7 +79,9 @@ @Option(help = "Write debug values into a file instead of the terminal. " + "If DebugValueSummary is Thread, the thread name will be prepended.", type = OptionType.Debug) public static final OptionKey DebugValueFile = new OptionKey<>(null); - @Option(help = "Send Graal compiler IR to dump handlers on error", type = OptionType.Debug) + @Option(help = "Enable debug output for stub code generation and snippet preparation.", type = OptionType.Debug) + public static final OptionKey DebugStubsAndSnippets = new OptionKey<>(false); + @Option(help = "Send Graal compiler IR to dump handlers on error.", type = OptionType.Debug) public static final OptionKey DumpOnError = new OptionKey<>(false); @Option(help = "Intercept also bailout exceptions", type = OptionType.Debug) public static final OptionKey InterceptBailout = new OptionKey<>(false); @@ -406,7 +408,7 @@ if (e instanceof BailoutException && !Options.InterceptBailout.getValue(options)) { return null; } - Debug.setConfig(Debug.fixedConfig(options, Debug.BASIC_LOG_LEVEL, Debug.BASIC_LOG_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output)); + Debug.setConfig(Debug.fixedConfig(options, Debug.BASIC_LEVEL, Debug.BASIC_LEVEL, false, false, false, false, false, dumpHandlers, verifyHandlers, output)); Debug.log("Exception occurred in scope: %s", Debug.currentScope()); Map firstSeen = new IdentityHashMap<>(); for (Object o : Debug.context()) { @@ -414,7 +416,7 @@ if (!firstSeen.containsKey(o)) { firstSeen.put(o, o); if (Options.DumpOnError.getValue(options) || Options.Dump.getValue(options) != null) { - Debug.dump(Debug.BASIC_LOG_LEVEL, o, "Exception: %s", e); + Debug.dump(Debug.BASIC_LEVEL, o, "Exception: %s", e); } else { Debug.log("Context obj %s", o); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/internal/DebugScope.java Thu Apr 06 14:31:32 2017 -0700 @@ -352,7 +352,7 @@ dumpHandler.dump(object, message); } } else { - TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.Dump=xxx"); + TTY.println("Forced dump ignored because debugging is disabled - use -Dgraal.ForceDebugEnable=true"); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Thu Apr 06 14:31:32 2017 -0700 @@ -405,6 +405,13 @@ return add(node); } + public T maybeAddOrUnique(T node) { + if (node.isAlive()) { + return node; + } + return addOrUnique(node); + } + public T addOrUniqueWithInputs(T node) { if (node.isAlive()) { assert node.graph() == this; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Thu Apr 06 14:31:32 2017 -0700 @@ -40,6 +40,8 @@ import java.util.function.Predicate; import org.graalvm.compiler.core.common.Fields; +import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.Fingerprint; import org.graalvm.compiler.graph.Graph.NodeEvent; @@ -131,7 +133,9 @@ * Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If * the constructor is called as part of node intrinsification, the node intrinsifier will inject * an argument for the annotated parameter. Injected parameters must precede all non-injected - * parameters in a constructor. + * parameters in a constructor. If the type of the annotated parameter is {@link Stamp}, the + * {@linkplain Stamp#javaType type} of the injected stamp is the return type of the annotated + * method (which cannot be {@code void}). */ @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) @java.lang.annotation.Target(ElementType.PARAMETER) @@ -140,40 +144,45 @@ /** * Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the - * annotated method can be replaced with an instance of the node class denoted by - * {@link #value()}. For this reason, the signature of the annotated method must match the - * signature (excluding a prefix of {@linkplain InjectedNodeParameter injected} parameters) of a - * constructor in the node class. + * annotated method will be processed by a generated {@code InvocationPlugin} that calls either + * a factory method or a constructor corresponding with the annotated method. *

- * If the node class has a static method {@code intrinsify} with a matching signature plus a - * {@code GraphBuilderContext} as first argument, this method is called instead of creating the - * node. + * A factory method corresponding to an annotated method is a static method named + * {@code intrinsify} defined in the class denoted by {@link #value()}. In order, its signature + * is as follows: + *

    + *
  1. A {@code GraphBuilderContext} parameter.
  2. + *
  3. A {@code ResolvedJavaMethod} parameter.
  4. + *
  5. A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.
  6. + *
  7. Remaining parameters that match the declared parameters of the annotated method.
  8. + *
+ * A constructor corresponding to an annotated method is defined in the class denoted by + * {@link #value()}. In order, its signature is as follows: + *
    + *
  1. A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.
  2. + *
  3. Remaining parameters that match the declared parameters of the annotated method.
  4. + *
+ * There must be exactly one such factory method or constructor corresponding to a + * {@link NodeIntrinsic} annotated method. */ @java.lang.annotation.Retention(RetentionPolicy.RUNTIME) @java.lang.annotation.Target(ElementType.METHOD) public static @interface NodeIntrinsic { /** - * Gets the {@link Node} subclass instantiated when intrinsifying a call to the annotated - * method. If not specified, then the class in which the annotated method is declared is - * used (and is assumed to be a {@link Node} subclass). + * The class declaring the factory method or {@link Node} subclass declaring the constructor + * used to intrinsify a call to the annotated method. The default value is the class in + * which the annotated method is declared. */ Class value() default NodeIntrinsic.class; /** - * Determines if the stamp of the instantiated intrinsic node has its stamp set from the - * return type of the annotated method. - *

- * When it is set to true, the stamp that is passed in to the constructor of ValueNode is - * ignored and can therefore safely be {@code null}. + * If {@code true}, the factory method or constructor selected by the annotation must have + * an {@linkplain InjectedNodeParameter injected} {@link Stamp} parameter. Calling + * {@link AbstractPointerStamp#nonNull()} on the injected stamp is guaranteed to return + * {@code true}. */ - boolean setStampFromReturnType() default false; - - /** - * Determines if the stamp of the instantiated intrinsic node is guaranteed to be non-null. - * Generally used in conjunction with {@link #setStampFromReturnType()}. - */ - boolean returnStampIsNonNull() default false; + boolean injectedStampIsNonNull() default false; } /** @@ -304,7 +313,7 @@ * @return an {@link NodeIterable iterable} for all non-null successor edges. */ public NodeIterable successors() { - assert !this.isDeleted(); + assert !this.isDeleted() : this; return nodeClass.getSuccessorIterable(this); } @@ -328,7 +337,7 @@ if (usage1 == null) { return 1; } - return 2 + extraUsagesCount; + return INLINE_USAGE_COUNT + extraUsagesCount; } /** @@ -391,30 +400,45 @@ } private void movUsageFromEndTo(int destIndex) { - int lastIndex = this.getUsageCount() - 1; - if (destIndex == 0) { - if (lastIndex == 0) { - usage0 = null; - return; - } else if (lastIndex == 1) { - usage0 = usage1; - usage1 = null; - return; - } else { - usage0 = extraUsages[lastIndex - INLINE_USAGE_COUNT]; - } + if (destIndex >= INLINE_USAGE_COUNT) { + movUsageFromEndToExtraUsages(destIndex - INLINE_USAGE_COUNT); } else if (destIndex == 1) { - if (lastIndex == 1) { - usage1 = null; - return; - } - usage1 = extraUsages[lastIndex - INLINE_USAGE_COUNT]; + movUsageFromEndToIndexOne(); } else { - Node n = extraUsages[lastIndex - INLINE_USAGE_COUNT]; - extraUsages[destIndex - INLINE_USAGE_COUNT] = n; + assert destIndex == 0; + movUsageFromEndToIndexZero(); } - extraUsages[lastIndex - INLINE_USAGE_COUNT] = null; + } + + private void movUsageFromEndToExtraUsages(int destExtraIndex) { this.extraUsagesCount--; + Node n = extraUsages[extraUsagesCount]; + extraUsages[destExtraIndex] = n; + extraUsages[extraUsagesCount] = null; + } + + private void movUsageFromEndToIndexZero() { + if (extraUsagesCount > 0) { + this.extraUsagesCount--; + usage0 = extraUsages[extraUsagesCount]; + extraUsages[extraUsagesCount] = null; + } else if (usage1 != null) { + usage0 = usage1; + usage1 = null; + } else { + usage0 = null; + } + } + + private void movUsageFromEndToIndexOne() { + if (extraUsagesCount > 0) { + this.extraUsagesCount--; + usage1 = extraUsages[extraUsagesCount]; + extraUsages[extraUsagesCount] = null; + } else { + assert usage1 != null; + usage1 = null; + } } /** @@ -425,20 +449,21 @@ */ public boolean removeUsage(Node node) { assert node != null; - // It is critical that this method maintains the invariant that - // the usage list has no null element preceding a non-null element + // For large graphs, usage removal is performance critical. + // Furthermore, it is critical that this method maintains the invariant that the usage list + // has no null element preceding a non-null element. incUsageModCount(); if (usage0 == node) { - this.movUsageFromEndTo(0); + movUsageFromEndToIndexZero(); return true; } if (usage1 == node) { - this.movUsageFromEndTo(1); + movUsageFromEndToIndexOne(); return true; } for (int i = this.extraUsagesCount - 1; i >= 0; i--) { if (extraUsages[i] == node) { - this.movUsageFromEndTo(i + INLINE_USAGE_COUNT); + movUsageFromEndToExtraUsages(i); return true; } } @@ -537,8 +562,9 @@ assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id); this.graph = newGraph; newGraph.register(this); - this.getNodeClass().registerAtInputsAsUsage(this); - this.getNodeClass().registerAtSuccessorsAsPredecessor(this); + NodeClass nc = nodeClass; + nc.registerAtInputsAsUsage(this); + nc.registerAtSuccessorsAsPredecessor(this); } /** @@ -588,7 +614,7 @@ } public final void replaceAtUsages(Node other) { - replaceAtUsages(other, null, null); + replaceAtAllUsages(other, (Node) null); } public final void replaceAtUsages(Node other, Predicate filter) { @@ -606,22 +632,60 @@ } protected void replaceAtUsages(Node other, Predicate filter, Node toBeDeleted) { + if (filter == null) { + replaceAtAllUsages(other, toBeDeleted); + } else { + replaceAtMatchingUsages(other, filter, toBeDeleted); + } + } + + protected void replaceAtAllUsages(Node other, Node toBeDeleted) { + assert checkReplaceWith(other); + if (usage0 == null) { + return; + } + replaceAtUsage(other, toBeDeleted, usage0); + usage0 = null; + + if (usage1 == null) { + return; + } + replaceAtUsage(other, toBeDeleted, usage1); + usage1 = null; + + if (extraUsagesCount <= 0) { + return; + } + for (int i = 0; i < extraUsagesCount; i++) { + Node usage = extraUsages[i]; + replaceAtUsage(other, toBeDeleted, usage); + } + this.extraUsages = NO_NODES; + this.extraUsagesCount = 0; + } + + private void replaceAtUsage(Node other, Node toBeDeleted, Node usage) { + boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); + assert assertTrue(result, "not found in inputs, usage: %s", usage); + /* + * Don't notify for nodes which are about to be deleted. + */ + if (toBeDeleted == null || usage != toBeDeleted) { + maybeNotifyInputChanged(usage); + } + if (other != null) { + other.addUsage(usage); + } + } + + private void replaceAtMatchingUsages(Node other, Predicate filter, Node toBeDeleted) { + assert filter != null; assert checkReplaceWith(other); int i = 0; while (i < this.getUsageCount()) { Node usage = this.getUsageAt(i); if (filter == null || filter.test(usage)) { - boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); - assert assertTrue(result, "not found in inputs, usage: %s", usage); - /* - * Don't notify for nodes which are about to be deleted. - */ - if (toBeDeleted == null || usage != toBeDeleted) { - maybeNotifyInputChanged(usage); - } - if (other != null) { - other.addUsage(usage); - } + replaceAtUsage(other, toBeDeleted, usage); this.movUsageFromEndTo(i); } else { ++i; @@ -641,21 +705,7 @@ public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) { assert checkReplaceWith(other); - int index = 0; - while (index < this.getUsageCount()) { - Node usage = getUsageAt(index); - if (usagePredicate.apply(usage)) { - boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other); - assert assertTrue(result, "not found in inputs, usage: %s", usage); - if (other != null) { - maybeNotifyInputChanged(usage); - other.addUsage(usage); - } - this.movUsageFromEndTo(index); - } else { - index++; - } - } + replaceAtMatchingUsages(other, usagePredicate, null); } public void replaceAtUsages(InputType type, Node other) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java Thu Apr 06 14:31:32 2017 -0700 @@ -154,7 +154,7 @@ if (bits.length < other.bits.length) { bits = Arrays.copyOf(bits, other.bits.length); } - for (int i = 0; i < bits.length; i++) { + for (int i = 0; i < Math.min(bits.length, other.bits.length); i++) { bits[i] |= other.bits[i]; } } @@ -181,44 +181,47 @@ } } - private static class MarkedNodeIterator implements Iterator { + protected int nextMarkedNodeId(int fromNodeId) { + assert fromNodeId >= 0; + int wordIndex = fromNodeId >> SHIFT; + int wordsInUse = bits.length; + if (wordIndex < wordsInUse) { + long word = bits[wordIndex] & (0xFFFFFFFFFFFFFFFFL << fromNodeId); + while (true) { + if (word != 0) { + return wordIndex * Long.SIZE + Long.numberOfTrailingZeros(word); + } + if (++wordIndex == wordsInUse) { + break; + } + word = bits[wordIndex]; + } + } + return -2; + } - private final NodeBitMap visited; - private Iterator nodes; - private Node nextNode; + private class MarkedNodeIterator implements Iterator { + private int nextNodeId; - MarkedNodeIterator(NodeBitMap visited, Iterator nodes) { - this.visited = visited; - this.nodes = nodes; + MarkedNodeIterator() { + nextNodeId = -1; forward(); } private void forward() { - do { - if (!nodes.hasNext()) { - nextNode = null; - return; - } - nextNode = nodes.next(); - if (visited.isNew(nextNode)) { - nextNode = null; - return; - } - } while (!visited.isMarked(nextNode)); + nextNodeId = NodeBitMap.this.nextMarkedNodeId(nextNodeId + 1); } @Override public boolean hasNext() { - return nextNode != null; + return nextNodeId >= 0; } @Override public Node next() { - try { - return nextNode; - } finally { - forward(); - } + Node result = graph.getNode(nextNodeId); + forward(); + return result; } @Override @@ -230,7 +233,7 @@ @Override public Iterator iterator() { - return new MarkedNodeIterator(NodeBitMap.this, graph().getNodes().iterator()); + return new MarkedNodeIterator(); } public NodeBitMap copy() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Thu Apr 06 14:31:32 2017 -0700 @@ -599,23 +599,24 @@ } private static boolean deepEquals0(Object e1, Object e2) { - assert e1 != null; - if (e2 == null) { + if (e1 == e2) { + return true; + } else if (e1 == null || e2 == null) { return false; - } else if (e1 instanceof Object[] && e2 instanceof Object[]) { - return Arrays.deepEquals((Object[]) e1, (Object[]) e2); } else if (!e1.getClass().isArray() || e1.getClass() != e2.getClass()) { return e1.equals(e2); - } else if (e1 instanceof byte[]) { - return Arrays.equals((byte[]) e1, (byte[]) e2); - } else if (e1 instanceof short[]) { - return Arrays.equals((short[]) e1, (short[]) e2); + } else if (e1 instanceof Object[] && e2 instanceof Object[]) { + return deepEquals((Object[]) e1, (Object[]) e2); } else if (e1 instanceof int[]) { return Arrays.equals((int[]) e1, (int[]) e2); } else if (e1 instanceof long[]) { return Arrays.equals((long[]) e1, (long[]) e2); + } else if (e1 instanceof byte[]) { + return Arrays.equals((byte[]) e1, (byte[]) e2); } else if (e1 instanceof char[]) { return Arrays.equals((char[]) e1, (char[]) e2); + } else if (e1 instanceof short[]) { + return Arrays.equals((short[]) e1, (short[]) e2); } else if (e1 instanceof float[]) { return Arrays.equals((float[]) e1, (float[]) e2); } else if (e1 instanceof double[]) { @@ -627,6 +628,20 @@ } } + private static boolean deepEquals(Object[] a1, Object[] a2) { + int length = a1.length; + if (a2.length != length) { + return false; + } + + for (int i = 0; i < length; i++) { + if (!deepEquals0(a1[i], a2[i])) { + return false; + } + } + return true; + } + public boolean dataEquals(Node a, Node b) { assert a.getClass() == b.getClass(); for (int i = 0; i < data.getCount(); ++i) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java Thu Apr 06 14:31:32 2017 -0700 @@ -23,14 +23,17 @@ package org.graalvm.compiler.graph; public final class NodeStack { - - private static final int INITIAL_SIZE = 8; + private static final int DEFAULT_INITIAL_SIZE = 8; protected Node[] values; public int tos; public NodeStack() { - values = new Node[INITIAL_SIZE]; + this(DEFAULT_INITIAL_SIZE); + } + + public NodeStack(int initialSize) { + values = new Node[initialSize]; } public int size() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeWorkList.java Thu Apr 06 14:31:32 2017 -0700 @@ -27,7 +27,7 @@ import java.util.NoSuchElementException; import java.util.Queue; -import org.graalvm.compiler.core.common.PermanentBailoutException; +import org.graalvm.compiler.debug.Debug; public abstract class NodeWorkList implements Iterable { @@ -72,26 +72,19 @@ } public static final class IterativeNodeWorkList extends NodeWorkList { - private static final int HARD_ITERATION_LIMIT = 1_000_000; private static final int EXPLICIT_BITMAP_THRESHOLD = 10; protected NodeBitMap inQueue; private int iterationLimit; - private boolean hardLimit; private Node firstNoChange; private Node lastPull; private Node lastChain; public IterativeNodeWorkList(Graph graph, boolean fill, int iterationLimitPerNode) { super(graph, fill); - if (iterationLimitPerNode > 0) { - long limit = (long) iterationLimitPerNode * graph.getNodeCount(); - iterationLimit = (int) Long.min(Integer.MAX_VALUE, limit); - hardLimit = false; - } else { - iterationLimit = HARD_ITERATION_LIMIT; - hardLimit = true; - } + assert iterationLimitPerNode > 0; + long limit = (long) iterationLimitPerNode * graph.getNodeCount(); + iterationLimit = (int) Long.min(Integer.MAX_VALUE, limit); } @Override @@ -101,11 +94,8 @@ public boolean hasNext() { dropDeleted(); if (iterationLimit <= 0) { - if (hardLimit) { - throw new PermanentBailoutException("Iteration limit reached"); - } else { - return false; - } + Debug.log(Debug.INFO_LEVEL, "Exceeded iteration limit in IterativeNodeWorkList"); + return false; } return !worklist.isEmpty(); } @@ -152,7 +142,7 @@ } } } - assert checkInfiniteWork(node) : "Readded " + node; + assert checkInfiniteWork(node) : "Re-added " + node; if (inQueue != null) { inQueue.markAndGrow(node); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicate.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,13 +22,20 @@ */ package org.graalvm.compiler.graph.iterators; +import java.util.function.Predicate; + import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.iterators.NodePredicates.AndPredicate; -public interface NodePredicate { +public interface NodePredicate extends Predicate { boolean apply(Node n); + @Override + default boolean test(Node n) { + return apply(n); + } + default NodePredicate and(NodePredicate np) { return new AndPredicate(this, np); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/iterators/NodePredicates.java Thu Apr 06 14:31:32 2017 -0700 @@ -105,6 +105,7 @@ return !a.apply(n); } + @Override public NodePredicate negate() { return a; } @@ -148,6 +149,7 @@ return this; } + @Override public NodePredicate negate() { return new NegativeTypePredicate(this); } @@ -183,6 +185,7 @@ return this; } + @Override public NodePredicate negate() { return new PositiveTypePredicate(this); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Thu Apr 06 14:31:32 2017 -0700 @@ -557,7 +557,7 @@ LIR lir = getResult().getLIR(); ArrayList instructions = lir.getLIRforBlock(lir.getControlFlowGraph().getStartBlock()); instructions.add(1, op); - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "created rescue dummy op"); + Debug.dump(Debug.INFO_LEVEL, lir, "created rescue dummy op"); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ClassSubstitutionsTests.java Thu Apr 06 14:31:32 2017 -0700 @@ -48,7 +48,7 @@ StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); compile(graph.method(), graph); assertNotInGraph(graph, Invoke.class); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + Debug.dump(Debug.BASIC_LEVEL, graph, snippet); return graph; } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -47,7 +47,7 @@ System.setProperty(CompileTheWorld.LIMITMODS_PROPERTY_NAME, "java.base"); OptionValues initialOptions = getInitialOptions(); EconomicMap, Object> compilationOptions = CompileTheWorld.parseOptions("Inline=false"); - new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, 1, 5, null, null, true, initialOptions, compilationOptions).compile(); + new CompileTheWorld(runtime, (HotSpotGraalCompiler) runtime.getCompiler(), CompileTheWorld.SUN_BOOT_CLASS_PATH, 1, 5, null, null, false, initialOptions, compilationOptions).compile(); assert ExitVMOnException.getValue(initialOptions) == originalSetting; } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java Thu Apr 06 14:31:32 2017 -0700 @@ -57,7 +57,7 @@ StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); compile(graph.method(), graph); assertNotInGraph(graph, Invoke.class); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + Debug.dump(Debug.BASIC_LEVEL, graph, snippet); return graph; } catch (Throwable e) { throw Debug.handle(e); @@ -117,59 +117,32 @@ } } - /** - * Disables these tests until we know how to dynamically export the {@code jdk.internal.reflect} - * package from the {@code java.base} module to the unnamed module associated with - * {@link AsmLoader}. Without such an export, the test fails as follows: - * - *

-     * Caused by: java.lang.IllegalAccessError: class org.graalvm.compiler.hotspot.test.ConstantPoolTest
-     * (in unnamed module @0x57599b23) cannot access class jdk.internal.reflect.ConstantPool (in
-     * module java.base) because module java.base does not export jdk.internal.reflect to unnamed
-     * module @0x57599b23
-     * 
- */ - private static void assumeJDK8() { - // Assume.assumeTrue(Java8OrEarlier); - } - @Test public void testGetSize() { - assumeJDK8(); Object cp = getConstantPoolForObject(); test("getSize", cp); } @Test public void testGetIntAt() { - assumeJDK8(); test("getIntAt"); } @Test public void testGetLongAt() { - assumeJDK8(); test("getLongAt"); } @Test public void testGetFloatAt() { - assumeJDK8(); test("getFloatAt"); } @Test public void testGetDoubleAt() { - assumeJDK8(); test("getDoubleAt"); } - // @Test - public void testGetUTF8At() { - assumeJDK8(); - test("getUTF8At"); - } - private static final String PACKAGE_NAME = ConstantPoolSubstitutionsTests.class.getPackage().getName(); private static final String PACKAGE_NAME_INTERNAL = PACKAGE_NAME.replace('.', '/'); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -53,6 +53,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.VirtualObject; import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.common.JVMCIError; @@ -140,8 +141,9 @@ graph.addAfterFixed(graph.start(), test); CompilationResult compResult = compile(method, graph); - HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(method, null, compResult); - getCodeCache().addCode(method, compiledCode, null, null); + CodeCacheProvider codeCache = getCodeCache(); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, method, null, compResult); + codeCache.addCode(method, compiledCode, null, null); } @Test(expected = JVMCIError.class) diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/LoadJavaMirrorWithKlassTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -58,7 +58,11 @@ @Override @SuppressWarnings("try") protected Suites createSuites(OptionValues options) { - return super.createSuites(new OptionValues(options, GraalOptions.ImmutableCode, true)); + return super.createSuites(getOptions()); + } + + private static OptionValues getOptions() { + return new OptionValues(getInitialOptions(), GraalOptions.ImmutableCode, true); } @Override @@ -77,7 +81,7 @@ @Test public void testClassConstant() { - test("classConstant"); + test(getOptions(), "classConstant"); } public static Class primitiveClassConstant() { @@ -86,7 +90,7 @@ @Test public void testPrimitiveClassConstant() { - test("primitiveClassConstant"); + test(getOptions(), "primitiveClassConstant"); } public static Wrapper compressedClassConstant(Wrapper w) { @@ -97,7 +101,7 @@ @Test public void testCompressedClassConstant() { ArgSupplier arg = () -> new Wrapper(); - test("compressedClassConstant", arg); + test(getOptions(), "compressedClassConstant", arg); } public static Wrapper compressedPrimitiveClassConstant(Wrapper w) { @@ -108,6 +112,6 @@ @Test public void testCompressedPrimitiveClassConstant() { ArgSupplier arg = () -> new Wrapper(); - test("compressedPrimitiveClassConstant", arg); + test(getOptions(), "compressedPrimitiveClassConstant", arg); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/RetryableCompilationTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.hotspot.test; + +import static org.graalvm.compiler.test.SubprocessUtil.formatExecutedCommand; +import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; +import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.hotspot.CompilationTask; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests {@link CompilationTask} support for dumping graphs and other info useful for debugging a + * compiler crash. + */ +public class RetryableCompilationTest extends GraalCompilerTest { + @Test + public void test() throws IOException { + List args = withoutDebuggerArguments(getVMCommandLine()); + + args.add("-XX:+BootstrapJVMCI"); + args.add("-XX:+UseJVMCICompiler"); + args.add("-Dgraal.CrashAt=Object.*,String.*"); + args.add("-version"); + + ProcessBuilder processBuilder = new ProcessBuilder(args); + processBuilder.redirectErrorStream(true); + Process process = processBuilder.start(); + BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String forcedCrashString = "Forced crash after compiling"; + String diagnosticOutputFilePrefix = "Graal diagnostic output saved in "; + + boolean seenForcedCrashString = false; + String diagnosticOutputZip = null; + + List outputLines = new ArrayList<>(); + + String line; + while ((line = stdout.readLine()) != null) { + outputLines.add(line); + if (line.contains(forcedCrashString)) { + seenForcedCrashString = true; + } else if (diagnosticOutputZip == null) { + int index = line.indexOf(diagnosticOutputFilePrefix); + if (index != -1) { + diagnosticOutputZip = line.substring(diagnosticOutputFilePrefix.length()).trim(); + } + } + } + String dashes = "-------------------------------------------------------"; + if (!seenForcedCrashString) { + Assert.fail(String.format("Did not find '%s' in output of command:%n%s", forcedCrashString, formatExecutedCommand(args, outputLines, dashes, dashes))); + } + if (diagnosticOutputZip == null) { + Assert.fail(String.format("Did not find '%s' in output of command:%n%s", diagnosticOutputFilePrefix, formatExecutedCommand(args, outputLines, dashes, dashes))); + } + + File zip = new File(diagnosticOutputZip).getAbsoluteFile(); + Assert.assertTrue(zip.toString(), zip.exists()); + try { + int bgv = 0; + int cfg = 0; + ZipFile dd = new ZipFile(diagnosticOutputZip); + List entries = new ArrayList<>(); + for (Enumeration e = dd.entries(); e.hasMoreElements();) { + ZipEntry ze = e.nextElement(); + String name = ze.getName(); + entries.add(name); + if (name.endsWith(".bgv")) { + bgv++; + } else if (name.endsWith(".cfg")) { + cfg++; + } + } + if (bgv == 0) { + Assert.fail(String.format("Expected at least one .bgv file in %s: %s", diagnosticOutputZip, entries)); + } + if (cfg == 0) { + Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries)); + } + } finally { + zip.delete(); + } + } +} diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierAdditionTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -266,7 +266,7 @@ new GuardLoweringPhase().apply(graph, midContext); new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext); new WriteBarrierAdditionPhase(config).apply(graph); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After Write Barrier Addition"); + Debug.dump(Debug.BASIC_LEVEL, graph, "After Write Barrier Addition"); int barriers = 0; if (config.useG1GC) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java Thu Apr 06 14:31:32 2017 -0700 @@ -30,7 +30,20 @@ import static org.graalvm.compiler.core.GraalCompilerOptions.PrintFilter; import static org.graalvm.compiler.core.GraalCompilerOptions.PrintStackTraceOnException; import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; +import static org.graalvm.compiler.debug.Debug.INFO_LEVEL; +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.DUMP_METHOD; +import static org.graalvm.compiler.debug.DelegatingDebugConfig.Level.DUMP; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Dump; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DumpPath; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.ForceDebugEnable; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintCFGFileName; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFile; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.PrintGraphFileName; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import org.graalvm.compiler.code.CompilationResult; @@ -38,7 +51,9 @@ import org.graalvm.compiler.debug.Debug.Scope; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugCounter; +import org.graalvm.compiler.debug.DebugDumpHandler; import org.graalvm.compiler.debug.DebugDumpScope; +import org.graalvm.compiler.debug.DebugRetryableTask; import org.graalvm.compiler.debug.DebugTimer; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.Management; @@ -46,6 +61,7 @@ import org.graalvm.compiler.debug.TimeSource; import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.printer.GraalDebugConfigCustomizer; import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.BailoutException; @@ -96,6 +112,136 @@ private final boolean useProfilingInfo; private final OptionValues options; + final class RetryableCompilation extends DebugRetryableTask { + private final EventProvider.CompilationEvent compilationEvent; + CompilationResult result; + + RetryableCompilation(EventProvider.CompilationEvent compilationEvent) { + this.compilationEvent = compilationEvent; + } + + @SuppressWarnings("try") + @Override + protected HotSpotCompilationRequestResult run(Throwable retryCause) { + HotSpotResolvedJavaMethod method = getMethod(); + int entryBCI = getEntryBCI(); + final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; + CompilationStatistics stats = CompilationStatistics.create(options, method, isOSR); + final boolean printCompilation = PrintCompilation.getValue(options) && !TTY.isSuppressed(); + final boolean printAfterCompilation = PrintAfterCompilation.getValue(options) && !TTY.isSuppressed(); + if (printCompilation) { + TTY.println(getMethodDescription() + "..."); + } + + TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(options), method); + final long start; + final long allocatedBytesBefore; + if (printAfterCompilation || printCompilation) { + final long threadId = Thread.currentThread().getId(); + start = TimeSource.getTimeNS(); + allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L; + } else { + start = 0L; + allocatedBytesBefore = 0L; + } + + try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) { + // Begin the compilation event. + compilationEvent.begin(); + result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options); + } catch (Throwable e) { + throw Debug.handle(e); + } finally { + // End the compilation event. + compilationEvent.end(); + + filter.remove(); + + if (printAfterCompilation || printCompilation) { + final long threadId = Thread.currentThread().getId(); + final long stop = TimeSource.getTimeNS(); + final long duration = (stop - start) / 1000000; + final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; + final int bytecodeSize = result != null ? result.getBytecodeSize() : 0; + final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId); + final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; + + if (printAfterCompilation) { + TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + } else if (printCompilation) { + TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); + } + } + } + + if (result != null) { + try (DebugCloseable b = CodeInstallationTime.start()) { + installMethod(result); + } + } + stats.finish(method, installedCode); + if (result != null) { + return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize()); + } + return null; + } + + @Override + protected boolean onRetry(Throwable t) { + if (t instanceof BailoutException) { + return false; + } + + if (!Debug.isEnabled()) { + TTY.printf("Error while processing %s.%nRe-run with -D%s%s=true to capture graph dumps upon a compilation failure.%n", CompilationTask.this, + HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX, ForceDebugEnable.getName()); + return false; + } + + if (Dump.hasBeenSet(options)) { + // If dumping is explicitly enabled, Graal is being debugged + // so don't interfere with what the user is expecting to see. + return false; + } + + String outputDirectory = compiler.getGraalRuntime().getOutputDirectory(); + if (outputDirectory == null) { + return false; + } + String methodFQN = getMethod().format("%H.%n"); + File dumpPath = new File(outputDirectory, methodFQN); + dumpPath.mkdirs(); + if (!dumpPath.exists()) { + TTY.println("Warning: could not create dump directory " + dumpPath); + return false; + } + + TTY.println("Retrying " + CompilationTask.this); + retryDumpHandlers = new ArrayList<>(); + retryOptions = new OptionValues(options, + PrintGraphFile, true, + PrintCFGFileName, methodFQN, + PrintGraphFileName, methodFQN, + DumpPath, dumpPath.getPath()); + override(DUMP, INFO_LEVEL).enable(DUMP_METHOD); + new GraalDebugConfigCustomizer().customize(this); + return true; + } + + private Collection retryDumpHandlers; + private OptionValues retryOptions; + + @Override + public Collection dumpHandlers() { + return retryDumpHandlers; + } + + @Override + public OptionValues getOptions() { + return retryOptions; + } + } + static class Lazy { /** * A {@link com.sun.management.ThreadMXBean} to be able to query some information about the @@ -196,9 +342,8 @@ public HotSpotCompilationRequestResult runCompilation() { HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime(); GraalHotSpotVMConfig config = graalRuntime.getVMConfig(); - final long threadId = Thread.currentThread().getId(); int entryBCI = getEntryBCI(); - final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; + boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; HotSpotResolvedJavaMethod method = getMethod(); // register the compilation id in the method metrics @@ -220,64 +365,9 @@ return null; } - CompilationResult result = null; + RetryableCompilation compilation = new RetryableCompilation(compilationEvent); try (DebugCloseable a = CompilationTime.start()) { - CompilationStatistics stats = CompilationStatistics.create(options, method, isOSR); - final boolean printCompilation = PrintCompilation.getValue(options) && !TTY.isSuppressed(); - final boolean printAfterCompilation = PrintAfterCompilation.getValue(options) && !TTY.isSuppressed(); - if (printCompilation) { - TTY.println(getMethodDescription() + "..."); - } - - TTY.Filter filter = new TTY.Filter(PrintFilter.getValue(options), method); - final long start; - final long allocatedBytesBefore; - if (printAfterCompilation || printCompilation) { - start = TimeSource.getTimeNS(); - allocatedBytesBefore = printAfterCompilation || printCompilation ? Lazy.threadMXBean.getThreadAllocatedBytes(threadId) : 0L; - } else { - start = 0L; - allocatedBytesBefore = 0L; - } - - try (Scope s = Debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) { - // Begin the compilation event. - compilationEvent.begin(); - result = compiler.compile(method, entryBCI, useProfilingInfo, compilationId, options); - } catch (Throwable e) { - throw Debug.handle(e); - } finally { - // End the compilation event. - compilationEvent.end(); - - filter.remove(); - - if (printAfterCompilation || printCompilation) { - final long stop = TimeSource.getTimeNS(); - final long duration = (stop - start) / 1000000; - final int targetCodeSize = result != null ? result.getTargetCodeSize() : -1; - final int bytecodeSize = result != null ? result.getBytecodeSize() : 0; - final long allocatedBytesAfter = Lazy.threadMXBean.getThreadAllocatedBytes(threadId); - final long allocatedKBytes = (allocatedBytesAfter - allocatedBytesBefore) / 1024; - - if (printAfterCompilation) { - TTY.println(getMethodDescription() + String.format(" | %4dms %5dB %5dB %5dkB", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); - } else if (printCompilation) { - TTY.println(String.format("%-6d JVMCI %-70s %-45s %-50s | %4dms %5dB %5dB %5dkB", getId(), "", "", "", duration, bytecodeSize, targetCodeSize, allocatedKBytes)); - } - } - } - - if (result != null) { - try (DebugCloseable b = CodeInstallationTime.start()) { - installMethod(result); - } - } - stats.finish(method, installedCode); - if (result != null) { - return HotSpotCompilationRequestResult.success(result.getBytecodeSize() - method.getCodeSize()); - } - return null; + return compilation.execute(); } catch (BailoutException bailout) { BAILOUTS.increment(); if (ExitVMOnBailout.getValue(options)) { @@ -319,8 +409,9 @@ try { int compiledBytecodes = 0; int codeSize = 0; - if (result != null) { - compiledBytecodes = result.getBytecodeSize(); + + if (compilation.result != null) { + compiledBytecodes = compilation.result.getBytecodeSize(); CompiledBytecodes.add(compiledBytecodes); if (installedCode != null) { codeSize = installedCode.getSize(); @@ -334,7 +425,7 @@ compilationEvent.setMethod(method.format("%H.%n(%p)")); compilationEvent.setCompileId(getId()); compilationEvent.setCompileLevel(config.compilationLevelFullOptimization); - compilationEvent.setSucceeded(result != null && installedCode != null); + compilationEvent.setSucceeded(compilation.result != null && installedCode != null); compilationEvent.setIsOsr(isOSR); compilationEvent.setCodeSize(codeSize); compilationEvent.setInlinedBytes(compiledBytecodes); @@ -387,7 +478,7 @@ installedCode = null; Object[] context = {new DebugDumpScope(getIdString(), true), codeCache, getMethod(), compResult}; try (Scope s = Debug.scope("CodeInstall", context)) { - HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(getRequest().getMethod(), getRequest(), compResult); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, getRequest().getMethod(), getRequest(), compResult); installedCode = (HotSpotInstalledCode) codeCache.installCode(getRequest().getMethod(), compiledCode, null, getRequest().getMethod().getSpeculationLog(), installAsDefault); } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Thu Apr 06 14:31:32 2017 -0700 @@ -267,7 +267,31 @@ public final int secondarySuperCacheOffset = getFieldOffset("Klass::_secondary_super_cache", Integer.class, "Klass*"); public final int secondarySupersOffset = getFieldOffset("Klass::_secondary_supers", Integer.class, "Array*"); - public final int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "oop"); + public final boolean classMirrorIsHandle; + public final int classMirrorOffset; + { + String name = "Klass::_java_mirror"; + int offset = -1; + boolean isHandle = false; + try { + offset = getFieldOffset(name, Integer.class, "oop"); + } catch (JVMCIError e) { + + } + if (offset == -1) { + try { + offset = getFieldOffset(name, Integer.class, "jobject"); + isHandle = true; + } catch (JVMCIError e) { + + } + } + if (offset == -1) { + throw new JVMCIError("cannot get offset of field " + name + " with type oop or jobject"); + } + classMirrorOffset = offset; + classMirrorIsHandle = isHandle; + } public final int klassSuperKlassOffset = getFieldOffset("Klass::_super", Integer.class, "Klass*"); public final int klassModifierFlagsOffset = getFieldOffset("Klass::_modifier_flags", Integer.class, "jint"); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Thu Apr 06 14:31:32 2017 -0700 @@ -406,7 +406,7 @@ @Override public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) { HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null; - return HotSpotCompiledCodeBuilder.createCompiledCode(method, compRequest, compResult); + return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java Thu Apr 06 14:31:32 2017 -0700 @@ -42,6 +42,7 @@ import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.graph.NodeSourcePosition; +import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.StackSlot; import jdk.vm.ci.code.site.ConstantReference; @@ -61,13 +62,13 @@ public class HotSpotCompiledCodeBuilder { - public static HotSpotCompiledCode createCompiledCode(ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) { + public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) { String name = compResult.getName(); byte[] targetCode = compResult.getTargetCode(); int targetCodeSize = compResult.getTargetCodeSize(); - Site[] sites = getSortedSites(compResult); + Site[] sites = getSortedSites(codeCache, compResult); Assumption[] assumptions = compResult.getAssumptions(); @@ -201,7 +202,7 @@ * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects * {@link Infopoint} PCs to be unique. */ - private static Site[] getSortedSites(CompilationResult target) { + private static Site[] getSortedSites(CodeCacheProvider codeCache, CompilationResult target) { List sites = new ArrayList<>( target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size()); sites.addAll(target.getExceptionHandlers()); @@ -214,9 +215,11 @@ * can really be represented and recording the end PC seems to give the best results and * corresponds with what C1 and C2 do. */ - for (SourceMapping source : target.getSourceMappings()) { - sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION)); - assert verifySourcePositionReceivers(source.getSourcePosition()); + if (codeCache.shouldDebugNonSafepoints()) { + for (SourceMapping source : target.getSourceMappings()) { + sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION)); + assert verifySourcePositionReceivers(source.getSourcePosition()); + } } SiteComparator c = new SiteComparator(); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDebugInfoBuilder.java Thu Apr 06 14:31:32 2017 -0700 @@ -71,8 +71,8 @@ VirtualStackSlot slot = lockStack.makeLockSlot(lockDepth); ValueNode lock = state.lockAt(lockIndex); JavaValue object = toJavaValue(lock); - boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex) == null; - assert state.monitorIdAt(lockIndex) == null || state.monitorIdAt(lockIndex).getLockDepth() == lockDepth; + boolean eliminated = object instanceof VirtualObject || state.monitorIdAt(lockIndex).isEliminated(); + assert state.monitorIdAt(lockIndex).getLockDepth() == lockDepth; return new StackLockValue(object, slot, eliminated); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Thu Apr 06 14:31:32 2017 -0700 @@ -24,6 +24,7 @@ import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; + import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.Formattable; @@ -98,6 +99,9 @@ @Override @SuppressWarnings("try") public CompilationRequestResult compileMethod(CompilationRequest request) { + if (graalRuntime.isShutdown()) { + return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), false); + } OptionValues options = graalRuntime.getOptions(); if (graalRuntime.isBootstrapping()) { if (GraalDebugConfig.Options.BootstrapInitializeOnly.getValue(options)) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Thu Apr 06 14:31:32 2017 -0700 @@ -45,6 +45,7 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFactory { private static MethodFilter[] graalCompileOnlyFilter; + private static boolean compileGraalWithC1Only; private final HotSpotGraalJVMCIServiceLocator locator; @@ -67,18 +68,17 @@ JVMCIVersionCheck.check(false); assert options == null : "cannot select " + getClass() + " service more than once"; options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; - initializeGraalCompileOnlyFilter(options); - if (graalCompileOnlyFilter != null || !Options.UseTrivialPrefixes.getValue(options)) { - /* - * Exercise this code path early to encourage loading now. This doesn't solve problem of - * deadlock during class loading but seems to eliminate it in practice. - */ - adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization); - adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple); - } + initializeGraalCompilePolicyFields(options); + /* + * Exercise this code path early to encourage loading now. This doesn't solve problem of + * deadlock during class loading but seems to eliminate it in practice. + */ + adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.FullOptimization); + adjustCompilationLevelInternal(Object.class, "hashCode", "()I", CompilationLevel.Simple); } - private static void initializeGraalCompileOnlyFilter(OptionValues options) { + private static void initializeGraalCompilePolicyFields(OptionValues options) { + compileGraalWithC1Only = Options.CompileGraalWithC1Only.getValue(options); String optionValue = Options.GraalCompileOnly.getValue(options); if (optionValue != null) { MethodFilter[] filter = MethodFilter.parse(optionValue); @@ -101,9 +101,6 @@ @Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert) public static final OptionKey CompileGraalWithC1Only = new OptionKey<>(true); - @Option(help = "Hook into VM-level mechanism for denoting compilations to be performed in first tier.", type = OptionType.Expert) - public static final OptionKey UseTrivialPrefixes = new OptionKey<>(false); - @Option(help = "A method filter selecting what should be compiled by Graal. All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert) public static final OptionKey GraalCompileOnly = new OptionKey<>(null); // @formatter:on @@ -137,27 +134,15 @@ } @Override - public String[] getTrivialPrefixes() { - if (Options.UseTrivialPrefixes.getValue(options)) { - if (Options.CompileGraalWithC1Only.getValue(options)) { - return new String[]{"jdk/vm/ci", "org/graalvm/compiler", "com/oracle/graal"}; - } - } - return null; - } - - @Override public CompilationLevelAdjustment getCompilationLevelAdjustment() { if (graalCompileOnlyFilter != null) { return CompilationLevelAdjustment.ByFullSignature; } - if (!Options.UseTrivialPrefixes.getValue(options)) { - if (Options.CompileGraalWithC1Only.getValue(options)) { - // We only decide using the class declaring the method - // so no need to have the method name and signature - // symbols converted to a String. - return CompilationLevelAdjustment.ByHolder; - } + if (compileGraalWithC1Only) { + // We only decide using the class declaring the method + // so no need to have the method name and signature + // symbols converted to a String. + return CompilationLevelAdjustment.ByHolder; } return CompilationLevelAdjustment.None; } @@ -193,10 +178,12 @@ return CompilationLevel.Simple; } } - if (level.ordinal() > CompilationLevel.Simple.ordinal()) { - String declaringClassName = declaringClass.getName(); - if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm.compiler") || declaringClassName.startsWith("com.oracle.graal")) { - return CompilationLevel.Simple; + if (compileGraalWithC1Only) { + if (level.ordinal() > CompilationLevel.Simple.ordinal()) { + String declaringClassName = declaringClass.getName(); + if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) { + return CompilationLevel.Simple; + } } } return level; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalJVMCIServiceLocator.java Thu Apr 06 14:31:32 2017 -0700 @@ -30,68 +30,77 @@ import org.graalvm.compiler.serviceprovider.ServiceProvider; import jdk.vm.ci.hotspot.HotSpotVMEventListener; -import jdk.vm.ci.runtime.JVMCICompiler; import jdk.vm.ci.runtime.JVMCICompilerFactory; import jdk.vm.ci.services.JVMCIServiceLocator; +import jdk.vm.ci.services.Services; @ServiceProvider(JVMCIServiceLocator.class) public final class HotSpotGraalJVMCIServiceLocator extends JVMCIServiceLocator { - private boolean exportsAdded; - /** - * Dynamically exports and opens various internal JDK packages to the Graal module. This - * requires only a single {@code --add-exports=java.base/jdk.internal.module=} on - * the VM command line instead of a {@code --add-exports} instance for each JDK internal package - * used by Graal. + * Holds the state shared between all {@link HotSpotGraalJVMCIServiceLocator} instances. This is + * necessary as {@link Services} can create a new instance of a service provider each time + * {@link Services#load(Class)} or {@link Services#loadSingle(Class, boolean)} is called. */ - private void addExports() { - if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) { - Object javaBaseModule = getModule.invoke(String.class); - Object graalModule = getModule.invoke(getClass()); - addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule); - addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule); - addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule); - addOpens.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule); - addOpens.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule); - addOpens.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule); - exportsAdded = true; + private static final class Shared { + static final Shared SINGLETON = new Shared(); + + private boolean exportsAdded; + + /** + * Dynamically exports and opens various internal JDK packages to the Graal module. This + * requires only a single {@code --add-exports=java.base/jdk.internal.module=} + * on the VM command line instead of a {@code --add-exports} instance for each JDK internal + * package used by Graal. + */ + private void addExports() { + if (JAVA_SPECIFICATION_VERSION >= 9 && !exportsAdded) { + Object javaBaseModule = getModule.invoke(String.class); + Object graalModule = getModule.invoke(getClass()); + addExports.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule); + addExports.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule); + addExports.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule); + addOpens.invokeStatic(javaBaseModule, "jdk.internal.misc", graalModule); + addOpens.invokeStatic(javaBaseModule, "jdk.internal.jimage", graalModule); + addOpens.invokeStatic(javaBaseModule, "com.sun.crypto.provider", graalModule); + exportsAdded = true; + } + } + + T getProvider(Class service, HotSpotGraalJVMCIServiceLocator locator) { + if (service == JVMCICompilerFactory.class) { + addExports(); + return service.cast(new HotSpotGraalCompilerFactory(locator)); + } else if (service == HotSpotVMEventListener.class) { + if (graalRuntime != null) { + addExports(); + return service.cast(new HotSpotGraalVMEventListener(graalRuntime)); + } + } + return null; + } + + private HotSpotGraalRuntime graalRuntime; + + /** + * Notifies this object of the compiler created via {@link HotSpotGraalJVMCIServiceLocator}. + */ + void onCompilerCreation(HotSpotGraalCompiler compiler) { + assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created"; + this.graalRuntime = (HotSpotGraalRuntime) compiler.getGraalRuntime(); } } - private HotSpotGraalRuntime graalRuntime; - @Override public T getProvider(Class service) { - if (service == JVMCICompilerFactory.class) { - addExports(); - return service.cast(new HotSpotGraalCompilerFactory(this)); - } else if (service == HotSpotVMEventListener.class) { - if (graalRuntime != null) { - addExports(); - return service.cast(new HotSpotGraalVMEventListener(graalRuntime)); - } - } - return null; + return Shared.SINGLETON.getProvider(service, this); } /** - * The signature cannot mention HotSpotGraalCompiler since it indirectly references - * JVMCICompiler which is in a non-exported JVMCI package. This causes an IllegalAccessError - * while looking for the - * provider factory - * method: - * - *
-     * java.util.ServiceConfigurationError: jdk.vm.ci.services.JVMCIServiceLocator: Unable to get public provider() method
-     * ...
-     * Caused by: java.lang.IllegalAccessError: superinterface check failed: class org.graalvm.compiler.api.runtime.GraalJVMCICompiler
-     * (in module org.graalvm.compiler.graal_core) cannot access class jdk.vm.ci.runtime.JVMCICompiler (in module jdk.vm.ci) because
-     * module jdk.vm.ci does not export jdk.vm.ci.runtime to module org.graalvm.compiler.graal_core
-     * 
+ * Notifies this object of the compiler created via {@link HotSpotGraalJVMCIServiceLocator}. */ - void onCompilerCreation(JVMCICompiler compiler) { - assert this.graalRuntime == null : "only expect a single JVMCICompiler to be created"; - this.graalRuntime = (HotSpotGraalRuntime) ((HotSpotGraalCompiler) compiler).getGraalRuntime(); + @SuppressWarnings("static-method") + void onCompilerCreation(HotSpotGraalCompiler compiler) { + Shared.SINGLETON.onCompilerCreation(compiler); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Thu Apr 06 14:31:32 2017 -0700 @@ -34,8 +34,22 @@ import static org.graalvm.compiler.debug.GraalDebugConfig.Options.MethodFilter; import static org.graalvm.compiler.debug.GraalDebugConfig.Options.Verify; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.zip.Deflater; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.runtime.GraalRuntime; @@ -278,6 +292,7 @@ } private long runtimeStartTime; + private boolean shutdown; /** * Take action related to entering a new execution phase. @@ -291,6 +306,7 @@ } void shutdown() { + shutdown = true; if (debugValuesPrinter != null) { debugValuesPrinter.printDebugValues(options); } @@ -302,6 +318,8 @@ } } BenchmarkCounters.shutdown(runtime(), options, runtimeStartTime); + + archiveAndDeleteOutputDirectory(); } void clearMeters() { @@ -321,4 +339,95 @@ public boolean isBootstrapping() { return bootstrapJVMCI && !bootstrapFinished; } + + @Override + public boolean isShutdown() { + return shutdown; + } + + /** + * Gets a unique identifier for this execution such as a process ID. + */ + private static String getExecutionID() { + String runtimeName = ManagementFactory.getRuntimeMXBean().getName(); + try { + int index = runtimeName.indexOf('@'); + if (index != -1) { + long pid = Long.parseLong(runtimeName.substring(0, index)); + return Long.toString(pid); + } + } catch (NumberFormatException e) { + } + return runtimeName; + } + + private String outputDirectory; + + @Override + public String getOutputDirectory() { + if (outputDirectory == null) { + outputDirectory = "graal_output_" + getExecutionID(); + File dir = new File(outputDirectory).getAbsoluteFile(); + if (!dir.exists()) { + dir.mkdirs(); + if (!dir.exists()) { + TTY.println("Warning: could not create Graal diagnostic directory " + dir); + return null; + } + } + } + return outputDirectory; + } + + /** + * Archives and deletes the {@linkplain #getOutputDirectory() output directory} if it exists. + */ + private void archiveAndDeleteOutputDirectory() { + if (outputDirectory != null) { + Path dir = Paths.get(outputDirectory); + if (dir.toFile().exists()) { + try { + // Give compiler threads a chance to finishing dumping + Thread.sleep(1000); + } catch (InterruptedException e1) { + } + File zip = new File(outputDirectory + ".zip").getAbsoluteFile(); + List toDelete = new ArrayList<>(); + try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip))) { + zos.setLevel(Deflater.BEST_COMPRESSION); + Files.walkFileTree(dir, Collections.emptySet(), Integer.MAX_VALUE, new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (attrs.isRegularFile()) { + ZipEntry ze = new ZipEntry(file.toString()); + zos.putNextEntry(ze); + zos.write(Files.readAllBytes(file)); + zos.closeEntry(); + } + toDelete.add(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path d, IOException exc) throws IOException { + toDelete.add(d); + return FileVisitResult.CONTINUE; + } + }); + TTY.println("Graal diagnostic output saved in %s", zip); + } catch (IOException e) { + TTY.printf("IO error archiving %s:%n", dir); + e.printStackTrace(TTY.out); + } + for (Path p : toDelete) { + try { + Files.delete(p); + } catch (IOException e) { + TTY.printf("IO error deleting %s:%n", p); + e.printStackTrace(TTY.out); + } + } + } + } + } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java Thu Apr 06 14:31:32 2017 -0700 @@ -62,4 +62,19 @@ * Determines if the VM is currently bootstrapping the JVMCI compiler. */ boolean isBootstrapping(); + + /** + * This runtime has been requested to shutdown. + */ + boolean isShutdown(); + + /** + * Gets a directory into which diagnostics such crash reports and dumps should be written. This + * method will create the directory if it doesn't exist so it should only be called if + * diagnostics are about to be generated. + * + * @return the directory into which diagnostics can be written or {@code null} if the directory + * does not exist and could not be created + */ + String getOutputDirectory(); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalVMEventListener.java Thu Apr 06 14:31:32 2017 -0700 @@ -46,10 +46,10 @@ @Override public void notifyInstall(HotSpotCodeCacheProvider codeCache, InstalledCode installedCode, CompiledCode compiledCode) { - if (Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { + if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) { CompilationResult compResult = Debug.contextLookup(CompilationResult.class); assert compResult != null : "can't dump installed code properly without CompilationResult"; - Debug.dump(Debug.BASIC_LOG_LEVEL, installedCode, "After code installation"); + Debug.dump(Debug.BASIC_LEVEL, installedCode, "After code installation"); } if (Debug.isLogEnabled()) { Debug.log("%s", codeCache.disassemble(installedCode)); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/PrintStreamOptionKey.java Thu Apr 06 14:31:32 2017 -0700 @@ -45,7 +45,7 @@ } /** - * Replace any instance of %p with a an identifying name. Try to get it from the RuntimeMXBean + * Replace any instance of %p with an identifying name. Try to get it from the RuntimeMXBean * name. * * @return the name of the file to log to diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu Apr 06 14:31:32 2017 -0700 @@ -31,6 +31,7 @@ import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION; +import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_HANDLE_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION; import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION; @@ -40,6 +41,7 @@ import java.lang.ref.Reference; import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; @@ -409,10 +411,17 @@ return; } + ValueNode hub = n.getHub(); + GraalHotSpotVMConfig vmConfig = runtime.getVMConfig(); StructuredGraph graph = n.graph(); - assert !n.getHub().isConstant(); - AddressNode address = createOffsetAddress(graph, n.getHub(), runtime.getVMConfig().classMirrorOffset); - FloatingReadNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, n.stamp(), null, BarrierType.NONE)); + assert !hub.isConstant() || GraalOptions.ImmutableCode.getValue(graph.getOptions()); + AddressNode mirrorAddress = createOffsetAddress(graph, hub, vmConfig.classMirrorOffset); + FloatingReadNode read = graph.unique(new FloatingReadNode(mirrorAddress, CLASS_MIRROR_LOCATION, null, vmConfig.classMirrorIsHandle ? StampFactory.forKind(target.wordJavaKind) : n.stamp(), + null, BarrierType.NONE)); + if (vmConfig.classMirrorIsHandle) { + AddressNode address = createOffsetAddress(graph, read, 0); + read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_HANDLE_LOCATION, null, n.stamp(), null, BarrierType.NONE)); + } n.replaceAtUsagesAndDelete(read); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Thu Apr 06 14:31:32 2017 -0700 @@ -323,7 +323,8 @@ */ private static ValueNode getMetaspaceConstantPool(GraphBuilderContext b, ValueNode constantPoolOop, WordTypes wordTypes, GraalHotSpotVMConfig config) { // ConstantPool.constantPoolOop is in fact the holder class. - ClassGetHubNode klass = b.add(new ClassGetHubNode(b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None))); + ValueNode value = b.nullCheckedValue(constantPoolOop, DeoptimizationAction.None); + ValueNode klass = b.add(ClassGetHubNode.create(value, b.getMetaAccess(), b.getConstantReflection(), false)); boolean notCompressible = false; AddressNode constantsAddress = b.add(new OffsetAddressNode(klass, b.add(ConstantNode.forLong(config.instanceKlassConstantsOffset)))); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSuitesProvider.java Thu Apr 06 14:31:32 2017 -0700 @@ -90,7 +90,7 @@ if (ImmutableCode.getValue(options)) { // lowering introduces class constants, therefore it must be after lowering - ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config.classMirrorOffset, config.useCompressedOops ? config.getOopEncoding() : null)); + ret.getHighTier().appendPhase(new LoadJavaMirrorWithKlassPhase(config)); if (VerifyPhases.getValue(options)) { ret.getHighTier().appendPhase(new AheadOfTimeVerificationPhase()); } @@ -146,10 +146,10 @@ protected void run(StructuredGraph graph, HighTierContext context) { EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, runtime.getTarget().arch); - SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), - context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()), runtime.getTarget().arch); StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), AllowAssumptions.YES).method(graph.method()).build(); - graphDecoder.decode(targetGraph, encodedGraph); + SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(), + context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions())); + graphDecoder.decode(encodedGraph); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java Thu Apr 06 14:31:32 2017 -0700 @@ -109,7 +109,7 @@ PointerEqualsNode comparison = b.add(new PointerEqualsNode(left, right)); ValueNode eqValue = b.add(forBoolean(opcode == POINTER_EQ)); ValueNode neValue = b.add(forBoolean(opcode == POINTER_NE)); - b.addPush(returnKind, new ConditionalNode(comparison, eqValue, neValue)); + b.addPush(returnKind, ConditionalNode.create(comparison, eqValue, neValue)); break; case IS_NULL: @@ -118,7 +118,7 @@ assert pointer.stamp() instanceof MetaspacePointerStamp; LogicNode isNull = b.add(IsNullNode.create(pointer)); - b.addPush(returnKind, new ConditionalNode(isNull, b.add(forBoolean(true)), b.add(forBoolean(false)))); + b.addPush(returnKind, ConditionalNode.create(isNull, b.add(forBoolean(true)), b.add(forBoolean(false)))); break; case FROM_POINTER: diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/GraalHotSpotVMConfigNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -29,6 +29,7 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; @@ -72,8 +73,8 @@ * @param config * @param markId id of the config value */ - public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId) { - super(TYPE, StampFactory.forNodeIntrinsic()); + public GraalHotSpotVMConfigNode(@InjectedNodeParameter Stamp stamp, @InjectedNodeParameter GraalHotSpotVMConfig config, int markId) { + super(TYPE, stamp); this.config = config; this.markId = markId; } @@ -85,7 +86,7 @@ * @param markId id of the config value * @param kind explicit type of the node */ - public GraalHotSpotVMConfigNode(@InjectedNodeParameter GraalHotSpotVMConfig config, int markId, JavaKind kind) { + public GraalHotSpotVMConfigNode(GraalHotSpotVMConfig config, int markId, JavaKind kind) { super(TYPE, StampFactory.forKind(kind)); this.config = config; this.markId = markId; @@ -100,13 +101,13 @@ @NodeIntrinsic private static native boolean areConfigValuesConstant(); - @NodeIntrinsic(setStampFromReturnType = true) + @NodeIntrinsic private static native long loadLongConfigValue(@ConstantNodeParameter int markId); - @NodeIntrinsic(setStampFromReturnType = true) + @NodeIntrinsic private static native int loadIntConfigValue(@ConstantNodeParameter int markId); - @NodeIntrinsic(setStampFromReturnType = true) + @NodeIntrinsic private static native byte loadByteConfigValue(@ConstantNodeParameter int markId); public static long cardTableAddress() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/StubForeignCallNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,7 +32,7 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallLinkage; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; -import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil; @@ -44,7 +44,6 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; -import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; /** @@ -59,8 +58,8 @@ protected final ForeignCallDescriptor descriptor; - public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, ForeignCallDescriptor descriptor, ValueNode... arguments) { - super(TYPE, StampFactory.forKind(JavaKind.fromJavaClass(descriptor.getResultType()))); + public StubForeignCallNode(@InjectedNodeParameter ForeignCallsProvider foreignCalls, @InjectedNodeParameter Stamp stamp, ForeignCallDescriptor descriptor, ValueNode... arguments) { + super(TYPE, stamp); this.arguments = new NodeInputList<>(this, arguments); this.descriptor = descriptor; this.foreignCalls = foreignCalls; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/EncodedSymbolNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.hotspot.nodes.aot; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; @@ -44,8 +45,8 @@ @OptionalInput protected ValueNode value; - public EncodedSymbolNode(ValueNode value) { - super(TYPE, null); + public EncodedSymbolNode(@InjectedNodeParameter Stamp stamp, ValueNode value) { + super(TYPE, stamp); assert value != null; this.value = value; } @@ -61,6 +62,6 @@ return this; } - @NodeIntrinsic(setStampFromReturnType = true) + @NodeIntrinsic public static native Word encode(Object constant); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/LoadJavaMirrorWithKlassPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,7 +22,6 @@ */ package org.graalvm.compiler.hotspot.phases; -import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION; import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; import static org.graalvm.compiler.nodes.NamedLocationIdentity.FINAL_LOCATION; @@ -32,9 +31,11 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.nodes.CompressionNode; import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp; import org.graalvm.compiler.hotspot.nodes.type.NarrowOopStamp; +import org.graalvm.compiler.hotspot.replacements.HubGetClassNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; @@ -67,12 +68,10 @@ */ public class LoadJavaMirrorWithKlassPhase extends BasePhase { - private final int classMirrorOffset; private final CompressEncoding oopEncoding; - public LoadJavaMirrorWithKlassPhase(int classMirrorOffset, CompressEncoding oopEncoding) { - this.classMirrorOffset = classMirrorOffset; - this.oopEncoding = oopEncoding; + public LoadJavaMirrorWithKlassPhase(GraalHotSpotVMConfig config) { + this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null; } private ValueNode getClassConstantReplacement(StructuredGraph graph, PhaseContext context, JavaConstant constant) { @@ -85,13 +84,12 @@ if (type instanceof HotSpotResolvedObjectType) { ConstantNode klass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), ((HotSpotResolvedObjectType) type).klass(), metaAccess, graph); - AddressNode address = graph.unique(new OffsetAddressNode(klass, ConstantNode.forLong(classMirrorOffset, graph))); - ValueNode read = graph.unique(new FloatingReadNode(address, CLASS_MIRROR_LOCATION, null, stamp)); + ValueNode getClass = graph.unique(new HubGetClassNode(metaAccess, klass)); if (((HotSpotObjectConstant) constant).isCompressed()) { - return CompressionNode.compress(read, oopEncoding); + return CompressionNode.compress(getClass, oopEncoding); } else { - return read; + return getClass; } } else { /* diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -94,7 +94,7 @@ assert graph.getNodes(EntryMarkerNode.TYPE).isEmpty(); return; } - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement initial at bci %d", graph.getEntryBCI()); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement initial at bci %d", graph.getEntryBCI()); EntryMarkerNode osr; int maxIterations = -1; @@ -144,7 +144,7 @@ proxy.replaceAndDelete(proxy.value()); } GraphUtil.removeFixedWithUnusedInputs(osr); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement loop peeling result"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement loop peeling result"); } while (true); FrameState osrState = osr.stateAfter(); @@ -157,7 +157,7 @@ graph.setStart(osrStart); osrStart.setStateAfter(osrState); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement after setting OSR start"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement after setting OSR start"); final int localsSize = osrState.localsSize(); final int locksSize = osrState.locksSize(); @@ -188,9 +188,9 @@ } osr.replaceAtUsages(InputType.Guard, osrStart); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement after replacing entry proxies"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies"); GraphUtil.killCFG(start); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement result"); new DeadCodeEliminationPhase(Required).apply(graph); if (currentOSRWithLocks) { @@ -210,7 +210,7 @@ osrMonitorEnter.setNext(oldNext); osrStart.setNext(osrMonitorEnter); } - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "After inserting OSR monitor enters"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "After inserting OSR monitor enters"); /* * Ensure balanced monitorenter - monitorexit * @@ -226,7 +226,7 @@ } } } - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "OnStackReplacement result"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "OnStackReplacement result"); new DeadCodeEliminationPhase(Required).apply(graph); /* * There must not be any parameter nodes left after OSR compilation. diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -28,9 +28,6 @@ import java.util.HashMap; import java.util.Map.Entry; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.JavaConstant; - import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; @@ -43,6 +40,9 @@ import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.tiers.PhaseContext; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.Constant; + public class EliminateRedundantInitializationPhase extends BasePhase { /** * Find blocks with class initializing nodes for the class identified the by the constant node. @@ -204,7 +204,7 @@ ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, false, true, false); ArrayList redundantInits = new ArrayList<>(); for (ConstantNode node : getConstantNodes(graph)) { - JavaConstant constant = node.asJavaConstant(); + Constant constant = node.asConstant(); if (constant instanceof HotSpotMetaspaceConstant) { redundantInits.addAll(processConstantNode(cfg, node)); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,8 +25,11 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.calc.Condition; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Canonicalizable; @@ -42,6 +45,7 @@ import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.spi.Lowerable; @@ -69,19 +73,30 @@ this.clazz = clazz; } - @Override - public Node canonical(CanonicalizerTool tool) { - if (tool.allUsagesAvailable() && hasNoUsages()) { + public static ValueNode create(ValueNode clazz, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable) { + return canonical(null, metaAccess, constantReflection, allUsagesAvailable, KlassPointerStamp.klass(), clazz); + } + + @SuppressWarnings("unused") + public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode clazz) { + ValueNode clazzValue = create(clazz, b.getMetaAccess(), b.getConstantReflection(), false); + b.push(JavaKind.Object, b.recursiveAppend(clazzValue)); + return true; + } + + public static ValueNode canonical(ClassGetHubNode classGetHubNode, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable, Stamp stamp, + ValueNode clazz) { + ClassGetHubNode self = classGetHubNode; + if (allUsagesAvailable && self != null && self.hasNoUsages()) { return null; } else { if (clazz.isConstant()) { - MetaAccessProvider metaAccess = tool.getMetaAccess(); if (metaAccess != null) { - ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(clazz.asJavaConstant()); + ResolvedJavaType exactType = constantReflection.asJavaType(clazz.asJavaConstant()); if (exactType.isPrimitive()) { - return ConstantNode.forConstant(stamp(), JavaConstant.NULL_POINTER, metaAccess); + return ConstantNode.forConstant(stamp, JavaConstant.NULL_POINTER, metaAccess); } else { - return ConstantNode.forConstant(stamp(), tool.getConstantReflection().asObjectHub(exactType), metaAccess); + return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(exactType), metaAccess); } } } @@ -90,14 +105,22 @@ return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject()); } if (clazz instanceof HubGetClassNode) { - // replace _klass._java_mirror._klass -> _klass + // Replace: _klass._java_mirror._klass -> _klass return ((HubGetClassNode) clazz).getHub(); } - return this; + if (self == null) { + self = new ClassGetHubNode(clazz); + } + return self; } } @Override + public Node canonical(CanonicalizerTool tool) { + return canonical(this, tool.getMetaAccess(), tool.getConstantReflection(), tool.allUsagesAvailable(), stamp(), clazz); + } + + @Override public void lower(LoweringTool tool) { tool.getLowerer().lower(this, tool); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Thu Apr 06 14:31:32 2017 -0700 @@ -702,17 +702,17 @@ public static Word loadWordFromObject(Object object, int offset) { ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); - return loadWordFromObjectIntrinsic(object, offset, getWordKind(), LocationIdentity.any()); + return loadWordFromObjectIntrinsic(object, offset, LocationIdentity.any(), getWordKind()); } public static Word loadWordFromObject(Object object, int offset, LocationIdentity identity) { ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); - return loadWordFromObjectIntrinsic(object, offset, getWordKind(), identity); + return loadWordFromObjectIntrinsic(object, offset, identity, getWordKind()); } public static KlassPointer loadKlassFromObject(Object object, int offset, LocationIdentity identity) { ReplacementsUtil.staticAssert(offset != hubOffset(INJECTED_VMCONFIG), "Use loadHubIntrinsic instead of loadWordFromObject"); - return loadKlassFromObjectIntrinsic(object, offset, getWordKind(), identity); + return loadKlassFromObjectIntrinsic(object, offset, identity, getWordKind()); } /** @@ -725,17 +725,17 @@ return registerAsWord(register, true, false); } - @NodeIntrinsic(value = ReadRegisterNode.class, setStampFromReturnType = true) + @NodeIntrinsic(value = ReadRegisterNode.class) public static native Word registerAsWord(@ConstantNodeParameter Register register, @ConstantNodeParameter boolean directUse, @ConstantNodeParameter boolean incoming); - @NodeIntrinsic(value = WriteRegisterNode.class, setStampFromReturnType = true) + @NodeIntrinsic(value = WriteRegisterNode.class) public static native void writeRegisterAsWord(@ConstantNodeParameter Register register, Word value); - @NodeIntrinsic(value = RawLoadNode.class, setStampFromReturnType = true) - private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity); + @NodeIntrinsic(value = RawLoadNode.class) + private static native Word loadWordFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind); - @NodeIntrinsic(value = RawLoadNode.class, setStampFromReturnType = true) - private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter JavaKind wordKind, @ConstantNodeParameter LocationIdentity locationIdentity); + @NodeIntrinsic(value = RawLoadNode.class) + private static native KlassPointer loadKlassFromObjectIntrinsic(Object object, long offset, @ConstantNodeParameter LocationIdentity locationIdentity, @ConstantNodeParameter JavaKind wordKind); @NodeIntrinsic(value = LoadHubNode.class) public static native KlassPointer loadHubIntrinsic(Object object); @@ -803,6 +803,8 @@ public static final LocationIdentity CLASS_MIRROR_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror"); + public static final LocationIdentity CLASS_MIRROR_HANDLE_LOCATION = NamedLocationIdentity.immutable("Klass::_java_mirror handle"); + public static final LocationIdentity HEAP_TOP_LOCATION = NamedLocationIdentity.mutable("HeapTop"); @Fold diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; +import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.graph.Node; @@ -70,7 +71,7 @@ return null; } else { MetaAccessProvider metaAccess = tool.getMetaAccess(); - if (metaAccess != null && hub.isConstant()) { + if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(graph().getOptions())) { ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant()); if (exactType != null) { return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/KlassLayoutHelperNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,9 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_4; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaMethod; import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -38,6 +41,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; @@ -63,6 +67,18 @@ this.klass = klass; } + public static ValueNode create(GraalHotSpotVMConfig config, ValueNode klass, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess) { + Stamp stamp = StampFactory.forKind(JavaKind.Int); + return canonical(null, config, klass, stamp, constantReflection, metaAccess); + } + + @SuppressWarnings("unused") + public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, @InjectedNodeParameter GraalHotSpotVMConfig config, ValueNode klass) { + ValueNode valueNode = create(config, klass, b.getConstantReflection(), b.getMetaAccess()); + b.push(JavaKind.Int, b.recursiveAppend(valueNode)); + return true; + } + @Override public boolean inferStamp() { if (klass instanceof LoadHubNode) { @@ -92,27 +108,36 @@ if (tool.allUsagesAvailable() && hasNoUsages()) { return null; } else { - if (klass.isConstant()) { - if (!klass.asConstant().isDefaultForKind()) { - Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset); - return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess()); + return canonical(this, config, klass, stamp(), tool.getConstantReflection(), tool.getMetaAccess()); + } + } + + private static ValueNode canonical(KlassLayoutHelperNode klassLayoutHelperNode, GraalHotSpotVMConfig config, ValueNode klass, Stamp stamp, ConstantReflectionProvider constantReflection, + MetaAccessProvider metaAccess) { + KlassLayoutHelperNode self = klassLayoutHelperNode; + if (klass.isConstant()) { + if (!klass.asConstant().isDefaultForKind()) { + Constant constant = stamp.readConstant(constantReflection.getMemoryAccessProvider(), klass.asConstant(), config.klassLayoutHelperOffset); + return ConstantNode.forConstant(stamp, constant, metaAccess); + } + } + if (klass instanceof LoadHubNode) { + LoadHubNode hub = (LoadHubNode) klass; + Stamp hubStamp = hub.getValue().stamp(); + if (hubStamp instanceof ObjectStamp) { + ObjectStamp ostamp = (ObjectStamp) hubStamp; + HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type(); + if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) { + // The layout for all object arrays is the same. + Constant constant = stamp.readConstant(constantReflection.getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset); + return ConstantNode.forConstant(stamp, constant, metaAccess); } } - if (klass instanceof LoadHubNode) { - LoadHubNode hub = (LoadHubNode) klass; - Stamp hubStamp = hub.getValue().stamp(); - if (hubStamp instanceof ObjectStamp) { - ObjectStamp ostamp = (ObjectStamp) hubStamp; - HotSpotResolvedObjectType type = (HotSpotResolvedObjectType) ostamp.type(); - if (type != null && type.isArray() && !type.getComponentType().isPrimitive()) { - // The layout for all object arrays is the same. - Constant constant = stamp().readConstant(tool.getConstantReflection().getMemoryAccessProvider(), type.klass(), config.klassLayoutHelperOffset); - return ConstantNode.forConstant(stamp(), constant, tool.getMetaAccess()); - } - } - } - return this; } + if (self == null) { + self = new KlassLayoutHelperNode(config, klass); + } + return self; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/LoadExceptionObjectSnippets.java Thu Apr 06 14:31:32 2017 -0700 @@ -35,8 +35,10 @@ import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; +import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.java.LoadExceptionObjectNode; @@ -52,6 +54,7 @@ import jdk.vm.ci.code.BytecodeFrame; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.TargetDescription; +import jdk.vm.ci.meta.ResolvedJavaType; /** * Snippet for loading the exception object at the start of an exception dispatcher. @@ -76,15 +79,19 @@ public static class Templates extends AbstractTemplates { private final SnippetInfo loadException = snippet(LoadExceptionObjectSnippets.class, "loadException", EXCEPTION_OOP_LOCATION, EXCEPTION_PC_LOCATION); + private final HotSpotWordTypes wordTypes; public Templates(OptionValues options, HotSpotProviders providers, TargetDescription target) { super(options, providers, providers.getSnippetReflection(), target); + this.wordTypes = providers.getWordTypes(); } public void lower(LoadExceptionObjectNode loadExceptionObject, HotSpotRegistersProvider registers, LoweringTool tool) { StructuredGraph graph = loadExceptionObject.graph(); if (LoadExceptionObjectInVM.getValue(graph.getOptions())) { - ReadRegisterNode thread = graph.add(new ReadRegisterNode(registers.getThreadRegister(), true, false)); + ResolvedJavaType wordType = providers.getMetaAccess().lookupJavaType(Word.class); + Stamp stamp = wordTypes.getWordStamp(wordType); + ReadRegisterNode thread = graph.add(new ReadRegisterNode(stamp, registers.getThreadRegister(), true, false)); graph.addBeforeFixed(loadExceptionObject, thread); ForeignCallNode loadExceptionC = graph.add(new ForeignCallNode(providers.getForeignCalls(), LOAD_AND_CLEAR_EXCEPTION, thread)); loadExceptionC.setStateAfter(loadExceptionObject.stateAfter()); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java Thu Apr 06 14:31:32 2017 -0700 @@ -56,7 +56,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.writeTlabTop; import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocations; import static org.graalvm.compiler.hotspot.replacements.HotspotSnippetsOptions.ProfileAllocationsContext; -import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCast; +import static org.graalvm.compiler.nodes.PiArrayNode.piArrayCastToSnippetReplaceeStamp; import static org.graalvm.compiler.nodes.PiNode.piCastToSnippetReplaceeStamp; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY; import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY; @@ -226,7 +226,7 @@ return verifyOop(result); } - @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true) public static native Object newInstance(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub); @Snippet @@ -307,7 +307,7 @@ @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext, @ConstantParameter OptionValues options, @ConstantParameter Counters counters) { Object result = allocateArrayImpl(hub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, false, options, counters); - return piArrayCast(verifyOop(result), length); + return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length); } private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, Register threadRegister, @@ -334,20 +334,20 @@ return result; } - @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true) public static native Object newArray(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length, boolean fillContents); public static final ForeignCallDescriptor DYNAMIC_NEW_ARRAY = new ForeignCallDescriptor("dynamic_new_array", Object.class, Class.class, int.class); public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class); - @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true) public static native Object dynamicNewArrayStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType, int length); public static Object dynamicNewInstanceStub(Class elementType) { return dynamicNewInstanceStubCall(DYNAMIC_NEW_INSTANCE, elementType); } - @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true) public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class elementType); @Snippet @@ -396,7 +396,7 @@ int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG); Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", true, options, counters); - return piArrayCast(verifyOop(result), length); + return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length); } /** @@ -418,7 +418,7 @@ return newmultiarray(hubPIC, rank, dimensions); } - @NodeIntrinsic(value = ForeignCallNode.class, returnStampIsNonNull = true) + @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = true) public static native Object newArrayCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int rank, Word dims); /** diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ReflectionGetCallerClassNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -80,7 +80,7 @@ /** * If inlining is deep enough this method returns a {@link ConstantNode} of the caller class by - * walking the the stack. + * walking the stack. * * @param metaAccess * @return ConstantNode of the caller class, or null diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,8 +22,6 @@ */ package org.graalvm.compiler.hotspot.replacements.arraycopy; -import jdk.vm.ci.meta.JavaKind; - import static org.graalvm.compiler.core.common.LocationIdentity.any; import org.graalvm.compiler.core.common.LocationIdentity; @@ -33,11 +31,12 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.Lowerable; import org.graalvm.compiler.nodes.spi.LoweringTool; -import org.graalvm.compiler.nodes.spi.Virtualizable; import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode; +import jdk.vm.ci.meta.JavaKind; + @NodeInfo -public final class ArrayCopyNode extends BasicArrayCopyNode implements Virtualizable, Lowerable { +public final class ArrayCopyNode extends BasicArrayCopyNode implements Lowerable { public static final NodeClass TYPE = NodeClass.create(ArrayCopyNode.class); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Thu Apr 06 14:31:32 2017 -0700 @@ -63,6 +63,7 @@ import org.graalvm.compiler.nodes.java.ArrayLengthNode; import org.graalvm.compiler.nodes.spi.LoweringTool; import org.graalvm.compiler.nodes.type.StampTool; +import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.replacements.SnippetCounter; import org.graalvm.compiler.replacements.SnippetCounter.Group; @@ -628,7 +629,7 @@ private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { StructuredGraph graph = arraycopy.graph(); SnippetTemplate template = template(args); - UnmodifiableEconomicMap replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args); + UnmodifiableEconomicMap replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false); for (Node originalNode : replacements.getKeys()) { if (originalNode instanceof Invoke) { Invoke invoke = (Invoke) replacements.get(originalNode); @@ -643,17 +644,18 @@ if (arraycopy.stateDuring() != null) { newInvoke.setStateDuring(arraycopy.stateDuring()); } else { - assert arraycopy.stateAfter() != null; + assert arraycopy.stateAfter() != null : arraycopy; newInvoke.setStateAfter(arraycopy.stateAfter()); } graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke); } else if (originalNode instanceof ArrayCopySlowPathNode) { ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode); - assert arraycopy.stateAfter() != null; - slowPath.setStateAfter(arraycopy.stateAfter()); + assert arraycopy.stateAfter() != null : arraycopy; + assert slowPath.stateAfter() == arraycopy.stateAfter(); slowPath.setBci(arraycopy.getBci()); } } + GraphUtil.killCFG(arraycopy); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ExceptionHandlerStub.java Thu Apr 06 14:31:32 2017 -0700 @@ -157,6 +157,6 @@ public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_PC = newDescriptor(ExceptionHandlerStub.class, "exceptionHandlerForPc", Word.class, Word.class); - @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + @NodeIntrinsic(value = StubForeignCallNode.class) public static native Word exceptionHandlerForPc(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForPc, Word thread); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/ForeignCallStub.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,6 +32,7 @@ import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.debug.Debug; @@ -57,6 +58,7 @@ import jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider; import jdk.vm.ci.hotspot.HotSpotSignature; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.MetaAccessProvider; @@ -241,17 +243,13 @@ } kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result)); - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Initial stub graph"); - } + Debug.dump(Debug.VERBOSE_LEVEL, graph, "Initial stub graph"); kit.inlineInvokes(); new RemoveValueProxyPhase().apply(graph); - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Stub graph before compilation"); - } + Debug.dump(Debug.VERBOSE_LEVEL, graph, "Stub graph before compilation"); return graph; } @@ -269,13 +267,14 @@ } private StubForeignCallNode createTargetCall(GraphKit kit, ParameterNode[] params, ReadRegisterNode thread) { + Stamp stamp = StampFactory.forKind(JavaKind.fromJavaClass(target.getDescriptor().getResultType())); if (prependThread) { ValueNode[] targetArguments = new ValueNode[1 + params.length]; targetArguments[0] = thread; System.arraycopy(params, 0, targetArguments, 1, params.length); - return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), targetArguments)); + return kit.append(new StubForeignCallNode(providers.getForeignCalls(), stamp, target.getDescriptor(), targetArguments)); } else { - return kit.append(new StubForeignCallNode(providers.getForeignCalls(), target.getDescriptor(), params)); + return kit.append(new StubForeignCallNode(providers.getForeignCalls(), stamp, target.getDescriptor(), params)); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,7 @@ import static org.graalvm.compiler.core.GraalCompiler.emitBackEnd; import static org.graalvm.compiler.core.GraalCompiler.emitFrontEnd; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugStubsAndSnippets; import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER; import static org.graalvm.util.CollectionsUtil.allMatch; @@ -35,6 +36,7 @@ import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.debug.Debug; import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.DebugConfig; import org.graalvm.compiler.debug.internal.DebugScope; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; @@ -176,7 +178,8 @@ @SuppressWarnings("try") public synchronized InstalledCode getCode(final Backend backend) { if (code == null) { - try (Scope d = Debug.sandbox("CompilingStub", DebugScope.getConfig(), providers.getCodeCache(), debugScopeContext())) { + DebugConfig config = DebugStubsAndSnippets.getValue(options) ? DebugScope.getConfig() : Debug.silentConfig(); + try (Scope d = Debug.sandbox("CompilingStub", config, providers.getCodeCache(), debugScopeContext())) { CodeCacheProvider codeCache = providers.getCodeCache(); CompilationResult compResult = buildCompilationResult(backend); @@ -184,7 +187,7 @@ assert destroyedCallerRegisters != null; // Add a GeneratePIC check here later, we don't want to install // code if we don't have a corresponding VM global symbol. - HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(null, null, compResult); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult); code = codeCache.installCode(null, compiledCode, null, null, false); } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/UnwindExceptionToCallerStub.java Thu Apr 06 14:31:32 2017 -0700 @@ -122,6 +122,6 @@ public static final ForeignCallDescriptor EXCEPTION_HANDLER_FOR_RETURN_ADDRESS = newDescriptor(UnwindExceptionToCallerStub.class, "exceptionHandlerForReturnAddress", Word.class, Word.class, Word.class); - @NodeIntrinsic(value = StubForeignCallNode.class, setStampFromReturnType = true) + @NodeIntrinsic(value = StubForeignCallNode.class) public static native Word exceptionHandlerForReturnAddress(@ConstantNodeParameter ForeignCallDescriptor exceptionHandlerForReturnAddress, Word thread, Word returnAddress); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Thu Apr 06 14:31:32 2017 -0700 @@ -1051,8 +1051,8 @@ public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options) { BciBlockMapping map = new BciBlockMapping(code); map.build(stream, options); - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { - Debug.dump(Debug.INFO_LOG_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)")); + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { + Debug.dump(Debug.INFO_LEVEL, map, code.getMethod().format("After block building %f %R %H.%n(%P)")); } return map; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Thu Apr 06 14:31:32 2017 -0700 @@ -247,7 +247,6 @@ import static org.graalvm.compiler.core.common.type.StampFactory.objectNonNull; import static org.graalvm.compiler.debug.GraalError.guarantee; import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; -import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding; import static org.graalvm.compiler.java.BytecodeParserOptions.TraceBytecodeParserLevel; import static org.graalvm.compiler.java.BytecodeParserOptions.TraceInlineDuringParsing; import static org.graalvm.compiler.java.BytecodeParserOptions.TraceParserPlugins; @@ -272,8 +271,8 @@ import org.graalvm.compiler.bytecode.Bytes; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; +import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; @@ -770,10 +769,6 @@ for (BciBlock block : blocks) { processBlock(block); } - - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue(options) && this.beforeReturnNode != startInstruction) { - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Bytecodes parsed: %s.%s", method.getDeclaringClass().getUnqualifiedName(), method.getName()); - } } } @@ -890,7 +885,7 @@ */ protected void handleUnresolvedCheckCast(JavaType type, ValueNode object) { assert !graphBuilderConfig.eagerResolving(); - append(new FixedGuardNode(graph.unique(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); + append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), Unresolved, InvalidateRecompile)); frameState.push(JavaKind.Object, appendConstant(JavaConstant.NULL_POINTER)); } @@ -902,7 +897,7 @@ assert !graphBuilderConfig.eagerResolving(); AbstractBeginNode successor = graph.add(new BeginNode()); DeoptimizeNode deopt = graph.add(new DeoptimizeNode(InvalidateRecompile, Unresolved)); - append(new IfNode(graph.unique(IsNullNode.create(object)), successor, deopt, 1)); + append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(object)), successor, deopt, 1)); lastInstr = successor; frameState.push(JavaKind.Int, appendConstant(JavaConstant.INT_0)); } @@ -1060,15 +1055,15 @@ } protected ValueNode genNegateOp(ValueNode x) { - return (new NegateNode(x)); + return NegateNode.create(x); } protected ValueNode genLeftShift(ValueNode x, ValueNode y) { - return new LeftShiftNode(x, y); + return LeftShiftNode.create(x, y); } protected ValueNode genRightShift(ValueNode x, ValueNode y) { - return new RightShiftNode(x, y); + return RightShiftNode.create(x, y); } protected ValueNode genUnsignedRightShift(ValueNode x, ValueNode y) { @@ -1123,11 +1118,11 @@ } protected LogicNode genIntegerEquals(ValueNode x, ValueNode y) { - return IntegerEqualsNode.create(x, y, constantReflection); + return IntegerEqualsNode.create(x, y); } protected LogicNode genIntegerLessThan(ValueNode x, ValueNode y) { - return IntegerLessThanNode.create(x, y, constantReflection); + return IntegerLessThanNode.create(x, y); } protected ValueNode genUnique(ValueNode x) { @@ -1146,8 +1141,8 @@ genInfoPointNode(InfopointReason.BYTECODE_POSITION, null); ValueNode exception = frameState.pop(JavaKind.Object); - FixedGuardNode nullCheck = append(new FixedGuardNode(graph.unique(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true)); - PiNode nonNullException = graph.unique(new PiNode(exception, exception.stamp().join(objectNonNull()), nullCheck)); + FixedGuardNode nullCheck = append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true)); + ValueNode nonNullException = graph.maybeAddOrUnique(PiNode.create(exception, exception.stamp().join(objectNonNull()), nullCheck)); lastInstr.setNext(handleException(nonNullException, bci())); } @@ -1172,7 +1167,7 @@ } protected ValueNode genConditional(ValueNode x) { - return new ConditionalNode((LogicNode) x); + return ConditionalNode.create((LogicNode) x); } protected NewInstanceNode createNewInstance(ResolvedJavaType type, boolean fillContents) { @@ -1190,9 +1185,11 @@ protected ValueNode genLoadField(ValueNode receiver, ResolvedJavaField field) { StampPair stamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, field.getType(), false); if (stamp == null) { - return LoadFieldNode.create(this.graph.getAssumptions(), receiver, field); + return LoadFieldNode.create(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(), + getAssumptions(), receiver, field, false, false); } else { - return LoadFieldNode.createOverrideStamp(stamp, receiver, field); + return LoadFieldNode.createOverrideStamp(getConstantFieldProvider(), getConstantReflection(), getMetaAccess(), getOptions(), + stamp, receiver, field, false, false); } } @@ -1202,8 +1199,8 @@ } BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class)); AbstractBeginNode falseSucc = graph.add(new BeginNode()); - PiNode nonNullReceiver = graph.unique(new PiNode(receiver, objectNonNull(), falseSucc)); - append(new IfNode(graph.unique(IsNullNode.create(receiver)), exception, falseSucc, 0.01)); + ValueNode nonNullReceiver = graph.addOrUnique(PiNode.create(receiver, objectNonNull(), falseSucc)); + append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, 0.01)); lastInstr = falseSucc; exception.setStateAfter(createFrameState(bci(), exception)); @@ -1215,7 +1212,7 @@ protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) { AbstractBeginNode trueSucc = graph.add(new BeginNode()); BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index)); - append(new IfNode(graph.unique(IntegerBelowNode.create(index, length, constantReflection)), trueSucc, exception, 0.99)); + append(new IfNode(genUnique(IntegerBelowNode.create(index, length)), trueSucc, exception, 0.99)); lastInstr = trueSucc; exception.setStateAfter(createFrameState(bci(), exception)); @@ -1401,11 +1398,6 @@ } if (invokeKind.hasReceiver()) { args[0] = emitExplicitExceptions(args[0]); - - if (args[0].isNullConstant()) { - append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); - return null; - } } InlineInfo inlineInfo = null; @@ -1419,6 +1411,11 @@ return null; } + if (invokeKind.hasReceiver() && args[0].isNullConstant()) { + append(new DeoptimizeNode(InvalidateRecompile, NullCheckException)); + return null; + } + if (!invokeKind.isIndirect() || (UseGuardedIntrinsics.getValue(options) && !GeneratePIC.getValue(options))) { if (tryInvocationPlugin(invokeKind, args, targetMethod, resultType, returnType)) { if (TraceParserPlugins.getValue(options)) { @@ -1611,7 +1608,7 @@ LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver)); LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub)); ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess())); - LogicNode compare = graph.unique(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection)); + LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(Condition.EQ, actual, expected, constantReflection)); JavaTypeProfile profile = null; if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) { @@ -2125,8 +2122,8 @@ JsrScope scope = currentBlock.getJsrScope(); int retAddress = scope.nextReturnAddress(); ConstantNode returnBciNode = getJsrConstant(retAddress); - LogicNode guard = IntegerEqualsNode.create(local, returnBciNode, constantReflection); - guard = graph.unique(guard); + LogicNode guard = IntegerEqualsNode.create(local, returnBciNode); + guard = graph.addOrUniqueWithInputs(guard); append(new FixedGuardNode(guard, JavaSubroutineMismatch, InvalidateReprofile)); if (!successor.getJsrScope().equals(scope.pop())) { throw new JsrNotSupportedBailout("unstructured control flow (ret leaves more than one scope)"); @@ -2656,7 +2653,7 @@ } private DebugCloseable openNodeContext() { - if (graphBuilderConfig.trackNodeSourcePosition() && !parsingIntrinsic()) { + if ((graphBuilderConfig.trackNodeSourcePosition() || Debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) { return graph.withNodeSourcePosition(createBytecodePosition()); } return null; @@ -2776,7 +2773,7 @@ genConstantTargetIf(trueBlock, falseBlock, negate, condition); } else { if (condition.graph() == null) { - condition = graph.unique(condition); + condition = genUnique(condition); } // Need to get probability based on current bci. @@ -3048,7 +3045,7 @@ int nextBCI = stream.nextBCI(); int nextBC = stream.readUByte(nextBCI); - if (nextBC == Bytecodes.GETFIELD) { + if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { stream.next(); genGetField(lookupField(stream.readCPI(), Bytecodes.GETFIELD), value); } else { @@ -3147,7 +3144,7 @@ default: throw shouldNotReachHere(); } - frameState.push(kind, append(v)); + frameState.push(kind, recursiveAppend(v)); } private void genIntegerDivOp(JavaKind kind, int opcode) { @@ -3194,7 +3191,7 @@ default: throw shouldNotReachHere(); } - frameState.push(kind, append(v)); + frameState.push(kind, recursiveAppend(v)); } private void genLogicOp(JavaKind kind, int opcode) { @@ -3217,7 +3214,7 @@ default: throw shouldNotReachHere(); } - frameState.push(kind, append(v)); + frameState.push(kind, recursiveAppend(v)); } private void genCompareOp(JavaKind kind, boolean isUnorderedLess) { @@ -3236,7 +3233,7 @@ if (from != from.getStackKind()) { input = append(genNarrow(input, from.getBitCount())); } - frameState.push(to, append(genSignExtend(input, to.getBitCount()))); + frameState.push(to, recursiveAppend(genSignExtend(input, to.getBitCount()))); } private void genZeroExtend(JavaKind from, JavaKind to) { @@ -3257,7 +3254,7 @@ int delta = getStream().readIncrement(); ValueNode x = frameState.loadLocal(index, JavaKind.Int); ValueNode y = appendConstant(JavaConstant.forInt(delta)); - frameState.storeLocal(index, JavaKind.Int, append(genIntegerAdd(x, y))); + frameState.storeLocal(index, JavaKind.Int, recursiveAppend(genIntegerAdd(x, y))); } private void genIfZero(Condition cond) { @@ -3373,7 +3370,7 @@ castNode = object; } else { FixedGuardNode fixedGuard = append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile, false)); - castNode = append(new PiNode(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard)); + castNode = append(PiNode.create(object, StampFactory.objectNonNull(TypeReference.createExactTrusted(singleType)), fixedGuard)); } } } @@ -3386,7 +3383,7 @@ castNode = object; } else { FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); - castNode = append(new PiNode(object, StampFactory.object(checkedType, nonNull), fixedGuard)); + castNode = append(PiNode.create(object, StampFactory.object(checkedType, nonNull), fixedGuard)); } } frameState.push(JavaKind.Object, castNode); @@ -3431,7 +3428,7 @@ int next = getStream().nextBCI(); int value = getStream().readUByte(next); - if (value == Bytecodes.IFEQ || value == Bytecodes.IFNE) { + if (next <= currentBlock.endBci && (value == Bytecodes.IFEQ || value == Bytecodes.IFNE)) { getStream().next(); BciBlock firstSucc = currentBlock.getSuccessor(0); BciBlock secondSucc = currentBlock.getSuccessor(1); @@ -3678,11 +3675,10 @@ } private void genGetStatic(JavaField field) { - if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - handleUnresolvedLoadField(field, null); + ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, null); + if (resolvedField == null) { return; } - ResolvedJavaField resolvedField = (ResolvedJavaField) field; if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { graph.recordField(resolvedField); @@ -3712,13 +3708,39 @@ frameState.push(field.getJavaKind(), append(genLoadField(null, resolvedField))); } + private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) { + if (field instanceof ResolvedJavaField) { + ResolvedJavaField resolvedField = (ResolvedJavaField) field; + if (resolvedField.getDeclaringClass().isInitialized()) { + return resolvedField; + } + /* + * Static fields have initialization semantics but may be safely accessed under certain + * conditions while the class is being initialized. Executing in the clinit or init of + * classes which are subtypes of the field holder are sure to be running in a context + * where the access is safe. + */ + if (resolvedField.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { + if (method.isClassInitializer() || method.isConstructor()) { + return resolvedField; + } + } + } + if (value == null) { + handleUnresolvedLoadField(field, null); + } else { + handleUnresolvedStoreField(field, value, null); + + } + return null; + } + private void genPutStatic(JavaField field) { ValueNode value = frameState.pop(field.getJavaKind()); - if (!(field instanceof ResolvedJavaField) || !((ResolvedJavaType) field.getDeclaringClass()).isInitialized()) { - handleUnresolvedStoreField(field, value, null); + ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value); + if (resolvedField == null) { return; } - ResolvedJavaField resolvedField = (ResolvedJavaField) field; if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { graph.recordField(resolvedField); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java Thu Apr 06 14:31:32 2017 -0700 @@ -52,9 +52,6 @@ @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) public static final OptionKey InlineDuringParsingMaxDepth = new OptionKey<>(10); - @Option(help = "Dump graphs after non-trivial changes during bytecode parsing.", type = OptionType.Debug) - public static final OptionKey DumpDuringGraphBuilding = new OptionKey<>(false); - @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug) public static final OptionKey HideSubstitutionStates = new OptionKey<>(false); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,6 +22,11 @@ */ package org.graalvm.compiler.lir.sparc; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static jdk.vm.ci.sparc.SPARC.CPU; +import static jdk.vm.ci.sparc.SPARC.g0; +import static jdk.vm.ci.sparc.SPARCKind.WORD; +import static jdk.vm.ci.sparc.SPARCKind.XWORD; import static org.graalvm.compiler.asm.sparc.SPARCAssembler.BPCC; import static org.graalvm.compiler.asm.sparc.SPARCAssembler.CBCOND; import static org.graalvm.compiler.asm.sparc.SPARCAssembler.FBPCC; @@ -68,19 +73,14 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; import static org.graalvm.compiler.lir.sparc.SPARCMove.const2reg; import static org.graalvm.compiler.lir.sparc.SPARCOP3Op.emitOp3; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static jdk.vm.ci.sparc.SPARC.CPU; -import static jdk.vm.ci.sparc.SPARC.g0; -import static jdk.vm.ci.sparc.SPARCKind.WORD; -import static jdk.vm.ci.sparc.SPARCKind.XWORD; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; + import org.graalvm.compiler.asm.Assembler; import org.graalvm.compiler.asm.Assembler.LabelHint; import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.asm.sparc.SPARCAssembler; import org.graalvm.compiler.asm.sparc.SPARCAssembler.BranchPredict; import org.graalvm.compiler.asm.sparc.SPARCAssembler.CC; @@ -98,8 +98,8 @@ import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure; import org.graalvm.compiler.lir.Variable; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence; -import org.graalvm.util.EconomicMap; import jdk.vm.ci.code.Register; import jdk.vm.ci.meta.AllocatableValue; @@ -159,6 +159,7 @@ public CompareBranchOp(AllocatableValue x, Value y, Condition condition, LabelRef trueDestination, LabelRef falseDestination, SPARCKind kind, boolean unorderedIsTrue, double trueDestinationProbability) { super(TYPE, SIZE); + assert x.getPlatformKind() == y.getPlatformKind() : String.format("PlatformKind of x must match PlatformKind of y. %s!=%s", x.getPlatformKind(), y.getPlatformKind()); this.x = x; this.y = y; this.trueDestination = trueDestination; @@ -250,6 +251,7 @@ * @return true if the branch could be emitted */ private boolean emitShortCompareBranch(CompilationResultBuilder crb, SPARCMacroAssembler masm) { + boolean isLong = kind == SPARCKind.XWORD; ConditionFlag actualConditionFlag = conditionFlag; Label actualTrueTarget = trueDestination.label(); Label actualFalseTarget = falseDestination.label(); @@ -274,7 +276,7 @@ actualFalseTarget = tmpTarget; } } - emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag); + emitCBCond(masm, x, y, actualTrueTarget, actualConditionFlag, isLong); if (needJump) { masm.jmp(actualFalseTarget); masm.nop(); @@ -282,16 +284,24 @@ return true; } - private void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag) { + private static void emitCBCond(SPARCMacroAssembler masm, Value actualX, Value actualY, Label actualTrueTarget, ConditionFlag cFlag, boolean isLong) { PlatformKind xKind = actualX.getPlatformKind(); - boolean isLong = kind == SPARCKind.XWORD; + Register rs1 = asRegister(actualX, xKind); if (isJavaConstant(actualY)) { JavaConstant c = asJavaConstant(actualY); long constantY = c.isNull() ? 0 : c.asLong(); - assert NumUtil.isInt(constantY); - CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), (int) constantY, actualTrueTarget); + try (ScratchRegister scratch = masm.getScratchRegister()) { + if (SPARCMacroAssembler.isSimm5(constantY)) { + CBCOND.emit(masm, cFlag, isLong, rs1, (int) constantY, actualTrueTarget); + } else { // !simm5 + Register rs2 = scratch.getRegister(); + masm.setx(constantY, rs2, false); + CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget); + } + } } else { - CBCOND.emit(masm, cFlag, isLong, asRegister(actualX, xKind), asRegister(actualY, xKind), actualTrueTarget); + Register rs2 = asRegister(actualY, xKind); + CBCOND.emit(masm, cFlag, isLong, rs1, rs2, actualTrueTarget); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Thu Apr 06 14:31:32 2017 -0700 @@ -217,7 +217,7 @@ /** * Calculates the entry and exit states for all basic blocks. * - * @return Returns true on success and false if the the control flow is too complex. + * @return Returns true on success and false if the control flow is too complex. */ @SuppressWarnings("try") private boolean solveDataFlow(LIR lir) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/SwitchStrategy.java Thu Apr 06 14:31:32 2017 -0700 @@ -46,7 +46,7 @@ private interface SwitchClosure { /** * Generates a conditional or unconditional jump. The jump will be unconditional if - * condition is null. If defaultTarget is true, then the jump will go the the default. + * condition is null. If defaultTarget is true, then the jump will go the default. * * @param index Index of the value and the jump target (only used if defaultTarget == false) * @param condition The condition on which to jump (can be null) diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java Thu Apr 06 14:31:32 2017 -0700 @@ -750,11 +750,11 @@ } } } - Debug.dump(Debug.BASIC_LOG_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label); + Debug.dump(Debug.BASIC_LEVEL, new LinearScanIntervalDumper(Arrays.copyOf(intervals, intervalsSize)), label); } public void printLir(String label, @SuppressWarnings("unused") boolean hirValid) { - Debug.dump(Debug.INFO_LOG_LEVEL, ir, label); + Debug.dump(Debug.INFO_LEVEL, ir, label); } boolean verify() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -110,12 +110,12 @@ interval.setSpillState(SpillState.StoreAtDefinition); return; } - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (initial): %s", spillBlock); + Debug.log(Debug.VERBOSE_LEVEL, "Spill block candidate (initial): %s", spillBlock); // move out of loops if (defBlock.getLoopDepth() < spillBlock.getLoopDepth()) { spillBlock = moveSpillOutOfLoop(defBlock, spillBlock); } - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock); + Debug.log(Debug.VERBOSE_LEVEL, "Spill block candidate (after loop optimizaton): %s", spillBlock); /* * The spill block is the begin of the first split child (aka the value is on the @@ -134,7 +134,7 @@ spillBlock = dom; } if (defBlock.equals(spillBlock)) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition is the best choice: %s", defBlock); + Debug.log(Debug.VERBOSE_LEVEL, "Definition is the best choice: %s", defBlock); // definition is the best choice interval.setSpillState(SpillState.StoreAtDefinition); return; @@ -146,7 +146,7 @@ } if (defBlock.probability() <= spillBlock.probability()) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock, + Debug.log(Debug.VERBOSE_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock, spillBlock.probability()); // better spill block has the same probability -> do nothing interval.setSpillState(SpillState.StoreAtDefinition); @@ -164,7 +164,7 @@ AllocatableValue fromLocation = interval.getSplitChildAtOpId(spillOpId, OperandMode.DEF, allocator).location(); AllocatableValue toLocation = LinearScan.canonicalSpillOpr(interval); LIRInstruction move = allocator.getSpillMoveFactory().createMove(toLocation, fromLocation); - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Insert spill move %s", move); + Debug.log(Debug.VERBOSE_LEVEL, "Insert spill move %s", move); move.setId(LinearScan.DOMINATOR_SPILL_MOVE_ID); /* * We can use the insertion buffer directly because we always insert at position 1. diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanWalker.java Thu Apr 06 14:31:32 2017 -0700 @@ -861,7 +861,7 @@ * errors */ allocator.assignSpillSlot(interval); - Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description); + Debug.dump(Debug.INFO_LEVEL, allocator.getLIR(), description); allocator.printIntervals(description); throw new OutOfRegistersException("LinearScan: no register found", description); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/GlobalLivenessAnalysisPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -65,7 +65,7 @@ private final class Analyser { - private static final int LOG_LEVEL = Debug.INFO_LOG_LEVEL; + private static final int LOG_LEVEL = Debug.INFO_LEVEL; /** * Bit map specifying which operands are live upon entry to this block. These are values diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceBuilderPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -64,8 +64,8 @@ // @formatter:on } - private static final int TRACE_LOG_LEVEL = 1; - public static final int TRACE_DUMP_LEVEL = 3; + private static final int TRACE_LOG_LEVEL = Debug.BASIC_LEVEL; + public static final int TRACE_DUMP_LEVEL = Debug.VERBOSE_LEVEL; @Override protected void run(TargetDescription target, LIRGenerationResult lirGenRes, AllocationContext context) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/TraceRegisterAllocationPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -89,7 +89,7 @@ final TraceRegisterAllocationPolicy plan = DefaultTraceRegisterAllocationPolicy.allocationPolicy(target, lirGenRes, spillMoveFactory, registerAllocationConfig, cachedStackSlots, resultTraces, neverSpillConstant, livenessInfo, lir.getOptions()); - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "Before TraceRegisterAllocation"); + Debug.dump(Debug.INFO_LEVEL, lir, "Before TraceRegisterAllocation"); try (Scope s0 = Debug.scope("AllocateTraces", resultTraces, livenessInfo)) { for (Trace trace : resultTraces.getTraces()) { tracesCounter.increment(); @@ -101,9 +101,9 @@ } catch (Throwable e) { throw Debug.handle(e); } - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { unnumberInstructions(lir); - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After trace allocation"); + Debug.dump(Debug.INFO_LEVEL, lir, "After trace allocation"); } TRACE_GLOBAL_MOVE_RESOLUTION_PHASE.apply(target, lirGenRes, traceContext); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -1073,7 +1073,7 @@ } } } - Debug.dump(Debug.INFO_LOG_LEVEL, this, label); + Debug.dump(Debug.INFO_LEVEL, this, label); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java Thu Apr 06 14:31:32 2017 -0700 @@ -954,7 +954,7 @@ * avoid errors */ allocator.assignSpillSlot(interval); - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { dumpLIRAndIntervals(description); } throw new OutOfRegistersException("LinearScan: no register found", description); @@ -991,7 +991,7 @@ } protected void dumpLIRAndIntervals(String description) { - Debug.dump(Debug.INFO_LOG_LEVEL, allocator.getLIR(), description); + Debug.dump(Debug.INFO_LEVEL, allocator.getLIR(), description); allocator.printIntervals(description); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Thu Apr 06 14:31:32 2017 -0700 @@ -461,7 +461,7 @@ if (block == null) { return; } - boolean emitComment = Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL) || PrintLIRWithAssembly.getValue(getOptions()); + boolean emitComment = Debug.isDumpEnabled(Debug.BASIC_LEVEL) || PrintLIRWithAssembly.getValue(getOptions()); if (emitComment) { blockComment(String.format("block B%d %s", block.getId(), block.getLoop())); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java Thu Apr 06 14:31:32 2017 -0700 @@ -214,7 +214,7 @@ phiConstantsSkipped.increment(); } phiConstants.set(var.index); - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Removing phi variable: %s", var); + Debug.log(Debug.VERBOSE_LEVEL, "Removing phi variable: %s", var); } } else { assert defined.get(var.index) : "phi but not defined? " + var; @@ -291,7 +291,7 @@ // no better solution found materializeAtDefinitionSkipped.increment(); } - Debug.dump(Debug.INFO_LOG_LEVEL, constTree, "ConstantTree for %s", tree.getVariable()); + Debug.dump(Debug.DETAILED_LEVEL, constTree, "ConstantTree for %s", tree.getVariable()); } private void createLoads(DefUseTree tree, ConstantTree constTree, AbstractBlockBase startBlock) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java Thu Apr 06 14:31:32 2017 -0700 @@ -72,19 +72,19 @@ worklist.offerLast(startBlock); while (!worklist.isEmpty()) { AbstractBlockBase block = worklist.pollLast(); - try (Indent i = Debug.logAndIndent(Debug.VERBOSE_LOG_LEVEL, "analyze: %s", block)) { + try (Indent i = Debug.logAndIndent(Debug.VERBOSE_LEVEL, "analyze: %s", block)) { assert block != null : "worklist is empty!"; assert isMarked(block) : "Block not part of the dominator tree: " + block; if (isLeafBlock(block)) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "leaf block"); + Debug.log(Debug.VERBOSE_LEVEL, "leaf block"); leafCost(block); continue; } if (!visited.get(block.getId())) { // if not yet visited (and not a leaf block) process all children first! - Debug.log(Debug.VERBOSE_LOG_LEVEL, "not marked"); + Debug.log(Debug.VERBOSE_LEVEL, "not marked"); worklist.offerLast(block); AbstractBlockBase dominated = block.getFirstDominated(); while (dominated != null) { @@ -93,7 +93,7 @@ } visited.set(block.getId()); } else { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "marked"); + Debug.log(Debug.VERBOSE_LEVEL, "marked"); // otherwise, process block process(block); } @@ -162,7 +162,7 @@ private void filteredPush(Deque> worklist, AbstractBlockBase block) { if (isMarked(block)) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "adding %s to the worklist", block); + Debug.log(Debug.VERBOSE_LEVEL, "adding %s to the worklist", block); worklist.offerLast(block); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/LIRPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -113,8 +113,8 @@ try (Scope s = Debug.scope(getName(), this)) { try (DebugCloseable a = timer.start(); DebugCloseable c = memUseTracker.start()) { run(target, lirGenRes, context); - if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, lirGenRes.getLIR(), "%s", getName()); + if (dumpLIR && Debug.isDumpEnabled(Debug.BASIC_LEVEL)) { + Debug.dump(Debug.BASIC_LEVEL, lirGenRes.getLIR(), "%s", getName()); } } } catch (Throwable e) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/ssa/SSAVerifier.java Thu Apr 06 14:31:32 2017 -0700 @@ -87,7 +87,7 @@ doBlock(pred); } } - try (Indent indent = Debug.logAndIndent(Debug.INFO_LOG_LEVEL, "handle block %s", b)) { + try (Indent indent = Debug.logAndIndent(Debug.INFO_LEVEL, "handle block %s", b)) { assert verifyBlock(b); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java Thu Apr 06 14:31:32 2017 -0700 @@ -131,7 +131,7 @@ @SuppressWarnings("try") private void allocate() { - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot numbering"); + Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot numbering"); long currentFrameSize = StackSlotAllocatorUtil.allocatedFramesize.isEnabled() ? frameMapBuilder.getFrameMap().currentFrameSize() : 0; EconomicSet usePos; @@ -145,14 +145,14 @@ assert verifyIntervals(); } } - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { dumpIntervals("Before stack slot allocation"); } // step 4: allocate stack slots try (DebugCloseable t = AllocateSlotsTimer.start()) { allocateStackSlots(); } - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { dumpIntervals("After stack slot allocation"); } @@ -160,7 +160,7 @@ try (DebugCloseable t = AssignSlotsTimer.start()) { assignStackSlots(usePos); } - Debug.dump(Debug.INFO_LOG_LEVEL, lir, "After StackSlot assignment"); + Debug.dump(Debug.INFO_LEVEL, lir, "After StackSlot assignment"); if (StackSlotAllocatorUtil.allocatedFramesize.isEnabled()) { StackSlotAllocatorUtil.allocatedFramesize.add(frameMapBuilder.getFrameMap().currentFrameSize() - currentFrameSize); } @@ -256,13 +256,13 @@ */ location = StackSlot.get(current.kind(), slot.getRawOffset(), slot.getRawAddFrameSize()); StackSlotAllocatorUtil.reusedSlots.increment(); - Debug.log(Debug.BASIC_LOG_LEVEL, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot); + Debug.log(Debug.BASIC_LEVEL, "Reuse stack slot %s (reallocated from %s) for virtual stack slot %s", location, slot, virtualSlot); } else { // Allocate new stack slot. location = frameMapBuilder.getFrameMap().allocateSpillSlot(virtualSlot.getValueKind()); StackSlotAllocatorUtil.virtualFramesize.add(frameMapBuilder.getFrameMap().spillSlotSize(virtualSlot.getValueKind())); StackSlotAllocatorUtil.allocatedSlots.increment(); - Debug.log(Debug.BASIC_LOG_LEVEL, "New stack slot %s for virtual stack slot %s", location, virtualSlot); + Debug.log(Debug.BASIC_LEVEL, "New stack slot %s for virtual stack slot %s", location, virtualSlot); } } Debug.log("Allocate location %s for interval %s", location, current); @@ -434,7 +434,7 @@ } private void dumpIntervals(String label) { - Debug.dump(Debug.INFO_LOG_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label); + Debug.dump(Debug.INFO_LEVEL, new StackIntervalDumper(Arrays.copyOf(stackSlotMap, stackSlotMap.length)), label); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopFullUnrollPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -54,7 +54,7 @@ Debug.log("FullUnroll %s", loop); LoopTransformations.fullUnroll(loop, context, canonicalizer); FULLY_UNROLLED_LOOPS.increment(); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "FullUnroll %s", loop); + Debug.dump(Debug.DETAILED_LEVEL, graph, "FullUnroll %s", loop); peeled = true; break; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPeelingPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -45,7 +45,7 @@ if (getPolicies().shouldPeel(loop, data.getCFG(), context.getMetaAccess())) { Debug.log("Peeling %s", loop); LoopTransformations.peel(loop); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "Peeling %s", loop); + Debug.dump(Debug.DETAILED_LEVEL, graph, "Peeling %s", loop); } } data.deleteUnusedNodes(); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopUnswitchingPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -61,7 +61,7 @@ logUnswitch(loop, controlSplits); } LoopTransformations.unswitch(loop, controlSplits); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "After unswitch %s", controlSplits); + Debug.dump(Debug.DETAILED_LEVEL, graph, "After unswitch %s", controlSplits); UNSWITCHED.increment(); unswitched = true; break; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopsDataTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -77,8 +77,8 @@ Assert.assertEquals(1, loops.outerFirst().get(0).loop().getDepth()); Assert.assertEquals(1, loops.outerFirst().get(1).loop().getDepth()); Assert.assertEquals(2, loops.outerFirst().get(2).loop().getDepth()); - Assert.assertEquals(2, loops.outerFirst().get(3).loop().getDepth()); - Assert.assertEquals(3, loops.outerFirst().get(4).loop().getDepth()); + Assert.assertEquals(3, loops.outerFirst().get(3).loop().getDepth()); + Assert.assertEquals(2, loops.outerFirst().get(4).loop().getDepth()); Assert.assertEquals(2, loops.outerFirst().get(5).loop().getDepth()); Assert.assertEquals(3, loops.outerFirst().get(6).loop().getDepth()); Assert.assertEquals(4, loops.outerFirst().get(7).loop().getDepth()); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedOffsetInductionVariable.java Thu Apr 06 14:31:32 2017 -0700 @@ -90,7 +90,7 @@ @Override public ValueNode strideNode() { if (value instanceof SubNode && base.valueNode() == value.getY()) { - return graph().unique(new NegateNode(base.strideNode())); + return graph().addOrUniqueWithInputs(NegateNode.create(base.strideNode())); } return base.strideNode(); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/micro/benchmarks/ArrayListBenchmark.java Thu Apr 06 14:31:32 2017 -0700 @@ -24,13 +24,14 @@ import java.util.ArrayList; +import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; -import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark; - /** * Benchmarks cost of ArrayList. */ @@ -40,7 +41,7 @@ @State(Scope.Benchmark) public static class ThreadState { - ArrayList list = new ArrayList<>(N); + final ArrayList list = new ArrayList<>(N); } @Benchmark @@ -61,9 +62,20 @@ state.list.clear(); } + @State(Scope.Benchmark) + public static class ClearedThreadState { + final ArrayList list = new ArrayList<>(N); + + // We don't want to measure the cost of list clearing + @Setup(Level.Invocation) + public void beforeInvocation() { + list.clear(); + } + } + @Benchmark @Warmup(iterations = 20) - public void addNull(ThreadState state) { + public void addNull(ClearedThreadState state) { for (int i = 0; i < N; ++i) { state.list.add(null); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Thu Apr 06 14:31:32 2017 -0700 @@ -374,13 +374,17 @@ codeEmittingOrder = ComputeBlockOrder.computeCodeEmittingOrder(blocks.length, startBlock); linearScanOrder = ComputeBlockOrder.computeLinearScanOrder(blocks.length, startBlock); - LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder, graph.getOptions()); + LIR lir = new LIR(cfg, linearScanOrder, codeEmittingOrder, getGraphOptions()); FrameMapBuilder frameMapBuilder = request.backend.newFrameMapBuilder(registerConfig); lirGenRes = request.backend.newLIRGenerationResult(graph.compilationId(), lir, frameMapBuilder, request.graph, stub); lirGenTool = request.backend.newLIRGenerator(lirGenRes); nodeLirGen = request.backend.newNodeLIRBuilder(request.graph, lirGenTool); } + protected OptionValues getGraphOptions() { + return graph.getOptions(); + } + private static ControlFlowGraph deepCopy(ControlFlowGraph cfg) { return ControlFlowGraph.compute(cfg.graph, true, true, true, true); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/trace/TraceLSRAIntervalBuildingBench.java Thu Apr 06 14:31:32 2017 -0700 @@ -28,6 +28,7 @@ import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessAnalysisPhase; import org.graalvm.compiler.lir.alloc.trace.GlobalLivenessInfo; import org.graalvm.compiler.lir.alloc.trace.TraceBuilderPhase; +import org.graalvm.compiler.lir.alloc.trace.TraceRegisterAllocationPhase; import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase; import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanLifetimeAnalysisPhase.Analyser; import org.graalvm.compiler.lir.alloc.trace.lsra.TraceLinearScanPhase; @@ -40,6 +41,7 @@ import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.microbenchmarks.graal.GraalBenchmark; import org.graalvm.compiler.microbenchmarks.lir.GraalCompilerState; +import org.graalvm.compiler.options.OptionValues; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Param; @@ -90,6 +92,11 @@ return new LIRSuites(ls.getPreAllocationOptimizationStage(), allocationStage, ls.getPostAllocationOptimizationStage()); } + @Override + protected OptionValues getGraphOptions() { + return new OptionValues(super.getGraphOptions(), TraceRegisterAllocationPhase.Options.TraceRAuseInterTraceHints, false); + } + @Setup(Level.Trial) public void setup() { initializeMethod(); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -86,8 +86,8 @@ /* * Don't allow guards with action None and reason RuntimeConstraint to float. In cases * where 2 guards are testing equivalent conditions they might be lowered at the same - * location. If the guard with the None action is lowered before the the other guard - * then the code will be stuck repeatedly deoptimizing without invalidating the code. + * location. If the guard with the None action is lowered before the other guard then + * the code will be stuck repeatedly deoptimizing without invalidating the code. * Conditional elimination will eliminate the guard if it's truly redundant in this * case. */ diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java Thu Apr 06 14:31:32 2017 -0700 @@ -105,7 +105,7 @@ */ @OptionalInput NodeInputList values; - @OptionalInput(Association) NodeInputList monitorIds; + @Input(Association) NodeInputList monitorIds; @OptionalInput(State) NodeInputList virtualObjectMappings; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -37,8 +37,8 @@ import java.util.SortedMap; import java.util.TreeMap; +import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.PermanentBailoutException; -import org.graalvm.compiler.core.common.Fields; import org.graalvm.compiler.core.common.util.TypeReader; import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader; import org.graalvm.compiler.debug.Debug; @@ -61,9 +61,9 @@ import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind; -import org.graalvm.util.Equivalence; import org.graalvm.util.EconomicMap; import org.graalvm.util.EconomicSet; +import org.graalvm.util.Equivalence; import jdk.vm.ci.code.Architecture; import jdk.vm.ci.meta.DeoptimizationAction; @@ -85,8 +85,6 @@ protected class MethodScope { /** The loop that contains the call. Only non-null during method inlining. */ public final LoopScope callerLoopScope; - /** The target graph where decoded nodes are added to. */ - public final StructuredGraph graph; /** * Mark for nodes that were present before the decoding of this method started. Note that * nodes that were decoded after the mark can still be part of an outer method, since @@ -95,20 +93,19 @@ public final Graph.Mark methodStartMark; /** The encode graph that is decoded. */ public final EncodedGraph encodedGraph; + /** The highest node order id that a fixed node has in the EncodedGraph. */ + public final int maxFixedNodeOrderId; /** Access to the encoded graph. */ public final TypeReader reader; /** The kind of loop explosion to be performed during decoding. */ public final LoopExplosionKind loopExplosion; - /** A list of tasks to run before the method scope is closed. */ - public final List cleanupTasks; /** All return nodes encountered during decoding. */ - public final List returnNodes; - /** The exception unwind node encountered during decoding, or null. */ - public final List unwindNodes; + public final List returnAndUnwindNodes; /** All merges created during loop explosion. */ public final EconomicSet loopExplosionMerges; + /** * The start of explosion, and the merge point for when irreducible loops are detected. Only * used when {@link MethodScope#loopExplosion} is {@link LoopExplosionKind#MERGE_EXPLODE}. @@ -117,16 +114,14 @@ protected MethodScope(LoopScope callerLoopScope, StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) { this.callerLoopScope = callerLoopScope; - this.graph = graph; this.methodStartMark = graph.getMark(); this.encodedGraph = encodedGraph; this.loopExplosion = loopExplosion; - this.cleanupTasks = new ArrayList<>(2); - this.returnNodes = new ArrayList<>(1); - this.unwindNodes = new ArrayList<>(0); + this.returnAndUnwindNodes = new ArrayList<>(2); if (encodedGraph != null) { reader = UnsafeArrayTypeReader.create(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), architecture.supportsUnalignedMemoryAccess()); + maxFixedNodeOrderId = reader.getUVInt(); if (encodedGraph.nodeStartOffsets == null) { int nodeCount = reader.getUVInt(); int[] nodeStartOffsets = new int[nodeCount]; @@ -137,6 +132,7 @@ } } else { reader = null; + maxFixedNodeOrderId = 0; } if (loopExplosion != LoopExplosionKind.NONE) { @@ -145,6 +141,10 @@ loopExplosionMerges = null; } } + + public boolean isInlinedMethod() { + return false; + } } /** Decoding state maintained for each loop in the encoded graph. */ @@ -175,23 +175,24 @@ public final Node[] createdNodes; /** * Nodes that have been created in outer loop scopes and existed before starting to process - * this loop, indexed by the orderId. + * this loop, indexed by the orderId. Only used when {@link MethodScope#loopExplosion} is + * not {@link LoopExplosionKind#NONE}. */ public final Node[] initialCreatedNodes; protected LoopScope(MethodScope methodScope) { this.methodScope = methodScope; this.outer = null; - this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>() : null; + this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>(2) : null; this.loopDepth = 0; this.loopIteration = 0; this.iterationStates = null; this.loopBeginOrderId = -1; int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length; - this.nodesToProcess = new BitSet(nodeCount); - this.initialCreatedNodes = new Node[nodeCount]; + this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); this.createdNodes = new Node[nodeCount]; + this.initialCreatedNodes = null; } protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes, @@ -203,9 +204,9 @@ this.nextIterations = nextIterations; this.iterationStates = iterationStates; this.loopBeginOrderId = loopBeginOrderId; - this.nodesToProcess = new BitSet(initialCreatedNodes.length); + this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); this.initialCreatedNodes = initialCreatedNodes; - this.createdNodes = Arrays.copyOf(createdNodes, createdNodes.length); + this.createdNodes = createdNodes; } @Override @@ -338,18 +339,23 @@ } protected final Architecture architecture; + /** The target graph where decoded nodes are added to. */ + protected final StructuredGraph graph; + private final EconomicMap, ArrayDeque> reusableFloatingNodes; - public GraphDecoder(Architecture architecture) { + public GraphDecoder(Architecture architecture, StructuredGraph graph) { this.architecture = architecture; + this.graph = graph; + reusableFloatingNodes = EconomicMap.create(Equivalence.IDENTITY); } @SuppressWarnings("try") - public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) { + public final void decode(EncodedGraph encodedGraph) { try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) { MethodScope methodScope = new MethodScope(null, graph, encodedGraph, LoopExplosionKind.NONE); decode(createInitialLoopScope(methodScope, null)); cleanupGraph(methodScope); - assert methodScope.graph.verify(); + assert graph.verify(); } catch (Throwable ex) { Debug.handle(ex); } @@ -370,14 +376,10 @@ startNode.setNext(firstNode); loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID); } else { - firstNode = methodScope.graph.start(); + firstNode = graph.start(); registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false); loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID); } - - if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { - methodScope.cleanupTasks.add(new LoopDetector(methodScope, startNode)); - } return loopScope; } @@ -411,18 +413,26 @@ } /* - * Finished with an inlined method. Perform all registered end-of-method cleanup tasks - * and continue with loop that contained the call. + * Finished with an inlined method. Perform end-of-method cleanup tasks. */ - for (Runnable task : methodScope.cleanupTasks) { - task.run(); + if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { + LoopDetector loopDetector = new LoopDetector(graph, methodScope); + loopDetector.run(); } + if (methodScope.isInlinedMethod()) { + finishInlining(methodScope); + } + + /* continue with the caller */ loopScope = methodScope.callerLoopScope; } } + protected void finishInlining(@SuppressWarnings("unused") MethodScope inlineScope) { + } + private static void propagateCreatedNodes(LoopScope loopScope) { - if (loopScope.outer == null) { + if (loopScope.outer == null || loopScope.createdNodes != loopScope.outer.createdNodes) { return; } @@ -474,7 +484,7 @@ LoopScope outerScope = loopScope.outer; int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1; successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes, - loopScope.initialCreatedNodes, outerScope.nextIterations, outerScope.iterationStates); + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates); checkLoopExplosionIteration(methodScope, successorAddScope); /* @@ -496,8 +506,8 @@ methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); int typeId = methodScope.reader.getUVInt(); assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId]; + makeFixedNodeInputs(methodScope, loopScope, node); readProperties(methodScope, node); - makeInputNodes(methodScope, loopScope, node, true); makeSuccessorStubs(methodScope, successorAddScope, node, updatePredecessors); LoopScope resultScope = loopScope; @@ -533,13 +543,16 @@ if (merge instanceof LoopBeginNode) { assert phiNodeScope == phiInputScope && phiNodeScope == loopScope; resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId, - Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length), loopScope.createdNodes, // - methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>() : null, // + methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null, + methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, // + methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>(2) : null, // methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? EconomicMap.create(Equivalence.DEFAULT) : null); phiInputScope = resultScope; phiNodeScope = resultScope; - registerNode(loopScope, mergeOrderId, null, true, true); + if (methodScope.loopExplosion != LoopExplosionKind.NONE) { + registerNode(loopScope, mergeOrderId, null, true, true); + } loopScope.nodesToProcess.clear(mergeOrderId); resultScope.nodesToProcess.set(mergeOrderId); } @@ -551,11 +564,8 @@ InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node); resultScope = handleInvoke(methodScope, loopScope, invokeData); - } else if (node instanceof ReturnNode) { - methodScope.returnNodes.add((ReturnNode) node); - } else if (node instanceof UnwindNode) { - methodScope.unwindNodes.add((UnwindNode) node); - + } else if (node instanceof ReturnNode || node instanceof UnwindNode) { + methodScope.returnAndUnwindNodes.add((ControlSinkNode) node); } else { handleFixedNode(methodScope, loopScope, nodeOrderId, node); } @@ -642,7 +652,7 @@ } } - MergeNode merge = methodScope.graph.add(new MergeNode()); + MergeNode merge = graph.add(new MergeNode()); methodScope.loopExplosionMerges.add(merge); if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { @@ -655,11 +665,11 @@ List newFrameStateValues = new ArrayList<>(); for (ValueNode frameStateValue : frameState.values) { - if (frameStateValue == null || frameStateValue.isConstant() || !methodScope.graph.isNew(methodScope.methodStartMark, frameStateValue)) { + if (frameStateValue == null || frameStateValue.isConstant() || !graph.isNew(methodScope.methodStartMark, frameStateValue)) { newFrameStateValues.add(frameStateValue); } else { - ProxyPlaceholder newFrameStateValue = methodScope.graph.unique(new ProxyPlaceholder(frameStateValue, merge)); + ProxyPlaceholder newFrameStateValue = graph.unique(new ProxyPlaceholder(frameStateValue, merge)); newFrameStateValues.add(newFrameStateValue); /* @@ -670,14 +680,19 @@ if (loopScope.createdNodes[i] == frameStateValue) { loopScope.createdNodes[i] = newFrameStateValue; } - if (loopScope.initialCreatedNodes[i] == frameStateValue) { - loopScope.initialCreatedNodes[i] = newFrameStateValue; + } + + if (loopScope.initialCreatedNodes != null) { + for (int i = 0; i < loopScope.initialCreatedNodes.length; i++) { + if (loopScope.initialCreatedNodes[i] == frameStateValue) { + loopScope.initialCreatedNodes[i] = newFrameStateValue; + } } } } } - FrameState newFrameState = methodScope.graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(), + FrameState newFrameState = graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(), frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings())); frameState.replaceAtUsagesAndDelete(newFrameState); @@ -708,7 +723,7 @@ } protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) { - EndNode replacementNode = methodScope.graph.add(new EndNode()); + EndNode replacementNode = graph.add(new EndNode()); loopEnd.replaceAtPredecessor(replacementNode); loopEnd.safeDelete(); @@ -716,7 +731,7 @@ if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) { int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1; LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes, - loopScope.initialCreatedNodes, loopScope.nextIterations, loopScope.iterationStates); + Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates); checkLoopExplosionIteration(methodScope, nextIterationScope); loopScope.nextIterations.addLast(nextIterationScope); registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true); @@ -749,7 +764,9 @@ * The ProxyNode transports a value from the loop to the outer scope. We therefore * register it in the outer scope. */ - registerNode(loopScope.outer, proxyOrderId, proxy, false, false); + if (loopScope.outer.createdNodes != loopScope.createdNodes) { + registerNode(loopScope.outer, proxyOrderId, proxy, false, false); + } } } @@ -757,7 +774,7 @@ assert loopExit.stateAfter() == null; int stateAfterOrderId = readOrderId(methodScope); - BeginNode begin = methodScope.graph.add(new BeginNode()); + BeginNode begin = graph.add(new BeginNode()); FixedNode loopExitSuccessor = loopExit.next(); loopExit.replaceAtPredecessor(begin); @@ -768,14 +785,14 @@ * This exit might end up as a loop exit of a loop detected after partial evaluation. We * need to be able to create a FrameState and the necessary proxy nodes in this case. */ - loopExitPlaceholder = methodScope.graph.add(new MergeNode()); + loopExitPlaceholder = graph.add(new MergeNode()); methodScope.loopExplosionMerges.add(loopExitPlaceholder); - EndNode end = methodScope.graph.add(new EndNode()); + EndNode end = graph.add(new EndNode()); begin.setNext(end); loopExitPlaceholder.addForwardEnd(end); - begin = methodScope.graph.add(new BeginNode()); + begin = graph.add(new BeginNode()); loopExitPlaceholder.setNext(begin); } @@ -793,10 +810,10 @@ } else if (existingExit instanceof BeginNode) { /* Second loop iteration that exits. Create the merge. */ - merge = methodScope.graph.add(new MergeNode()); + merge = graph.add(new MergeNode()); registerNode(outerScope, loopExitOrderId, merge, true, false); /* Add the first iteration. */ - EndNode firstEnd = methodScope.graph.add(new EndNode()); + EndNode firstEnd = graph.add(new EndNode()); ((BeginNode) existingExit).setNext(firstEnd); merge.addForwardEnd(firstEnd); merge.setNext(loopExitSuccessor); @@ -807,7 +824,7 @@ } if (merge != null) { - EndNode end = methodScope.graph.add(new EndNode()); + EndNode end = graph.add(new EndNode()); begin.setNext(end); merge.addForwardEnd(end); } @@ -826,7 +843,7 @@ if (loopExitPlaceholder != null) { if (!phiInput.isConstant()) { - phiInput = methodScope.graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder)); + phiInput = graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder)); } registerNode(loopScope, proxyOrderId, phiInput, true, false); } @@ -843,7 +860,14 @@ } else if (!merge.isPhiAtMerge(existing)) { /* Now we have two different values, so we need to create a phi node. */ - PhiNode phi = methodScope.graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge)); + PhiNode phi; + if (proxy instanceof ValueProxyNode) { + phi = graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge)); + } else if (proxy instanceof GuardProxyNode) { + phi = graph.addWithoutUnique(new GuardPhiNode(merge)); + } else { + throw GraalError.shouldNotReachHere(); + } /* Add the inputs from all previous exits. */ for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) { phi.addInput(existing); @@ -954,12 +978,6 @@ return false; } - protected Node instantiateNode(MethodScope methodScope, int nodeOrderId) { - methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); - NodeClass nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; - return nodeClass.allocateInstance(); - } - protected void readProperties(MethodScope methodScope, Node node) { node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope)); Fields fields = node.getNodeClass().getData(); @@ -980,7 +998,7 @@ * are created on demand (recursively since they can themselves reference not yet created * nodes). */ - protected void makeInputNodes(MethodScope methodScope, LoopScope loopScope, Node node, boolean updateUsages) { + protected void makeFixedNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) { Edges edges = node.getNodeClass().getInputEdges(); for (int index = 0; index < edges.getDirectCount(); index++) { if (skipDirectEdge(node, edges, index)) { @@ -989,25 +1007,60 @@ int orderId = readOrderId(methodScope); Node value = ensureNodeCreated(methodScope, loopScope, orderId); edges.initializeNode(node, index, value); - if (updateUsages && value != null && !value.isDeleted()) { + if (value != null && !value.isDeleted()) { edges.update(node, null, value); } } - for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { - if (skipIndirectEdge(node, edges, index, true)) { - continue; + + if (node instanceof AbstractMergeNode) { + /* The ends of merge nodes are filled manually when the ends are processed. */ + assert edges.getCount() - edges.getDirectCount() == 1 : "MergeNode has one variable size input (the ends)"; + assert Edges.getNodeList(node, edges.getOffsets(), edges.getDirectCount()) != null : "Input list must have been already created"; + } else { + for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { + int size = methodScope.reader.getSVInt(); + if (size != -1) { + NodeList nodeList = new NodeInputList<>(node, size); + edges.initializeList(node, index, nodeList); + for (int idx = 0; idx < size; idx++) { + int orderId = readOrderId(methodScope); + Node value = ensureNodeCreated(methodScope, loopScope, orderId); + nodeList.initialize(idx, value); + if (value != null && !value.isDeleted()) { + edges.update(node, null, value); + } + } + } } - int size = methodScope.reader.getSVInt(); - if (size != -1) { - NodeList nodeList = new NodeInputList<>(node, size); - edges.initializeList(node, index, nodeList); - for (int idx = 0; idx < size; idx++) { - int orderId = readOrderId(methodScope); - Node value = ensureNodeCreated(methodScope, loopScope, orderId); - nodeList.initialize(idx, value); - if (updateUsages && value != null && !value.isDeleted()) { - edges.update(node, null, value); + } + } + + protected void makeFloatingNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) { + Edges edges = node.getNodeClass().getInputEdges(); + if (node instanceof PhiNode) { + /* + * The inputs of phi functions are filled manually when the end nodes are processed. + * However, the values must not be null, so initialize them with an empty list. + */ + assert edges.getDirectCount() == 1 : "PhiNode has one direct input (the MergeNode)"; + assert edges.getCount() - edges.getDirectCount() == 1 : "PhiNode has one variable size input (the values)"; + edges.initializeList(node, edges.getDirectCount(), new NodeInputList<>(node)); + } else { + for (int index = 0; index < edges.getDirectCount(); index++) { + int orderId = readOrderId(methodScope); + Node value = ensureNodeCreated(methodScope, loopScope, orderId); + edges.initializeNode(node, index, value); + } + for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { + int size = methodScope.reader.getSVInt(); + if (size != -1) { + NodeList nodeList = new NodeInputList<>(node, size); + edges.initializeList(node, index, nodeList); + for (int idx = 0; idx < size; idx++) { + int orderId = readOrderId(methodScope); + Node value = ensureNodeCreated(methodScope, loopScope, orderId); + nodeList.initialize(idx, value); } } } @@ -1024,31 +1077,34 @@ } node = decodeFloatingNode(methodScope, loopScope, nodeOrderId); - if (node instanceof ProxyNode || node instanceof PhiNode) { /* * We need these nodes as they were in the original graph, without any canonicalization * or value numbering. */ - node = methodScope.graph.addWithoutUnique(node); + node = graph.addWithoutUnique(node); } else { /* Allow subclasses to canonicalize and intercept nodes. */ - node = handleFloatingNodeBeforeAdd(methodScope, loopScope, node); - if (!node.isAlive()) { - node = addFloatingNode(methodScope, node); + Node newNode = handleFloatingNodeBeforeAdd(methodScope, loopScope, node); + if (newNode != node) { + releaseFloatingNode(node); } - node = handleFloatingNodeAfterAdd(methodScope, loopScope, node); + + if (!newNode.isAlive()) { + newNode = addFloatingNode(methodScope, newNode); + } + node = handleFloatingNodeAfterAdd(methodScope, loopScope, newNode); } registerNode(loopScope, nodeOrderId, node, false, false); return node; } - protected Node addFloatingNode(MethodScope methodScope, Node node) { + protected Node addFloatingNode(@SuppressWarnings("unused") MethodScope methodScope, Node node) { /* * We want to exactly reproduce the encoded graph. Even though nodes should be unique in the * encoded graph, this is not always guaranteed. */ - return methodScope.graph.addWithoutUnique(node); + return graph.addWithoutUnique(node); } /** @@ -1056,7 +1112,10 @@ */ protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { long readerByteIndex = methodScope.reader.getByteIndex(); - Node node = instantiateNode(methodScope, nodeOrderId); + + methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); + NodeClass nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; + Node node = allocateFloatingNode(nodeClass); if (node instanceof FixedNode) { /* * This is a severe error that will lead to a corrupted graph, so it is better not to @@ -1065,16 +1124,38 @@ throw shouldNotReachHere("Not a floating node: " + node.getClass().getName()); } + /* Read the inputs of the node, possibly creating them recursively. */ + makeFloatingNodeInputs(methodScope, loopScope, node); + /* Read the properties of the node. */ readProperties(methodScope, node); /* There must not be any successors to read, since it is a non-fixed node. */ assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0; - /* Read the inputs of the node, possibly creating them recursively. */ - makeInputNodes(methodScope, loopScope, node, false); + methodScope.reader.setByteIndex(readerByteIndex); return node; } + private Node allocateFloatingNode(NodeClass nodeClass) { + ArrayDeque cachedNodes = reusableFloatingNodes.get(nodeClass); + if (cachedNodes != null) { + Node node = cachedNodes.poll(); + if (node != null) { + return node; + } + } + return nodeClass.allocateInstance(); + } + + private void releaseFloatingNode(Node node) { + ArrayDeque cachedNodes = reusableFloatingNodes.get(node.getNodeClass()); + if (cachedNodes == null) { + cachedNodes = new ArrayDeque<>(2); + reusableFloatingNodes.put(node.getNodeClass(), cachedNodes); + } + cachedNodes.push(node); + } + /** * Hook for subclasses to process a non-fixed node before it is added to the graph. * @@ -1121,9 +1202,6 @@ } } for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { - if (skipIndirectEdge(node, edges, index, true)) { - continue; - } int size = methodScope.reader.getSVInt(); if (size != -1) { NodeList nodeList = new NodeSuccessorList<>(node, size); @@ -1150,7 +1228,9 @@ } long readerByteIndex = methodScope.reader.getByteIndex(); - node = (FixedNode) methodScope.graph.add(instantiateNode(methodScope, nodeOrderId)); + methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); + NodeClass nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; + node = (FixedNode) graph.add(nodeClass.allocateInstance()); /* Properties and edges are not filled yet, the node remains uninitialized. */ methodScope.reader.setByteIndex(readerByteIndex); @@ -1174,12 +1254,6 @@ return true; } } - } else if (node instanceof PhiNode) { - /* The inputs of phi functions are filled manually when the end nodes are processed. */ - assert edges.type() == Edges.Type.Inputs; - assert index == edges.getDirectCount() - 1 : "PhiNode has one direct input (the MergeNode)"; - return true; - } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) { /* The stateAfter of the loop exit is filled manually. */ return true; @@ -1188,29 +1262,6 @@ return false; } - protected static boolean skipIndirectEdge(Node node, Edges edges, int index, boolean decode) { - assert !(node instanceof Invoke); - assert !(node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class); - if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs) { - /* The ends of merge nodes are filled manually when the ends are processed. */ - assert index == edges.getCount() - 1 : "MergeNode has one variable size input (the ends)"; - assert Edges.getNodeList(node, edges.getOffsets(), index) != null : "Input list must have been already created"; - return true; - - } else if (node instanceof PhiNode) { - /* The inputs of phi functions are filled manually when the end nodes are processed. */ - assert edges.type() == Edges.Type.Inputs; - assert index == edges.getCount() - 1 : "PhiNode has one variable size input (the values)"; - if (decode) { - /* The values must not be null, so initialize with an empty list. */ - edges.initializeList(node, index, new NodeInputList<>(node)); - } - return true; - - } - return false; - } - protected Node lookupNode(LoopScope loopScope, int nodeOrderId) { return loopScope.createdNodes[nodeOrderId]; } @@ -1236,11 +1287,11 @@ * @param methodScope The current method. */ protected void cleanupGraph(MethodScope methodScope) { - assert verifyEdges(methodScope); + assert verifyEdges(); } - protected boolean verifyEdges(MethodScope methodScope) { - for (Node node : methodScope.graph.getNodes()) { + protected boolean verifyEdges() { + for (Node node : graph.getNodes()) { assert node.isAlive(); for (Node i : node.inputs()) { assert i.isAlive(); @@ -1278,7 +1329,7 @@ * The ends, i.e., the source of backward branches. The {@link EndNode#successors successor} * is the {@link #header loop header}. */ - List ends = new ArrayList<>(); + List ends = new ArrayList<>(2); /** * Exits of the loop. The successor is a {@link MergeNode} marked in * {@link MethodScope#loopExplosionMerges}. @@ -1291,20 +1342,20 @@ boolean irreducible; } + private final StructuredGraph graph; private final MethodScope methodScope; - private final FixedNode startInstruction; private Loop irreducibleLoopHandler; private IntegerSwitchNode irreducibleLoopSwitch; - protected LoopDetector(MethodScope methodScope, FixedNode startInstruction) { + protected LoopDetector(StructuredGraph graph, MethodScope methodScope) { + this.graph = graph; this.methodScope = methodScope; - this.startInstruction = startInstruction; } @Override public void run() { - Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "Before loop detection"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "Before loop detection"); List orderedLoops = findLoops(); assert orderedLoops.get(orderedLoops.size() - 1) == irreducibleLoopHandler : "outermost loop must be the last element in the list"; @@ -1327,11 +1378,11 @@ } else { insertLoopNodes(loop); } - Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After handling of loop %s", loop.header); + Debug.dump(Debug.DETAILED_LEVEL, graph, "After handling of loop %s", loop.header); } logIrreducibleLoops(); - Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After loop detection"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "After loop detection"); } private List findLoops() { @@ -1346,11 +1397,11 @@ */ irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead); - NodeBitMap visited = methodScope.graph.createNodeBitMap(); - NodeBitMap active = methodScope.graph.createNodeBitMap(); + NodeBitMap visited = graph.createNodeBitMap(); + NodeBitMap active = graph.createNodeBitMap(); Deque stack = new ArrayDeque<>(); - visited.mark(startInstruction); - stack.push(startInstruction); + visited.mark(methodScope.loopExplosionHead); + stack.push(methodScope.loopExplosionHead); while (!stack.isEmpty()) { Node current = stack.peek(); @@ -1421,7 +1472,7 @@ */ List possibleExits = new ArrayList<>(); - NodeBitMap visited = methodScope.graph.createNodeBitMap(); + NodeBitMap visited = graph.createNodeBitMap(); Deque stack = new ArrayDeque<>(); for (EndNode loopEnd : loop.ends) { stack.push(loopEnd); @@ -1433,7 +1484,7 @@ if (current == loop.header) { continue; } - if (!methodScope.graph.isNew(methodScope.methodStartMark, current)) { + if (!graph.isNew(methodScope.methodStartMark, current)) { /* * The current node is before the method that contains the exploded loop. The loop * must have a second entry point, i.e., it is an irreducible loop. @@ -1498,7 +1549,6 @@ * necessary into a loop because it computes loop information based on bytecodes, before the * actual parsing. */ - for (Node succ : possibleExits) { if (!visited.contains(succ)) { stack.push(succ); @@ -1541,8 +1591,8 @@ FrameState stateAfter = merge.stateAfter().duplicate(); FixedNode afterMerge = merge.next(); merge.setNext(null); - EndNode preLoopEnd = methodScope.graph.add(new EndNode()); - LoopBeginNode loopBegin = methodScope.graph.add(new LoopBeginNode()); + EndNode preLoopEnd = graph.add(new EndNode()); + LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); merge.setNext(preLoopEnd); /* Add the single non-loop predecessor of the loop header. */ @@ -1559,7 +1609,7 @@ List loopBeginPhis = new ArrayList<>(mergePhis.size()); for (int i = 0; i < mergePhis.size(); i++) { PhiNode mergePhi = mergePhis.get(i); - PhiNode loopBeginPhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin)); + PhiNode loopBeginPhi = graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin)); mergePhi.replaceAtUsages(loopBeginPhi); /* * The first input of the new phi function is the original phi function, for the one @@ -1577,7 +1627,7 @@ } merge.removeEnd(endNode); - LoopEndNode loopEnd = methodScope.graph.add(new LoopEndNode(loopBegin)); + LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); endNode.replaceAndDelete(loopEnd); } @@ -1589,7 +1639,7 @@ AbstractMergeNode loopExplosionMerge = exit.merge(); assert methodScope.loopExplosionMerges.contains(loopExplosionMerge); - LoopExitNode loopExit = methodScope.graph.add(new LoopExitNode(loopBegin)); + LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); exit.replaceAtPredecessor(loopExit); loopExit.setNext(exit); assignLoopExitState(loopExit, loopExplosionMerge, exit); @@ -1630,7 +1680,7 @@ realValue = ProxyPlaceholder.unwrap(value); } - if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !methodScope.graph.isNew(methodScope.methodStartMark, realValue)) { + if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !graph.isNew(methodScope.methodStartMark, realValue)) { newValues.add(realValue); } else { /* @@ -1641,7 +1691,7 @@ "Value flowing out of loop, but we are not prepared to insert a ProxyNode"); ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value; - ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, methodScope.graph); + ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, graph); proxyPlaceholder.setValue(proxy); newValues.add(proxy); } @@ -1651,7 +1701,7 @@ oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings()); assert loopExit.stateAfter() == null; - loopExit.setStateAfter(methodScope.graph.add(newState)); + loopExit.setStateAfter(graph.add(newState)); } /** @@ -1722,7 +1772,7 @@ assert irreducibleLoopHandler.header.phis().isEmpty(); /* The new phi function for the loop variable. */ - loopVariablePhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header)); + loopVariablePhi = graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header)); for (int i = 0; i < irreducibleLoopHandler.header.phiPredecessorCount(); i++) { loopVariablePhi.addInput(explosionHeadValue); } @@ -1732,7 +1782,7 @@ * to the old FrameState: the loop variable is replaced with the phi function. */ FrameState oldFrameState = explosionHeadState; - List newFrameStateValues = new ArrayList<>(); + List newFrameStateValues = new ArrayList<>(explosionHeadValues.size()); for (int i = 0; i < explosionHeadValues.size(); i++) { if (i == loopVariableIndex) { newFrameStateValues.add(loopVariablePhi); @@ -1740,7 +1790,8 @@ newFrameStateValues.add(explosionHeadValues.get(i)); } } - FrameState newFrameState = methodScope.graph.add( + + FrameState newFrameState = graph.add( new FrameState(oldFrameState.outerFrameState(), oldFrameState.getCode(), oldFrameState.bci, newFrameStateValues, oldFrameState.localsSize(), oldFrameState.stackSize(), oldFrameState.rethrowException(), oldFrameState.duringCall(), oldFrameState.monitorIds(), oldFrameState.virtualObjectMappings())); @@ -1752,7 +1803,7 @@ */ FixedNode handlerNext = irreducibleLoopHandler.header.next(); irreducibleLoopHandler.header.setNext(null); - BeginNode handlerBegin = methodScope.graph.add(new BeginNode()); + BeginNode handlerBegin = graph.add(new BeginNode()); handlerBegin.setNext(handlerNext); dispatchTable.put(asInt(explosionHeadValue), handlerBegin); @@ -1760,8 +1811,8 @@ * We know that there will always be a matching key in the switch. But Graal always * wants a default successor, so we build a dummy block that just deoptimizes. */ - unreachableDefaultSuccessor = methodScope.graph.add(new BeginNode()); - DeoptimizeNode deopt = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); + unreachableDefaultSuccessor = graph.add(new BeginNode()); + DeoptimizeNode deopt = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); unreachableDefaultSuccessor.setNext(deopt); } else { @@ -1796,8 +1847,8 @@ /* Insert our loop into the dispatch state machine. */ assert loop.header.phis().isEmpty(); - BeginNode dispatchBegin = methodScope.graph.add(new BeginNode()); - EndNode dispatchEnd = methodScope.graph.add(new EndNode()); + BeginNode dispatchBegin = graph.add(new BeginNode()); + EndNode dispatchEnd = graph.add(new EndNode()); dispatchBegin.setNext(dispatchEnd); loop.header.addForwardEnd(dispatchEnd); int intLoopValue = asInt(loopValue); @@ -1813,7 +1864,7 @@ } /* Build and insert the switch node. */ - irreducibleLoopSwitch = methodScope.graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor)); + irreducibleLoopSwitch = graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor)); irreducibleLoopHandler.header.setNext(irreducibleLoopSwitch); } @@ -1859,14 +1910,14 @@ @SuppressWarnings("try") private void logIrreducibleLoops() { try (Debug.Scope s = Debug.scope("IrreducibleLoops")) { - if (Debug.isLogEnabled(Debug.BASIC_LOG_LEVEL) && irreducibleLoopSwitch != null) { + if (Debug.isLogEnabled(Debug.BASIC_LEVEL) && irreducibleLoopSwitch != null) { StringBuilder msg = new StringBuilder("Inserted state machine to remove irreducible loops. Dispatching to the following states: "); String sep = ""; for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) { msg.append(sep).append(irreducibleLoopSwitch.keyAt(i).asInt()); sep = ", "; } - Debug.log(Debug.BASIC_LOG_LEVEL, "%s", msg); + Debug.log(Debug.BASIC_LEVEL, "%s", msg); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -67,10 +67,11 @@ * encoding-local. * * The encoded graph has the following structure: First, all nodes and their edges are serialized. - * The start offset of every node is then known. The raw node data is followed by a "table of - * contents" that lists the start offset for every node. + * The start offset of every node is then known. The raw node data is followed by metadata, i.e., + * the maximum fixed node order id and a "table of contents" that lists the start offset for every + * node. * - * The beginning of that table of contents is the return value of {@link #encode} and stored in + * The beginning of this metadata is the return value of {@link #encode} and stored in * {@link EncodedGraph#getStartOffset()}. The order of nodes in the table of contents is the * {@link NodeOrder#orderIds orderId} of a node. Note that the orderId is not the regular node id * that every Graal graph node gets assigned. The orderId is computed and used just for encoding and @@ -85,8 +86,8 @@ *
  * struct Node {
  *   unsigned typeId
+ *   unsigned[] inputOrderIds
  *   signed[] properties
- *   unsigned[] inputOrderIds
  *   unsigned[] successorOrderIds
  * }
  * 
@@ -168,9 +169,8 @@ */ public void prepare(StructuredGraph graph) { for (Node node : graph.getNodes()) { - nodeClasses.addObject(node.getNodeClass()); - - NodeClass nodeClass = node.getNodeClass(); + NodeClass nodeClass = node.getNodeClass(); + nodeClasses.addObject(nodeClass); objects.addObject(node.getNodeSourcePosition()); for (int i = 0; i < nodeClass.getData().getCount(); i++) { if (!nodeClass.getData().getType(i).isPrimitive()) { @@ -223,8 +223,8 @@ /* Write out the type, properties, and edges. */ NodeClass nodeClass = node.getNodeClass(); writer.putUV(nodeClasses.getIndex(nodeClass)); + writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder); writeProperties(node, nodeClass.getData()); - writeEdges(node, nodeClass.getEdges(Edges.Type.Inputs), nodeOrder); writeEdges(node, nodeClass.getEdges(Edges.Type.Successors), nodeOrder); /* Special handling for some nodes that require additional information for decoding. */ @@ -276,18 +276,23 @@ } } - /* Write out the table of contents with the start offset for all nodes. */ - int nodeTableStart = TypeConversion.asS4(writer.getBytesWritten()); + /* + * Write out the metadata (maximum fixed node order id and the table of contents with the + * start offset for all nodes). + */ + int metadataStart = TypeConversion.asS4(writer.getBytesWritten()); + writer.putUV(nodeOrder.maxFixedNodeOrderId); writer.putUV(nodeCount); for (int i = 0; i < nodeCount; i++) { assert i == NULL_ORDER_ID || i == START_NODE_ORDER_ID || nodeStartOffsets[i] > 0; - writer.putUV(nodeTableStart - nodeStartOffsets[i]); + writer.putUV(metadataStart - nodeStartOffsets[i]); } /* Check that the decoding of the encode graph is the same as the input. */ - assert verifyEncoding(graph, new EncodedGraph(getEncoding(), nodeTableStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()), architecture); + assert verifyEncoding(graph, new EncodedGraph(getEncoding(), metadataStart, getObjects(), getNodeClasses(), graph.getAssumptions(), graph.getMethods()), + architecture); - return nodeTableStart; + return metadataStart; } public byte[] getEncoding() { @@ -297,6 +302,7 @@ static class NodeOrder { protected final NodeMap orderIds; protected int nextOrderId; + protected int maxFixedNodeOrderId; NodeOrder(StructuredGraph graph) { this.orderIds = new NodeMap<>(graph); @@ -337,6 +343,7 @@ } } while (current != null); + maxFixedNodeOrderId = nextOrderId - 1; for (Node node : graph.getNodes()) { assert (node instanceof FixedNode) == (orderIds.get(node) != null) : "all fixed nodes must be ordered: " + node; add(node); @@ -365,6 +372,11 @@ } protected void writeEdges(Node node, Edges edges, NodeOrder nodeOrder) { + if (node instanceof PhiNode) { + /* Edges are not needed for decoding, so we must not write it. */ + return; + } + for (int idx = 0; idx < edges.getDirectCount(); idx++) { if (GraphDecoder.skipDirectEdge(node, edges, idx)) { /* Edge is not needed for decoding, so we must not write it. */ @@ -373,21 +385,23 @@ Node edge = Edges.getNode(node, edges.getOffsets(), idx); writeOrderId(edge, nodeOrder); } - for (int idx = edges.getDirectCount(); idx < edges.getCount(); idx++) { - if (GraphDecoder.skipIndirectEdge(node, edges, idx, false)) { - /* Edge is not needed for decoding, so we must not write it. */ - continue; - } - NodeList edgeList = Edges.getNodeList(node, edges.getOffsets(), idx); - if (edgeList == null) { - writer.putSV(-1); - } else { - writer.putSV(edgeList.size()); - for (Node edge : edgeList) { - writeOrderId(edge, nodeOrder); + + if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs) { + /* The ends of merge nodes are decoded manually when the ends are processed. */ + } else { + for (int idx = edges.getDirectCount(); idx < edges.getCount(); idx++) { + NodeList edgeList = Edges.getNodeList(node, edges.getOffsets(), idx); + if (edgeList == null) { + writer.putSV(-1); + } else { + writer.putSV(edgeList.size()); + for (Node edge : edgeList) { + writeOrderId(edge, nodeOrder); + } } } } + } protected void writeOrderId(Node node, NodeOrder nodeOrder) { @@ -405,16 +419,16 @@ @SuppressWarnings("try") public static boolean verifyEncoding(StructuredGraph originalGraph, EncodedGraph encodedGraph, Architecture architecture) { StructuredGraph decodedGraph = new StructuredGraph.Builder(originalGraph.getOptions(), AllowAssumptions.YES).method(originalGraph.method()).build(); - GraphDecoder decoder = new GraphDecoder(architecture); - decoder.decode(decodedGraph, encodedGraph); + GraphDecoder decoder = new GraphDecoder(architecture, decodedGraph); + decoder.decode(encodedGraph); decodedGraph.verify(); try { GraphComparison.verifyGraphsEqual(originalGraph, decodedGraph); } catch (Throwable ex) { try (Debug.Scope scope = Debug.scope("GraphEncoder")) { - Debug.dump(Debug.INFO_LOG_LEVEL, originalGraph, "Original Graph"); - Debug.dump(Debug.INFO_LOG_LEVEL, decodedGraph, "Decoded Graph"); + Debug.forceDump(originalGraph, "Original Graph"); + Debug.forceDump(decodedGraph, "Decoded Graph"); } throw ex; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardedValueNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -87,7 +87,7 @@ if (stamp().equals(object().stamp())) { return object(); } else { - return new PiNode(object(), stamp()); + return PiNode.create(object(), stamp()); } } return this; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -316,7 +316,10 @@ FixedWithNextNode falseNext = (FixedWithNextNode) falseSucc.next(); NodeClass nodeClass = trueNext.getNodeClass(); if (trueNext.getClass() == falseNext.getClass()) { - if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) { + if (trueNext instanceof AbstractBeginNode) { + // Cannot do this optimization for begin nodes, because it could + // move guards above the if that need to stay below a branch. + } else if (nodeClass.equalInputs(trueNext, falseNext) && trueNext.valueEquals(falseNext)) { falseNext.replaceAtUsages(trueNext); graph().removeFixed(falseNext); GraphUtil.unlinkFixedNode(trueNext); @@ -600,7 +603,7 @@ protected void removeThroughFalseBranch(SimplifierTool tool) { AbstractBeginNode trueBegin = trueSuccessor(); - graph().removeSplitPropagate(this, trueBegin, tool); + graph().removeSplitPropagate(this, trueBegin); tool.addToWorkList(trueBegin); if (condition() != null) { GraphUtil.tryKillUnused(condition()); @@ -772,9 +775,9 @@ transferProxies(trueSuccessor(), trueMerge); transferProxies(falseSuccessor(), falseMerge); - cleanupMerge(tool, merge); - cleanupMerge(tool, trueMerge); - cleanupMerge(tool, falseMerge); + cleanupMerge(merge); + cleanupMerge(trueMerge); + cleanupMerge(falseMerge); return true; } @@ -869,10 +872,10 @@ } } - private void cleanupMerge(SimplifierTool tool, MergeNode merge) { + private void cleanupMerge(MergeNode merge) { if (merge != null && merge.isAlive()) { if (merge.forwardEndCount() == 0) { - GraphUtil.killCFG(merge, tool); + GraphUtil.killCFG(merge); } else if (merge.forwardEndCount() == 1) { graph().reduceTrivialMerge(merge); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -26,7 +26,6 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.CanonicalizerTool; @@ -69,12 +68,11 @@ * snippet. */ @NodeIntrinsic(Placeholder.class) - public static native Object piArrayCast(Object object, int length); + public static native Object piArrayCastToSnippetReplaceeStamp(Object object, int length); /** - * A placeholder node in a snippet that will be replaced with an appropriate {@link PiArrayNode} - * when the snippet is instantiated. Using a placeholder means that {@link PiArrayNode} never - * needs to deal with {@link StampFactory#forNodeIntrinsic()} stamps. + * A placeholder node in a snippet that will be replaced with a {@link PiArrayNode} when the + * snippet is instantiated. */ @NodeInfo(cycles = CYCLES_0, size = SIZE_0) public static class Placeholder extends PiNode.Placeholder { @@ -88,8 +86,9 @@ } @Override - public PiNode getReplacement(Stamp stampForPi) { - return graph().addOrUnique(new PiArrayNode(object(), length, stampForPi)); + public void makeReplacement(Stamp snippetReplaceeStamp) { + PiArrayNode piArray = graph().addOrUnique(new PiArrayNode(object(), length, snippetReplaceeStamp)); + replaceAndDelete(piArray); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,7 +25,10 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; +import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; @@ -36,6 +39,7 @@ import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.extended.GuardingNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; @@ -70,7 +74,6 @@ protected PiNode(NodeClass c, ValueNode object, Stamp stamp, GuardingNode guard) { super(c, stamp, guard); - assert stamp != StampFactory.forNodeIntrinsic(); this.object = object; this.piStamp = stamp; assert piStamp.isCompatible(object.stamp()) : "Object stamp not compatible to piStamp"; @@ -93,6 +96,53 @@ this(object, StampFactory.object(exactType ? TypeReference.createExactTrusted(toType) : TypeReference.createWithoutAssumptions(toType), nonNull || StampTool.isPointerNonNull(object.stamp()))); } + public static ValueNode create(ValueNode object, Stamp stamp) { + ValueNode value = canonical(object, stamp, null); + if (value != null) { + return value; + } + return new PiNode(object, stamp); + } + + public static ValueNode create(ValueNode object, Stamp stamp, ValueNode anchor) { + ValueNode value = canonical(object, stamp, (GuardingNode) anchor); + if (value != null) { + return value; + } + return new PiNode(object, stamp, anchor); + } + + public static ValueNode create(ValueNode object, ValueNode anchor) { + Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp()); + ValueNode value = canonical(object, stamp, (GuardingNode) anchor); + if (value != null) { + return value; + } + return new PiNode(object, stamp, anchor); + } + + @SuppressWarnings("unused") + public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ValueNode anchor) { + Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp()); + ValueNode value = canonical(object, stamp, (GuardingNode) anchor); + if (value == null) { + value = new PiNode(object, stamp, anchor); + } + b.push(JavaKind.Object, b.recursiveAppend(value)); + return true; + } + + @SuppressWarnings("unused") + public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) { + Stamp stamp = StampFactory.object(exactType ? TypeReference.createExactTrusted(toType) : TypeReference.createWithoutAssumptions(toType), nonNull || StampTool.isPointerNonNull(object.stamp())); + ValueNode value = canonical(object, stamp, null); + if (value == null) { + value = new PiNode(object, stamp); + } + b.push(JavaKind.Object, b.recursiveAppend(value)); + return true; + } + public final Stamp piStamp() { return piStamp; } @@ -124,37 +174,32 @@ } } - @Override - public Node canonical(CanonicalizerTool tool) { + public static ValueNode canonical(ValueNode object, Stamp stamp, GuardingNode guard) { // Use most up to date stamp. - Stamp computedStamp = computeStamp(); - - ValueNode o = object(); + Stamp computedStamp = stamp.improveWith(object.stamp()); // The pi node does not give any additional information => skip it. - if (computedStamp.equals(o.stamp())) { - return o; + if (computedStamp.equals(object.stamp())) { + return object; } - GuardingNode g = getGuard(); - if (g == null) { - + if (guard == null) { // Try to merge the pi node with a load node. - if (o instanceof ReadNode) { - ReadNode readNode = (ReadNode) o; - readNode.setStamp(readNode.stamp().improveWith(this.piStamp)); + if (object instanceof ReadNode) { + ReadNode readNode = (ReadNode) object; + readNode.setStamp(readNode.stamp().improveWith(stamp)); return readNode; } } else { - for (Node n : g.asNode().usages()) { + for (Node n : guard.asNode().usages()) { if (n instanceof PiNode) { PiNode otherPi = (PiNode) n; - if (o == otherPi.object() && computedStamp.equals(otherPi.stamp())) { + if (object == otherPi.object() && computedStamp.equals(otherPi.stamp())) { /* * Two PiNodes with the same guard and same result, so return the one with * the more precise piStamp. */ - Stamp newStamp = piStamp.join(otherPi.piStamp); + Stamp newStamp = stamp.join(otherPi.piStamp); if (newStamp.equals(otherPi.piStamp)) { return otherPi; } @@ -162,6 +207,15 @@ } } } + return null; + } + + @Override + public Node canonical(CanonicalizerTool tool) { + Node value = canonical(object(), stamp(), getGuard()); + if (value != null) { + return value; + } return this; } @@ -226,9 +280,8 @@ public static native Object piCast(Object object, @ConstantNodeParameter Class toType, @ConstantNodeParameter boolean exactType, @ConstantNodeParameter boolean nonNull); /** - * A placeholder node in a snippet that will be replaced with an appropriate {@link PiNode} when - * the snippet is instantiated. Using a placeholder means that {@link PiNode} never needs to - * deal with {@link StampFactory#forNodeIntrinsic()} stamps. + * A placeholder node in a snippet that will be replaced with a {@link PiNode} when the snippet + * is instantiated. */ @NodeInfo(cycles = CYCLES_0, size = SIZE_0) public static class Placeholder extends FloatingGuardedNode { @@ -241,7 +294,7 @@ } protected Placeholder(NodeClass c, ValueNode object) { - super(c, StampFactory.forNodeIntrinsic(), null); + super(c, PlaceholderStamp.SINGLETON, null); this.object = object; } @@ -250,12 +303,44 @@ } /** - * Gets a new {@link PiNode} that replaces this placeholder during snippet instantiation. + * Replaces this node with a {@link PiNode} during snippet instantiation. * * @param snippetReplaceeStamp the stamp of the node being replace by the snippet */ - public PiNode getReplacement(Stamp snippetReplaceeStamp) { - return graph().addOrUnique(new PiNode(object(), snippetReplaceeStamp, null)); + public void makeReplacement(Stamp snippetReplaceeStamp) { + ValueNode value = graph().maybeAddOrUnique(PiNode.create(object(), snippetReplaceeStamp, null)); + replaceAndDelete(value); + } + } + + /** + * A stamp for {@link Placeholder} nodes which are only used in snippets. It is replaced by an + * actual stamp when the snippet is instantiated. + */ + public static final class PlaceholderStamp extends ObjectStamp { + private static final PlaceholderStamp SINGLETON = new PlaceholderStamp(); + + public static PlaceholderStamp singleton() { + return SINGLETON; + } + + private PlaceholderStamp() { + super(null, false, false, false); + } + + @Override + public int hashCode() { + return System.identityHashCode(this); + } + + @Override + public boolean equals(Object obj) { + return this == obj; + } + + @Override + public String toString() { + return "PlaceholderStamp"; } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,6 +22,7 @@ */ package org.graalvm.compiler.nodes; +import static org.graalvm.compiler.nodeinfo.InputType.Guard; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; @@ -37,6 +38,9 @@ import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; +import org.graalvm.compiler.nodes.java.ArrayLengthNode; +import org.graalvm.compiler.nodes.java.LoadFieldNode; +import org.graalvm.compiler.nodes.java.LoadIndexedNode; import org.graalvm.compiler.nodes.spi.StampProvider; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; @@ -59,6 +63,7 @@ protected final ConstantFieldProvider constantFieldProvider; protected final StampProvider stampProvider; protected final boolean canonicalizeReads; + protected final CanonicalizerTool canonicalizerTool; protected class PECanonicalizerTool implements CanonicalizerTool { @@ -113,7 +118,7 @@ } } - @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) + @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED, allowedUsageTypes = {Guard}) static class CanonicalizeToNullNode extends FloatingNode implements Canonicalizable, GuardingNode { public static final NodeClass TYPE = NodeClass.create(CanonicalizeToNullNode.class); @@ -127,32 +132,30 @@ } } - public SimplifyingGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, - boolean canonicalizeReads, Architecture architecture) { - super(architecture); + public SimplifyingGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, + ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, + boolean canonicalizeReads) { + super(architecture, graph); this.metaAccess = metaAccess; this.constantReflection = constantReflection; this.constantFieldProvider = constantFieldProvider; this.stampProvider = stampProvider; this.canonicalizeReads = canonicalizeReads; + this.canonicalizerTool = new PECanonicalizerTool(graph.getAssumptions(), graph.getOptions()); } @Override protected void cleanupGraph(MethodScope methodScope) { - GraphUtil.normalizeLoops(methodScope.graph); + GraphUtil.normalizeLoops(graph); super.cleanupGraph(methodScope); - for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) { + for (Node node : graph.getNewNodes(methodScope.methodStartMark)) { if (node instanceof MergeNode) { MergeNode mergeNode = (MergeNode) node; if (mergeNode.forwardEndCount() == 1) { - methodScope.graph.reduceTrivialMerge(mergeNode); + graph.reduceTrivialMerge(mergeNode); } - } - } - - for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) { - if (node instanceof BeginNode || node instanceof KillingBeginNode) { + } else if (node instanceof BeginNode || node instanceof KillingBeginNode) { if (!(node.predecessor() instanceof ControlSplitNode) && node.hasNoUsages()) { GraphUtil.unlinkFixedNode((AbstractBeginNode) node); node.safeDelete(); @@ -160,7 +163,7 @@ } } - for (Node node : methodScope.graph.getNewNodes(methodScope.methodStartMark)) { + for (Node node : graph.getNewNodes(methodScope.methodStartMark)) { GraphUtil.tryKillUnused(node); } } @@ -187,7 +190,32 @@ @Override protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { - if (node instanceof IfNode) { + Node canonical = canonicalizeFixedNode(node); + if (canonical != node) { + handleCanonicalization(loopScope, nodeOrderId, node, canonical); + } + } + + private Node canonicalizeFixedNode(FixedNode node) { + if (node instanceof LoadFieldNode) { + LoadFieldNode loadFieldNode = (LoadFieldNode) node; + return loadFieldNode.canonical(canonicalizerTool); + } else if (node instanceof FixedGuardNode) { + FixedGuardNode guard = (FixedGuardNode) node; + if (guard.getCondition() instanceof LogicConstantNode) { + LogicConstantNode condition = (LogicConstantNode) guard.getCondition(); + if (condition.getValue() == guard.isNegated()) { + DeoptimizeNode deopt = new DeoptimizeNode(guard.getAction(), guard.getReason(), guard.getSpeculation()); + if (guard.stateBefore() != null) { + deopt.setStateBefore(guard.stateBefore()); + } + return deopt; + } else { + return null; + } + } + return node; + } else if (node instanceof IfNode) { IfNode ifNode = (IfNode) node; if (ifNode.condition() instanceof LogicNegationNode) { ifNode.eliminateNegation(); @@ -197,73 +225,55 @@ AbstractBeginNode survivingSuccessor = ifNode.getSuccessor(condition); AbstractBeginNode deadSuccessor = ifNode.getSuccessor(!condition); - methodScope.graph.removeSplit(ifNode, survivingSuccessor); + graph.removeSplit(ifNode, survivingSuccessor); assert deadSuccessor.next() == null : "must not be parsed yet"; deadSuccessor.safeDelete(); } - + return node; + } else if (node instanceof LoadIndexedNode) { + LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node; + return loadIndexedNode.canonical(canonicalizerTool); + } else if (node instanceof ArrayLengthNode) { + ArrayLengthNode arrayLengthNode = (ArrayLengthNode) node; + return arrayLengthNode.canonical(canonicalizerTool); } else if (node instanceof IntegerSwitchNode && ((IntegerSwitchNode) node).value().isConstant()) { IntegerSwitchNode switchNode = (IntegerSwitchNode) node; int value = switchNode.value().asJavaConstant().asInt(); AbstractBeginNode survivingSuccessor = switchNode.successorAtKey(value); List allSuccessors = switchNode.successors().snapshot(); - methodScope.graph.removeSplit(switchNode, survivingSuccessor); + graph.removeSplit(switchNode, survivingSuccessor); for (Node successor : allSuccessors) { if (successor != survivingSuccessor) { assert ((AbstractBeginNode) successor).next() == null : "must not be parsed yet"; successor.safeDelete(); } } - - } else if (node instanceof FixedGuardNode) { - FixedGuardNode guard = (FixedGuardNode) node; - if (guard.getCondition() instanceof LogicConstantNode) { - LogicConstantNode condition = (LogicConstantNode) guard.getCondition(); - Node canonical; - if (condition.getValue() == guard.isNegated()) { - DeoptimizeNode deopt = new DeoptimizeNode(guard.getAction(), guard.getReason(), guard.getSpeculation()); - if (guard.stateBefore() != null) { - deopt.setStateBefore(guard.stateBefore()); - } - canonical = deopt; - } else { - /* - * The guard is unnecessary, but we cannot remove the node completely yet - * because there might be nodes that use it as a guard input. Therefore, we - * replace it with a more lightweight node (which is floating and has no - * inputs). - */ - canonical = new CanonicalizeToNullNode(node.stamp); - } - handleCanonicalization(methodScope, loopScope, nodeOrderId, node, canonical); - } - + return node; } else if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool(methodScope.graph.getAssumptions(), methodScope.graph.getOptions())); - if (canonical != node) { - handleCanonicalization(methodScope, loopScope, nodeOrderId, node, canonical); - } + return ((Canonicalizable) node).canonical(canonicalizerTool); + } else { + return node; } } - private void handleCanonicalization(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node, Node c) { - Node canonical = c; + private static Node canonicalizeFixedNodeToNull(FixedNode node) { + /* + * When a node is unnecessary, we must not remove it right away because there might be nodes + * that use it as a guard input. Therefore, we replace it with a more lightweight node + * (which is floating and has no inputs). + */ + return new CanonicalizeToNullNode(node.stamp); + } - if (canonical == null) { - /* - * This is a possible return value of canonicalization. However, we might need to add - * additional usages later on for which we need a node. Therefore, we just do nothing - * and leave the node in place. - */ - return; - } - + private void handleCanonicalization(LoopScope loopScope, int nodeOrderId, FixedNode node, Node c) { + assert c != node : "unnecessary call"; + Node canonical = c == null ? canonicalizeFixedNodeToNull(node) : c; if (!canonical.isAlive()) { assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + canonical = graph.addOrUniqueWithInputs(canonical); if (canonical instanceof FixedWithNextNode) { - methodScope.graph.addBeforeFixed(node, (FixedWithNextNode) canonical); + graph.addBeforeFixed(node, (FixedWithNextNode) canonical); } else if (canonical instanceof ControlSinkNode) { FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor(); predecessor.setNext((ControlSinkNode) canonical); @@ -291,7 +301,7 @@ ((ValueNode) node).inferStamp(); } if (node instanceof Canonicalizable) { - Node canonical = ((Canonicalizable) node).canonical(new PECanonicalizerTool(methodScope.graph.getAssumptions(), methodScope.graph.getOptions())); + Node canonical = ((Canonicalizable) node).canonical(canonicalizerTool); if (canonical == null) { /* * This is a possible return value of canonicalization. However, we might need to @@ -301,10 +311,9 @@ } else if (canonical != node) { if (!canonical.isAlive()) { assert !canonical.isDeleted(); - canonical = methodScope.graph.addOrUniqueWithInputs(canonical); + canonical = graph.addOrUniqueWithInputs(canonical); } assert node.hasNoUsages(); - // methodScope.graph.replaceFloating((FloatingNode) node, canonical); return canonical; } } @@ -317,6 +326,6 @@ * In contrast to the base class implementation, we do not need to exactly reproduce the * encoded graph. Since we do canonicalization, we also want nodes to be unique. */ - return methodScope.graph.addOrUnique(node); + return graph.addOrUnique(node); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java Thu Apr 06 14:31:32 2017 -0700 @@ -37,7 +37,6 @@ import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeMap; -import org.graalvm.compiler.graph.spi.SimplifierTool; import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; @@ -553,12 +552,8 @@ node.safeDelete(); } + @SuppressWarnings("static-method") public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) { - removeSplitPropagate(node, survivingSuccessor, null); - } - - @SuppressWarnings("static-method") - public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor, SimplifierTool tool) { assert node != null; assert node.hasNoUsages(); assert survivingSuccessor != null; @@ -569,7 +564,7 @@ for (Node successor : snapshot) { if (successor != null && successor.isAlive()) { if (successor != survivingSuccessor) { - GraphUtil.killCFG((FixedNode) successor, tool); + GraphUtil.killCFG((FixedNode) successor); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -57,28 +57,16 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; + } + if (x.isConstant() && !y.isConstant()) { + return canonical(null, op, y, x); } else { - return new AddNode(x, y).maybeCommuteInputs(); + return canonical(null, op, x, y); } } - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - ValueNode ret = super.canonical(tool, forX, forY); - if (ret != this) { - return ret; - } - - if (forX.isConstant() && !forY.isConstant()) { - // we try to swap and canonicalize - ValueNode improvement = canonical(tool, forY, forX); - if (improvement != this) { - return improvement; - } - // if this fails we only swap - return new AddNode(forY, forX); - } - BinaryOp op = getOp(forX, forY); + private static ValueNode canonical(AddNode addNode, BinaryOp op, ValueNode forX, ValueNode forY) { + AddNode self = addNode; boolean associative = op.isAssociative(); if (associative) { if (forX instanceof SubNode) { @@ -101,10 +89,10 @@ if (op.isNeutral(c)) { return forX; } - if (associative) { + if (associative && self != null) { // canonicalize expressions like "(a + 1) + 2" - ValueNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY); - if (reassociated != this) { + ValueNode reassociated = reassociate(self, ValueNode.isConstantPredicate(), forX, forY); + if (reassociated != self) { return reassociated; } } @@ -114,7 +102,30 @@ } else if (forY instanceof NegateNode) { return BinaryArithmeticNode.sub(forX, ((NegateNode) forY).getValue()); } - return this; + if (self == null) { + self = (AddNode) new AddNode(forX, forY).maybeCommuteInputs(); + } + return self; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + ValueNode ret = super.canonical(tool, forX, forY); + if (ret != this) { + return ret; + } + + if (forX.isConstant() && !forY.isConstant()) { + // we try to swap and canonicalize + ValueNode improvement = canonical(tool, forY, forX); + if (improvement != this) { + return improvement; + } + // if this fails we only swap + return new AddNode(forY, forX); + } + BinaryOp op = getOp(forX, forY); + return canonical(this, op, forX, forY); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AndNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -57,9 +57,8 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new AndNode(x, y).maybeCommuteInputs(); } + return canonical(null, op, stamp, x, y); } @Override @@ -69,6 +68,10 @@ return ret; } + return canonical(this, getOp(forX, forY), stamp(), forX, forY); + } + + private static ValueNode canonical(AndNode self, BinaryOp op, Stamp stamp, ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return forX; } @@ -77,15 +80,15 @@ } if (forY.isConstant()) { Constant c = forY.asConstant(); - if (getOp(forX, forY).isNeutral(c)) { + if (op.isNeutral(c)) { return forX; } if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { long rawY = ((PrimitiveConstant) c).asLong(); - long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp())); + long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp)); if ((rawY & mask) == 0) { - return ConstantNode.forIntegerStamp(stamp(), 0); + return ConstantNode.forIntegerStamp(stamp, 0); } if (forX instanceof SignExtendNode) { SignExtendNode ext = (SignExtendNode) forX; @@ -100,9 +103,12 @@ } } - return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); + return reassociate(self != null ? self : (AndNode) new AndNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY); } - return this; + if (forX instanceof NotNode && forY instanceof NotNode) { + return new NotNode(OrNode.create(((NotNode) forX).getValue(), ((NotNode) forY).getValue())); + } + return self != null ? self : new AndNode(forX, forY).maybeCommuteInputs(); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -44,6 +44,7 @@ import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.PrimitiveConstant; @NodeInfo(cycles = CYCLES_1) public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary { @@ -151,12 +152,19 @@ } public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) { - if (forX.isConstant() && forY.isConstant() && constantReflection != null) { + if (forX.isConstant() && forY.isConstant() && (constantReflection != null || forX.asConstant() instanceof PrimitiveConstant)) { return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue)); } return null; } + public static LogicNode tryConstantFoldPrimitive(Condition condition, ValueNode forX, ValueNode forY, boolean unorderedIsTrue) { + if (forX.asConstant() instanceof PrimitiveConstant && forY.asConstant() instanceof PrimitiveConstant) { + return LogicConstantNode.forBoolean(condition.foldCondition((PrimitiveConstant) forX.asConstant(), (PrimitiveConstant) forY.asConstant(), unorderedIsTrue)); + } + return null; + } + /** * Does this operation represent an identity check such that for x == y, x is exactly the same * thing as y. This is generally true except for some floating point comparisons. @@ -221,7 +229,7 @@ public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { LogicNode result = createCompareNode(condition, x, y, constantReflection); - return (result.graph() == null ? graph.unique(result) : result); + return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result); } public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { @@ -237,15 +245,15 @@ comparison = PointerEqualsNode.create(x, y); } else { assert x.getStackKind().isNumericInteger(); - comparison = IntegerEqualsNode.create(x, y, constantReflection); + comparison = IntegerEqualsNode.create(x, y); } } else if (condition == Condition.LT) { assert x.getStackKind().isNumericInteger(); - comparison = IntegerLessThanNode.create(x, y, constantReflection); + comparison = IntegerLessThanNode.create(x, y); } else { assert condition == Condition.BT; assert x.getStackKind().isNumericInteger(); - comparison = IntegerBelowNode.create(x, y, constantReflection); + comparison = IntegerBelowNode.create(x, y); } return comparison; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -83,6 +83,10 @@ if (synonym != null) { return synonym; } + ValueNode result = canonicalizeConditional(condition, trueValue, falseValue, trueValue.stamp().meet(falseValue.stamp())); + if (result != null) { + return result; + } return new ConditionalNode(condition, trueValue, falseValue); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -58,9 +58,8 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new DivNode(x, y); } + return canonical(null, op, x, y); } @Override @@ -70,9 +69,13 @@ return ret; } + return canonical(this, getOp(forX, forY), forX, forY); + } + + private static ValueNode canonical(DivNode self, BinaryOp
op, ValueNode forX, ValueNode forY) { if (forY.isConstant()) { Constant c = forY.asConstant(); - if (getOp(forX, forY).isNeutral(c)) { + if (op.isNeutral(c)) { return forX; } if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { @@ -88,14 +91,14 @@ } if (divResult != null) { if (signFlip) { - return new NegateNode(divResult); + return NegateNode.create(divResult); } else { return divResult; } } } } - return this; + return self != null ? self : new DivNode(forX, forY); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -37,7 +37,6 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; -import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.TriState; @NodeInfo(shortName = "==", cycles = NodeCycles.CYCLES_3) @@ -50,8 +49,8 @@ assert x.stamp().isCompatible(y.stamp()); } - public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { - LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + public static LogicNode create(ValueNode x, ValueNode y) { + LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false); if (result != null) { return result; } else { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -36,7 +36,6 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; -import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.TriState; @NodeInfo(shortName = "<", cycles = NodeCycles.CYCLES_3) @@ -49,8 +48,8 @@ assert x.stamp().isCompatible(y.stamp()); } - public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue, ConstantReflectionProvider constantReflection) { - LogicNode result = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, unorderedIsTrue); + public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue) { + LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.LT, x, y, unorderedIsTrue); if (result != null) { return result; } else { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,7 +32,6 @@ import org.graalvm.compiler.nodes.ValueNode; import jdk.vm.ci.code.CodeUtil; -import jdk.vm.ci.meta.ConstantReflectionProvider; @NodeInfo(shortName = "|<|") public final class IntegerBelowNode extends IntegerLowerThanNode { @@ -45,8 +44,8 @@ assert y.stamp() instanceof IntegerStamp; } - public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { - return OP.create(x, y, constantReflection); + public static LogicNode create(ValueNode x, ValueNode y) { + return OP.create(x, y); } @Override @@ -108,7 +107,7 @@ } @Override - protected IntegerLowerThanNode create(ValueNode x, ValueNode y) { + protected IntegerLowerThanNode createNode(ValueNode x, ValueNode y) { return new IntegerBelowNode(x, y); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -40,7 +40,6 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.TriState; @@ -55,8 +54,8 @@ assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object; } - public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { - LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false); + public static LogicNode create(ValueNode x, ValueNode y) { + LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false); if (result != null) { return result; } else { @@ -117,6 +116,29 @@ } else if (forX.stamp().alwaysDistinct(forY.stamp())) { return LogicConstantNode.contradiction(); } + if (forX instanceof AddNode && forY instanceof AddNode) { + AddNode addX = (AddNode) forX; + AddNode addY = (AddNode) forY; + ValueNode v1 = null; + ValueNode v2 = null; + if (addX.getX() == addY.getX()) { + v1 = addX.getY(); + v2 = addY.getY(); + } else if (addX.getX() == addY.getY()) { + v1 = addX.getY(); + v2 = addY.getX(); + } else if (addX.getY() == addY.getX()) { + v1 = addX.getX(); + v2 = addY.getY(); + } else if (addX.getY() == addY.getY()) { + v1 = addX.getX(); + v2 = addY.getX(); + } + if (v1 != null) { + assert v2 != null; + return create(v1, v2); + } + } return super.canonical(tool, forX, forY); } @@ -130,14 +152,14 @@ // nonConstant can only be 0 or 1 (respective -1), test against 0 instead of 1 // (respective -1) for a more canonical graph and also to allow for faster execution // on specific platforms. - return LogicNegationNode.create(IntegerEqualsNode.create(nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0), null)); + return LogicNegationNode.create(IntegerEqualsNode.create(nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0))); } else if (primitiveConstant.asLong() == 0) { if (nonConstant instanceof AndNode) { AndNode andNode = (AndNode) nonConstant; return new IntegerTestNode(andNode.getX(), andNode.getY()); } else if (nonConstant instanceof SubNode) { SubNode subNode = (SubNode) nonConstant; - return IntegerEqualsNode.create(subNode.getX(), subNode.getY(), tool.getConstantReflection()); + return IntegerEqualsNode.create(subNode.getX(), subNode.getY()); } else if (nonConstant instanceof ShiftNode && nonConstant.stamp() instanceof IntegerStamp) { if (nonConstant instanceof LeftShiftNode) { LeftShiftNode shift = (LeftShiftNode) nonConstant; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -31,15 +31,14 @@ import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.LogicNegationNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.ValueNode; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PrimitiveConstant; @@ -55,8 +54,8 @@ assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object; } - public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { - return OP.create(x, y, constantReflection); + public static LogicNode create(ValueNode x, ValueNode y) { + return OP.create(x, y); } @Override @@ -91,79 +90,6 @@ } @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - ValueNode result = super.canonical(tool, forX, forY); - if (result != this) { - return result; - } - if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { - if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) { - return new IntegerBelowNode(forX, forY); - } - } - if (forY.isConstant() && forY.asConstant().isDefaultForKind() && forX instanceof SubNode) { - // (x - y) < 0 when x - y is known not to underflow <=> x < y - SubNode sub = (SubNode) forX; - IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp(); - IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp(); - long minValue = CodeUtil.minValue(xStamp.getBits()); - long maxValue = CodeUtil.maxValue(xStamp.getBits()); - - if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) { - return new IntegerLessThanNode(sub.getX(), sub.getY()); - } - } - - int bits = ((IntegerStamp) getX().stamp()).getBits(); - assert ((IntegerStamp) getY().stamp()).getBits() == bits; - long min = OP.minValue(bits); - long xResidue = 0; - ValueNode left = null; - JavaConstant leftCst = null; - if (forX instanceof AddNode) { - AddNode xAdd = (AddNode) forX; - if (xAdd.getY().isJavaConstant()) { - long xCst = xAdd.getY().asJavaConstant().asLong(); - xResidue = xCst - min; - left = xAdd.getX(); - } - } else if (forX.isJavaConstant()) { - leftCst = forX.asJavaConstant(); - } - if (left != null || leftCst != null) { - long yResidue = 0; - ValueNode right = null; - JavaConstant rightCst = null; - if (forY instanceof AddNode) { - AddNode yAdd = (AddNode) forY; - if (yAdd.getY().isJavaConstant()) { - long yCst = yAdd.getY().asJavaConstant().asLong(); - yResidue = yCst - min; - right = yAdd.getX(); - } - } else if (forY.isJavaConstant()) { - rightCst = forY.asJavaConstant(); - } - if (right != null || rightCst != null) { - if ((xResidue == 0 && left != null) || (yResidue == 0 && right != null)) { - if (left == null) { - left = ConstantNode.forIntegerBits(bits, leftCst.asLong() - min); - } else if (xResidue != 0) { - left = AddNode.create(left, ConstantNode.forIntegerBits(bits, xResidue)); - } - if (right == null) { - right = ConstantNode.forIntegerBits(bits, rightCst.asLong() - min); - } else if (yResidue != 0) { - right = AddNode.create(right, ConstantNode.forIntegerBits(bits, yResidue)); - } - return new IntegerBelowNode(left, right); - } - } - } - return this; - } - - @Override protected CompareNode duplicateModified(ValueNode newX, ValueNode newY) { if (newX.stamp() instanceof FloatStamp && newY.stamp() instanceof FloatStamp) { return new FloatLessThanNode(newX, newY, true); @@ -176,12 +102,104 @@ public static class LessThanOp extends LowerOp { @Override + protected LogicNode findSynonym(ValueNode forX, ValueNode forY) { + LogicNode result = super.findSynonym(forX, forY); + if (result != null) { + return result; + } + if (forX.stamp() instanceof IntegerStamp && forY.stamp() instanceof IntegerStamp) { + if (IntegerStamp.sameSign((IntegerStamp) forX.stamp(), (IntegerStamp) forY.stamp())) { + return new IntegerBelowNode(forX, forY); + } + } + if (forY.isConstant() && forX instanceof SubNode) { + SubNode sub = (SubNode) forX; + ValueNode xx = null; + ValueNode yy = null; + boolean negate = false; + if (forY.asConstant().isDefaultForKind()) { + // (x - y) < 0 when x - y is known not to underflow <=> x < y + xx = sub.getX(); + yy = sub.getY(); + } else if (forY.isJavaConstant() && forY.asJavaConstant().asLong() == 1) { + // (x - y) < 1 when x - y is known not to underflow <=> !(y < x) + xx = sub.getY(); + yy = sub.getX(); + negate = true; + } + if (xx != null) { + assert yy != null; + IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp(); + IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp(); + long minValue = CodeUtil.minValue(xStamp.getBits()); + long maxValue = CodeUtil.maxValue(xStamp.getBits()); + + if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) { + LogicNode logic = new IntegerLessThanNode(xx, yy); + if (negate) { + logic = LogicNegationNode.create(logic); + } + return logic; + } + } + } + + int bits = ((IntegerStamp) forX.stamp()).getBits(); + assert ((IntegerStamp) forY.stamp()).getBits() == bits; + long min = OP.minValue(bits); + long xResidue = 0; + ValueNode left = null; + JavaConstant leftCst = null; + if (forX instanceof AddNode) { + AddNode xAdd = (AddNode) forX; + if (xAdd.getY().isJavaConstant()) { + long xCst = xAdd.getY().asJavaConstant().asLong(); + xResidue = xCst - min; + left = xAdd.getX(); + } + } else if (forX.isJavaConstant()) { + leftCst = forX.asJavaConstant(); + } + if (left != null || leftCst != null) { + long yResidue = 0; + ValueNode right = null; + JavaConstant rightCst = null; + if (forY instanceof AddNode) { + AddNode yAdd = (AddNode) forY; + if (yAdd.getY().isJavaConstant()) { + long yCst = yAdd.getY().asJavaConstant().asLong(); + yResidue = yCst - min; + right = yAdd.getX(); + } + } else if (forY.isJavaConstant()) { + rightCst = forY.asJavaConstant(); + } + if (right != null || rightCst != null) { + if ((xResidue == 0 && left != null) || (yResidue == 0 && right != null)) { + if (left == null) { + left = ConstantNode.forIntegerBits(bits, leftCst.asLong() - min); + } else if (xResidue != 0) { + left = AddNode.create(left, ConstantNode.forIntegerBits(bits, xResidue)); + } + if (right == null) { + right = ConstantNode.forIntegerBits(bits, rightCst.asLong() - min); + } else if (yResidue != 0) { + right = AddNode.create(right, ConstantNode.forIntegerBits(bits, yResidue)); + } + return new IntegerBelowNode(left, right); + } + } + } + return null; + } + + @Override protected Condition getCondition() { return LT; } @Override - protected IntegerLowerThanNode create(ValueNode x, ValueNode y) { + protected IntegerLowerThanNode createNode(ValueNode x, ValueNode y) { return new IntegerLessThanNode(x, y); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -28,13 +28,13 @@ import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.LogicConstantNode; import org.graalvm.compiler.nodes.LogicNegationNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; -import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.TriState; /** @@ -65,51 +65,9 @@ if (synonym != null) { return synonym; } - if (forY.stamp() instanceof IntegerStamp) { - IntegerStamp yStamp = (IntegerStamp) forY.stamp(); - if (forX.isConstant() && forX.asJavaConstant().asLong() == getOp().minValue(yStamp.getBits())) { - // MIN < y is the same as y != MIN - return LogicNegationNode.create(CompareNode.createCompareNode(Condition.EQ, forY, forX, tool.getConstantReflection())); - } - if (forY instanceof AddNode) { - AddNode addNode = (AddNode) forY; - ValueNode canonical = canonicalizeXLowerXPlusA(forX, addNode, false, true); - if (canonical != null) { - return canonical; - } - } - if (forX instanceof AddNode) { - AddNode addNode = (AddNode) forX; - ValueNode canonical = canonicalizeXLowerXPlusA(forY, addNode, true, false); - if (canonical != null) { - return canonical; - } - } - } return this; } - private ValueNode canonicalizeXLowerXPlusA(ValueNode forX, AddNode addNode, boolean negated, boolean strict) { - // x < x + a - Stamp succeedingXStamp; - if (addNode.getX() == forX && addNode.getY().stamp() instanceof IntegerStamp) { - succeedingXStamp = getOp().getSucceedingStampForXLowerXPlusA(negated, strict, (IntegerStamp) addNode.getY().stamp()); - } else if (addNode.getY() == forX && addNode.getX().stamp() instanceof IntegerStamp) { - succeedingXStamp = getOp().getSucceedingStampForXLowerXPlusA(negated, strict, (IntegerStamp) addNode.getX().stamp()); - } else { - return null; - } - succeedingXStamp = forX.stamp().join(succeedingXStamp); - if (succeedingXStamp.isEmpty()) { - return LogicConstantNode.contradiction(); - } - /* - * since getSucceedingStampForXLowerXPlusA is only best effort, - * succeedingXStamp.equals(xStamp) does not imply tautology - */ - return null; - } - @Override public Stamp getSucceedingStampForX(boolean negated, Stamp xStampGeneric, Stamp yStampGeneric) { return getSucceedingStampForX(negated, !negated, xStampGeneric, yStampGeneric, getX(), getY()); @@ -196,10 +154,10 @@ protected abstract Condition getCondition(); - protected abstract IntegerLowerThanNode create(ValueNode x, ValueNode y); + protected abstract IntegerLowerThanNode createNode(ValueNode x, ValueNode y); - public LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection) { - LogicNode result = CompareNode.tryConstantFold(getCondition(), x, y, constantReflection, false); + public LogicNode create(ValueNode x, ValueNode y) { + LogicNode result = CompareNode.tryConstantFoldPrimitive(getCondition(), x, y, false); if (result != null) { return result; } else { @@ -207,7 +165,7 @@ if (result != null) { return result; } - return create(x, y); + return createNode(x, y); } } @@ -221,6 +179,73 @@ } else if (fold.isFalse()) { return LogicConstantNode.contradiction(); } + if (forY.stamp() instanceof IntegerStamp) { + IntegerStamp yStamp = (IntegerStamp) forY.stamp(); + int bits = yStamp.getBits(); + if (forX.isJavaConstant() && !forY.isConstant()) { + // bring the constant on the right + long xValue = forX.asJavaConstant().asLong(); + if (xValue != maxValue(bits)) { + // c < x <=> !(c >= x) <=> !(x <= c) <=> !(x < c + 1) + return LogicNegationNode.create(create(forY, ConstantNode.forIntegerStamp(yStamp, xValue + 1))); + } + } + if (forY.isJavaConstant()) { + long yValue = forY.asJavaConstant().asLong(); + if (yValue == maxValue(bits)) { + // x < MAX <=> x != MAX + return LogicNegationNode.create(IntegerEqualsNode.create(forX, forY)); + } + if (yValue == minValue(bits) + 1) { + // x < MIN + 1 <=> x <= MIN <=> x == MIN + return IntegerEqualsNode.create(forX, ConstantNode.forIntegerStamp(yStamp, minValue(bits))); + } + } else if (forY instanceof AddNode) { + AddNode addNode = (AddNode) forY; + LogicNode canonical = canonicalizeXLowerXPlusA(forX, addNode, false, true); + if (canonical != null) { + return canonical; + } + } + if (forX instanceof AddNode) { + AddNode addNode = (AddNode) forX; + LogicNode canonical = canonicalizeXLowerXPlusA(forY, addNode, true, false); + if (canonical != null) { + return canonical; + } + } + } + return null; + } + + private LogicNode canonicalizeXLowerXPlusA(ValueNode forX, AddNode addNode, boolean mirrored, boolean strict) { + // x < x + a + IntegerStamp succeedingXStamp; + boolean exact; + if (addNode.getX() == forX && addNode.getY().stamp() instanceof IntegerStamp) { + IntegerStamp aStamp = (IntegerStamp) addNode.getY().stamp(); + succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp); + exact = aStamp.lowerBound() == aStamp.upperBound(); + } else if (addNode.getY() == forX && addNode.getX().stamp() instanceof IntegerStamp) { + IntegerStamp aStamp = (IntegerStamp) addNode.getX().stamp(); + succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp); + exact = aStamp.lowerBound() == aStamp.upperBound(); + } else { + return null; + } + if (succeedingXStamp.join(forX.stamp()).isEmpty()) { + return LogicConstantNode.contradiction(); + } else if (exact && !succeedingXStamp.isEmpty()) { + int bits = succeedingXStamp.getBits(); + if (compare(lowerBound(succeedingXStamp), minValue(bits)) > 0) { + assert upperBound(succeedingXStamp) == maxValue(bits); + // x must be in [L..MAX] <=> x >= L <=> !(x < L) + return LogicNegationNode.create(create(forX, ConstantNode.forIntegerStamp(succeedingXStamp, lowerBound(succeedingXStamp)))); + } else if (compare(upperBound(succeedingXStamp), maxValue(bits)) < 0) { + // x must be in [MIN..H] <=> x <= H <=> !(H < x) + return LogicNegationNode.create(create(ConstantNode.forIntegerStamp(succeedingXStamp, upperBound(succeedingXStamp)), forX)); + } + } return null; } @@ -268,7 +293,7 @@ return null; } - protected IntegerStamp getSucceedingStampForXLowerXPlusA(boolean negated, boolean strict, IntegerStamp a) { + protected IntegerStamp getSucceedingStampForXLowerXPlusA(boolean mirrored, boolean strict, IntegerStamp a) { int bits = a.getBits(); long min = minValue(bits); long max = maxValue(bits); @@ -286,7 +311,7 @@ * This does not use upper/lowerBound from LowerOp because it's about the (signed) * addition not the comparison. */ - if (negated) { + if (mirrored) { if (a.contains(0)) { // a may be zero return a.unrestricted(); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -57,8 +57,7 @@ } public static LogicNode create(ValueNode forValue) { - LogicNode result = tryCanonicalize(forValue); - return result == null ? new IsNullNode(GraphUtil.skipPi(forValue)) : result; + return canonicalized(null, forValue); } public static LogicNode tryCanonicalize(ValueNode forValue) { @@ -84,7 +83,11 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { + return canonicalized(this, forValue); + } + private static LogicNode canonicalized(IsNullNode isNullNode, ValueNode forValue) { + IsNullNode self = isNullNode; LogicNode result = tryCanonicalize(forValue); if (result != null) { return result; @@ -101,7 +104,10 @@ } } - return this; + if (self == null) { + self = new IsNullNode(GraphUtil.skipPi(forValue)); + } + return self; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/LeftShiftNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -24,6 +24,8 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shl; +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; @@ -43,6 +45,17 @@ super(TYPE, ArithmeticOpTable::getShl, x, y); } + public static ValueNode create(ValueNode x, ValueNode y) { + ArithmeticOpTable.ShiftOp op = ArithmeticOpTable.forStamp(x.stamp()).getShl(); + Stamp stamp = op.foldStamp(x.stamp(), (IntegerStamp) y.stamp()); + ValueNode value = ShiftNode.canonical(op, stamp, x, y); + if (value != null) { + return value; + } + + return canonical(null, op, stamp, x, y); + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode ret = super.canonical(tool, forX, forY); @@ -50,10 +63,15 @@ return ret; } + return canonical(this, getArithmeticOp(), stamp(), forX, forY); + } + + private static ValueNode canonical(LeftShiftNode leftShiftNode, ArithmeticOpTable.ShiftOp op, Stamp stamp, ValueNode forX, ValueNode forY) { + LeftShiftNode self = leftShiftNode; if (forY.isConstant()) { int amount = forY.asJavaConstant().asInt(); - int originalAmout = amount; - int mask = getShiftAmountMask(); + int originalAmount = amount; + int mask = op.getShiftAmountMask(stamp); amount &= mask; if (amount == 0) { return forX; @@ -65,24 +83,27 @@ if (other instanceof LeftShiftNode) { int total = amount + otherAmount; if (total != (total & mask)) { - return ConstantNode.forIntegerKind(getStackKind(), 0); + return ConstantNode.forIntegerKind(stamp.getStackKind(), 0); } return new LeftShiftNode(other.getX(), ConstantNode.forInt(total)); } else if ((other instanceof RightShiftNode || other instanceof UnsignedRightShiftNode) && otherAmount == amount) { - if (getStackKind() == JavaKind.Long) { + if (stamp.getStackKind() == JavaKind.Long) { return new AndNode(other.getX(), ConstantNode.forLong(-1L << amount)); } else { - assert getStackKind() == JavaKind.Int; + assert stamp.getStackKind() == JavaKind.Int; return new AndNode(other.getX(), ConstantNode.forInt(-1 << amount)); } } } } - if (originalAmout != amount) { + if (originalAmount != amount) { return new LeftShiftNode(forX, ConstantNode.forInt(amount)); } } - return this; + if (self == null) { + self = new LeftShiftNode(forX, forY); + } + return self; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/MulNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -60,9 +60,8 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new MulNode(x, y).maybeCommuteInputs(); } + return canonical(null, op, stamp, x, y); } @Override @@ -81,8 +80,12 @@ // if this fails we only swap return new MulNode(forY, forX); } + BinaryOp op = getOp(forX, forY); + return canonical(this, op, stamp(), forX, forY); + } + + private static ValueNode canonical(MulNode self, BinaryOp op, Stamp stamp, ValueNode forX, ValueNode forY) { if (forY.isConstant()) { - BinaryOp op = getOp(forX, forY); Constant c = forY.asConstant(); if (op.isNeutral(c)) { return forX; @@ -96,7 +99,7 @@ } else if (i == 1) { return forX; } else if (i == -1) { - return new NegateNode(forX); + return NegateNode.create(forX); } else if (i > 0) { if (CodeUtil.isPowerOf2(i)) { return new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i))); @@ -107,17 +110,17 @@ } } else if (i < 0) { if (CodeUtil.isPowerOf2(-i)) { - return new NegateNode(new LeftShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(-i)))); + return NegateNode.create(LeftShiftNode.create(forX, ConstantNode.forInt(CodeUtil.log2(-i)))); } } } if (op.isAssociative()) { // canonicalize expressions like "(a * 1) * 2" - return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); + return reassociate(self != null ? self : (MulNode) new MulNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY); } } - return this; + return self != null ? self : new MulNode(forX, forY).maybeCommuteInputs(); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -49,20 +49,37 @@ super(TYPE, ArithmeticOpTable::getNeg, value); } + public static ValueNode create(ValueNode value) { + ValueNode synonym = findSynonym(value); + if (synonym != null) { + return synonym; + } + return new NegateNode(value); + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { - ValueNode ret = super.canonical(tool, forValue); - if (ret != this) { - return ret; + ValueNode synonym = findSynonym(forValue, getOp(forValue)); + if (synonym != null) { + return synonym; + } + return this; + } + + protected static ValueNode findSynonym(ValueNode forValue) { + ArithmeticOpTable.UnaryOp negOp = ArithmeticOpTable.forStamp(forValue.stamp()).getNeg(); + ValueNode synonym = UnaryArithmeticNode.findSynonym(forValue, negOp); + if (synonym != null) { + return synonym; } if (forValue instanceof NegateNode) { return ((NegateNode) forValue).getValue(); } if (forValue instanceof SubNode && !(forValue.stamp() instanceof FloatStamp)) { SubNode sub = (SubNode) forValue; - return new SubNode(sub.getY(), sub.getX()); + return SubNode.create(sub.getY(), sub.getX()); } - return this; + return null; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -93,11 +93,11 @@ LogicNode equalComp; LogicNode lessComp; if (getX().stamp() instanceof FloatStamp) { - equalComp = graph().unique(FloatEqualsNode.create(getX(), getY(), tool.getConstantReflection())); - lessComp = graph().unique(FloatLessThanNode.create(getX(), getY(), isUnorderedLess, tool.getConstantReflection())); + equalComp = graph().addOrUniqueWithInputs(FloatEqualsNode.create(getX(), getY())); + lessComp = graph().addOrUniqueWithInputs(FloatLessThanNode.create(getX(), getY(), isUnorderedLess)); } else { - equalComp = graph().unique(IntegerEqualsNode.create(getX(), getY(), tool.getConstantReflection())); - lessComp = graph().unique(IntegerLessThanNode.create(getX(), getY(), tool.getConstantReflection())); + equalComp = graph().addOrUniqueWithInputs(IntegerEqualsNode.create(getX(), getY())); + lessComp = graph().addOrUniqueWithInputs(IntegerLessThanNode.create(getX(), getY())); } ConditionalNode equalValue = graph().unique(new ConditionalNode(equalComp, ConstantNode.forInt(0, graph()), ConstantNode.forInt(1, graph()))); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/OrNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -56,9 +56,8 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new OrNode(x, y).maybeCommuteInputs(); } + return canonical(null, op, stamp, x, y); } @Override @@ -68,6 +67,10 @@ return ret; } + return canonical(this, getOp(forX, forY), stamp(), forX, forY); + } + + private static ValueNode canonical(OrNode self, BinaryOp op, Stamp stamp, ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return forX; } @@ -76,20 +79,23 @@ } if (forY.isConstant()) { Constant c = forY.asConstant(); - if (getOp(forX, forY).isNeutral(c)) { + if (op.isNeutral(c)) { return forX; } if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { long rawY = ((PrimitiveConstant) c).asLong(); - long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp())); + long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp)); if ((rawY & mask) == mask) { - return ConstantNode.forIntegerStamp(stamp(), mask); + return ConstantNode.forIntegerStamp(stamp, mask); } } - return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); + return reassociate(self != null ? self : (OrNode) new OrNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY); } - return this; + if (forX instanceof NotNode && forY instanceof NotNode) { + return new NotNode(AndNode.create(((NotNode) forX).getValue(), ((NotNode) forY).getValue())); + } + return self != null ? self : new OrNode(forX, forY).maybeCommuteInputs(); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,7 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp.Shr; import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool; @@ -44,6 +45,17 @@ super(TYPE, ArithmeticOpTable::getShr, x, y); } + public static ValueNode create(ValueNode x, ValueNode y) { + ArithmeticOpTable.ShiftOp op = ArithmeticOpTable.forStamp(x.stamp()).getShr(); + Stamp stamp = op.foldStamp(x.stamp(), (IntegerStamp) y.stamp()); + ValueNode value = ShiftNode.canonical(op, stamp, x, y); + if (value != null) { + return value; + } + + return canonical(null, op, stamp, x, y); + } + @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { ValueNode ret = super.canonical(tool, forX, forY); @@ -51,6 +63,11 @@ return ret; } + return canonical(this, getArithmeticOp(), stamp(), forX, forY); + } + + private static ValueNode canonical(RightShiftNode rightShiftNode, ArithmeticOpTable.ShiftOp op, Stamp stamp, ValueNode forX, ValueNode forY) { + RightShiftNode self = rightShiftNode; if (forX.stamp() instanceof IntegerStamp && ((IntegerStamp) forX.stamp()).isPositive()) { return new UnsignedRightShiftNode(forX, forY); } @@ -58,7 +75,7 @@ if (forY.isConstant()) { int amount = forY.asJavaConstant().asInt(); int originalAmout = amount; - int mask = getShiftAmountMask(); + int mask = op.getShiftAmountMask(stamp); amount &= mask; if (amount == 0) { return forX; @@ -74,10 +91,10 @@ IntegerStamp istamp = (IntegerStamp) other.getX().stamp(); if (istamp.isPositive()) { - return ConstantNode.forIntegerKind(getStackKind(), 0); + return ConstantNode.forIntegerKind(stamp.getStackKind(), 0); } if (istamp.isStrictlyNegative()) { - return ConstantNode.forIntegerKind(getStackKind(), -1L); + return ConstantNode.forIntegerKind(stamp.getStackKind(), -1L); } /* @@ -95,7 +112,10 @@ return new RightShiftNode(forX, ConstantNode.forInt(amount)); } } - return this; + if (self == null) { + self = new RightShiftNode(forX, forY); + } + return self; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ShiftNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -85,12 +85,20 @@ @Override public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + ValueNode valueNode = canonical(getOp(forX), stamp(), forX, forY); + if (valueNode != null) { + return valueNode; + } + return this; + } + + public static ValueNode canonical(ShiftOp op, Stamp stamp, ValueNode forX, ValueNode forY) { if (forX.isConstant() && forY.isConstant()) { JavaConstant amount = forY.asJavaConstant(); assert amount.getJavaKind() == JavaKind.Int; - return ConstantNode.forPrimitive(stamp(), getOp(forX).foldConstant(forX.asConstant(), amount.asInt())); + return ConstantNode.forPrimitive(stamp, op.foldConstant(forX.asConstant(), amount.asInt())); } - return this; + return null; } public int getShiftAmountMask() { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -63,9 +63,8 @@ ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp())); if (synonym != null) { return synonym; - } else { - return new SignExtendNode(input, inputBits, resultBits); } + return canonical(null, input, inputBits, resultBits); } @Override @@ -80,30 +79,34 @@ return ret; } + return canonical(this, forValue, getInputBits(), getResultBits()); + } + + private static ValueNode canonical(SignExtendNode self, ValueNode forValue, int inputBits, int resultBits) { if (forValue instanceof SignExtendNode) { // sxxx -(sign-extend)-> ssss sxxx -(sign-extend)-> ssssssss sssssxxx // ==> sxxx -(sign-extend)-> ssssssss sssssxxx SignExtendNode other = (SignExtendNode) forValue; - return SignExtendNode.create(other.getValue(), other.getInputBits(), getResultBits()); + return SignExtendNode.create(other.getValue(), other.getInputBits(), resultBits); } else if (forValue instanceof ZeroExtendNode) { ZeroExtendNode other = (ZeroExtendNode) forValue; if (other.getResultBits() > other.getInputBits()) { // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx // ==> sxxx -(zero-extend)-> 00000000 0000sxxx - return ZeroExtendNode.create(other.getValue(), other.getInputBits(), getResultBits()); + return ZeroExtendNode.create(other.getValue(), other.getInputBits(), resultBits); } } if (forValue.stamp() instanceof IntegerStamp) { IntegerStamp inputStamp = (IntegerStamp) forValue.stamp(); - if ((inputStamp.upMask() & (1L << (getInputBits() - 1))) == 0L) { + if ((inputStamp.upMask() & (1L << (inputBits - 1))) == 0L) { // 0xxx -(sign-extend)-> 0000 0xxx // ==> 0xxx -(zero-extend)-> 0000 0xxx - return ZeroExtendNode.create(forValue, getInputBits(), getResultBits()); + return ZeroExtendNode.create(forValue, inputBits, resultBits); } } - return this; + return self != null ? self : new SignExtendNode(forValue, inputBits, resultBits); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -67,7 +67,7 @@ return forX; } if (c == -1) { - return new NegateNode(forX); + return NegateNode.create(forX); } long abs = Math.abs(c); if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) { @@ -83,7 +83,7 @@ } RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2)); if (c < 0) { - return new NegateNode(shift); + return NegateNode.create(shift); } return shift; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SubNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -59,24 +59,16 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new SubNode(x, y); } + return canonical(null, op, stamp, x, y); } - @SuppressWarnings("hiding") - @Override - public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { - ValueNode ret = super.canonical(tool, forX, forY); - if (ret != this) { - return ret; - } - - BinaryOp op = getOp(forX, forY); + private static ValueNode canonical(SubNode subNode, BinaryOp op, Stamp stamp, ValueNode forX, ValueNode forY) { + SubNode self = subNode; if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { Constant zero = op.getZero(forX.stamp()); if (zero != null) { - return ConstantNode.forPrimitive(stamp(), zero); + return ConstantNode.forPrimitive(stamp, zero); } } boolean associative = op.isAssociative(); @@ -95,18 +87,18 @@ SubNode x = (SubNode) forX; if (x.getX() == forY) { // (a - b) - a - return new NegateNode(x.getY()); + return NegateNode.create(x.getY()); } } if (forY instanceof AddNode) { AddNode y = (AddNode) forY; if (y.getX() == forX) { // a - (a + b) - return new NegateNode(y.getY()); + return NegateNode.create(y.getY()); } if (y.getY() == forX) { // b - (a + b) - return new NegateNode(y.getX()); + return NegateNode.create(y.getX()); } } else if (forY instanceof SubNode) { SubNode y = (SubNode) forY; @@ -121,9 +113,9 @@ if (op.isNeutral(c)) { return forX; } - if (associative) { - ValueNode reassociated = reassociate(this, ValueNode.isConstantPredicate(), forX, forY); - if (reassociated != this) { + if (associative && self != null) { + ValueNode reassociated = reassociate(self, ValueNode.isConstantPredicate(), forX, forY); + if (reassociated != self) { return reassociated; } } @@ -132,27 +124,41 @@ if (i < 0 || ((IntegerStamp) StampFactory.forKind(forY.getStackKind())).contains(-i)) { // Adding a negative is more friendly to the backend since adds are // commutative, so prefer add when it fits. - return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp(), -i)); + return BinaryArithmeticNode.add(forX, ConstantNode.forIntegerStamp(stamp, -i)); } } } else if (forX.isConstant()) { Constant c = forX.asConstant(); - if (ArithmeticOpTable.forStamp(stamp()).getAdd().isNeutral(c)) { + if (ArithmeticOpTable.forStamp(stamp).getAdd().isNeutral(c)) { /* * Note that for floating point numbers, + and - have different neutral elements. We * have to test for the neutral element of +, because we are doing this * transformation: 0 - x == (-x) + 0 == -x. */ - return new NegateNode(forY); + return NegateNode.create(forY); } - if (associative) { - return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); + if (associative && self != null) { + return reassociate(self, ValueNode.isConstantPredicate(), forX, forY); } } if (forY instanceof NegateNode) { return BinaryArithmeticNode.add(forX, ((NegateNode) forY).getValue()); } - return this; + if (self == null) { + self = new SubNode(forX, forY); + } + return self; + } + + @Override + public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { + ValueNode ret = super.canonical(tool, forX, forY); + if (ret != this) { + return ret; + } + + BinaryOp op = getOp(forX, forY); + return canonical(this, op, stamp, forX, forY); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/XorNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -57,9 +57,8 @@ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp); if (tryConstantFold != null) { return tryConstantFold; - } else { - return new XorNode(x, y).maybeCommuteInputs(); } + return canonical(null, op, stamp, x, y); } @Override @@ -69,28 +68,32 @@ return ret; } + return canonical(this, getOp(forX, forY), stamp(), forX, forY); + } + + private static ValueNode canonical(XorNode self, BinaryOp op, Stamp stamp, ValueNode forX, ValueNode forY) { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { - return ConstantNode.forPrimitive(stamp(), getOp(forX, forY).getZero(forX.stamp())); + return ConstantNode.forPrimitive(stamp, op.getZero(forX.stamp())); } if (forX.isConstant() && !forY.isConstant()) { return new XorNode(forY, forX); } if (forY.isConstant()) { Constant c = forY.asConstant(); - if (getOp(forX, forY).isNeutral(c)) { + if (op.isNeutral(c)) { return forX; } if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) { long rawY = ((PrimitiveConstant) c).asLong(); - long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp())); + long mask = CodeUtil.mask(PrimitiveStamp.getBits(stamp)); if ((rawY & mask) == mask) { return new NotNode(forX); } } - return reassociate(this, ValueNode.isConstantPredicate(), forX, forY); + return reassociate(self != null ? self : (XorNode) new XorNode(forX, forY).maybeCommuteInputs(), ValueNode.isConstantPredicate(), forX, forY); } - return this; + return self != null ? self : new XorNode(forX, forY).maybeCommuteInputs(); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -67,9 +67,8 @@ ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp())); if (synonym != null) { return synonym; - } else { - return new ZeroExtendNode(input, inputBits, resultBits); } + return canonical(null, input, inputBits, resultBits); } @Override @@ -97,11 +96,16 @@ return ret; } + return canonical(this, forValue, getInputBits(), getResultBits()); + } + + private static ValueNode canonical(ZeroExtendNode zeroExtendNode, ValueNode forValue, int inputBits, int resultBits) { + ZeroExtendNode self = zeroExtendNode; if (forValue instanceof ZeroExtendNode) { // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx // ==> xxxx -(zero-extend)-> 00000000 0000xxxx ZeroExtendNode other = (ZeroExtendNode) forValue; - return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits()); + return new ZeroExtendNode(other.getValue(), other.getInputBits(), resultBits); } if (forValue instanceof NarrowNode) { NarrowNode narrow = (NarrowNode) forValue; @@ -128,7 +132,10 @@ } } - return this; + if (self == null) { + self = new ZeroExtendNode(forValue, inputBits, resultBits); + } + return self; } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Thu Apr 06 14:31:32 2017 -0700 @@ -607,7 +607,7 @@ if (sux.loop != loop) { AbstractBeginNode begin = sux.getBeginNode(); if (!(begin instanceof LoopExitNode && ((LoopExitNode) begin).loopBegin() == loopBegin)) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux); + Debug.log(Debug.VERBOSE_LEVEL, "Unexpected loop exit with %s, including whole branch in the loop", sux); computeLoopBlocks(sux, loop, stack, false); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -97,23 +97,22 @@ } boolean usageFound = false; for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) { - if (node.condition() == Condition.EQ) { - ValueNode other = node.getX(); - if (node.getX() == this) { - other = node.getY(); + assert node.condition() == Condition.EQ; + ValueNode other = node.getX(); + if (node.getX() == this) { + other = node.getY(); + } + if (other.isConstant()) { + double probabilityToSet = probabilityValue; + if (other.asJavaConstant().asInt() == 0) { + probabilityToSet = 1.0 - probabilityToSet; } - if (other.isConstant()) { - double probabilityToSet = probabilityValue; - if (other.asJavaConstant().asInt() == 0) { - probabilityToSet = 1.0 - probabilityToSet; - } - for (IfNode ifNodeUsages : node.usages().filter(IfNode.class)) { - usageFound = true; - ifNodeUsages.setTrueSuccessorProbability(probabilityToSet); - } - if (!usageFound) { - usageFound = node.usages().filter(NodePredicates.isA(FixedGuardNode.class).or(ConditionalNode.class)).isNotEmpty(); - } + for (IfNode ifNodeUsages : node.usages().filter(IfNode.class)) { + usageFound = true; + ifNodeUsages.setTrueSuccessorProbability(probabilityToSet); + } + if (!usageFound) { + usageFound = node.usages().filter(NodePredicates.isA(FixedGuardNode.class).or(ConditionalNode.class)).isNotEmpty(); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/IntegerSwitchNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -194,7 +194,7 @@ } else { int newDefaultSuccessor = addNewSuccessor(defaultSuccessor(), newSuccessors); double newDefaultProbability = keyProbabilities[keyProbabilities.length - 1]; - doReplace(tool, value(), newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability); + doReplace(value(), newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability); return true; } } @@ -294,7 +294,7 @@ * Build the low-level representation of the new switch keys and replace ourself with a new * node. */ - doReplace(tool, newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability); + doReplace(newValue, newKeyDatas, newSuccessors, newDefaultSuccessor, newDefaultProbability); /* The array load is now unnecessary. */ assert loadIndexed.hasNoUsages(); @@ -312,7 +312,7 @@ return index; } - private void doReplace(SimplifierTool tool, ValueNode newValue, List newKeyDatas, ArrayList newSuccessors, int newDefaultSuccessor, double newDefaultProbability) { + private void doReplace(ValueNode newValue, List newKeyDatas, ArrayList newSuccessors, int newDefaultSuccessor, double newDefaultProbability) { /* Sort the new keys (invariant of the IntegerSwitchNode). */ newKeyDatas.sort((k1, k2) -> k1.key - k2.key); @@ -353,7 +353,7 @@ if (!newSuccessors.contains(successor)) { FixedNode fixedBranch = successor; fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); - GraphUtil.killCFG(fixedBranch, tool); + GraphUtil.killCFG(fixedBranch); } setBlockSuccessor(i, null); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -27,6 +27,7 @@ import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.type.PrimitiveStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.NodeClass; @@ -52,10 +53,21 @@ public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtualizable { public static final NodeClass TYPE = NodeClass.create(RawLoadNode.class); + /** + * This constructor exists for node intrinsics that need a stamp based on {@code accessKind}. + */ public RawLoadNode(ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) { super(TYPE, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, false); } + /** + * This constructor exists for node intrinsics that need a stamp based on the return type of the + * {@link org.graalvm.compiler.graph.Node.NodeIntrinsic} annotated method. + */ + public RawLoadNode(@InjectedNodeParameter Stamp stamp, ValueNode object, ValueNode offset, LocationIdentity locationIdentity, JavaKind accessKind) { + super(TYPE, stamp, object, offset, accessKind, locationIdentity, false); + } + public RawLoadNode(NodeClass c, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) { super(c, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, false); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnsafeCopyNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,15 +22,15 @@ */ package org.graalvm.compiler.nodes.extended; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; - import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + /** * Copy a value at a location specified as an offset relative to a source object to another location * specified as an offset relative to destination object. No null checks are performed. diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Thu Apr 06 14:31:32 2017 -0700 @@ -70,8 +70,9 @@ void push(JavaKind kind, ValueNode value); /** - * Adds a node to the graph. If the returned node is a {@link StateSplit} with a null - * {@linkplain StateSplit#stateAfter() frame state}, the frame state is initialized. + * Adds a node to the graph. If the node is in the graph, returns immediately. If the node is a + * {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state}, the frame + * state is initialized. * * @param value the value to add to the graph and push to the stack. The * {@code value.getJavaKind()} kind is used when type checking this operation. @@ -92,6 +93,30 @@ return equivalentValue; } + /** + * Adds a node and its inputs to the graph. If the node is in the graph, returns immediately. If + * the node is a {@link StateSplit} with a null {@linkplain StateSplit#stateAfter() frame state} + * , the frame state is initialized. + * + * @param value the value to add to the graph and push to the stack. The + * {@code value.getJavaKind()} kind is used when type checking this operation. + * @return a node equivalent to {@code value} in the graph + */ + default T addWithInputs(T value) { + if (value.graph() != null) { + assert !(value instanceof StateSplit) || ((StateSplit) value).stateAfter() != null; + return value; + } + T equivalentValue = recursiveAppend(value); + if (equivalentValue instanceof StateSplit) { + StateSplit stateSplit = (StateSplit) equivalentValue; + if (stateSplit.stateAfter() == null && stateSplit.hasSideEffect()) { + setStateAfter(stateSplit); + } + } + return equivalentValue; + } + default ValueNode addNonNullCast(ValueNode value) { AbstractPointerStamp valueStamp = (AbstractPointerStamp) value.stamp(); if (valueStamp.nonNull()) { @@ -100,7 +125,7 @@ LogicNode isNull = add(IsNullNode.create(value)); FixedGuardNode fixedGuard = add(new FixedGuardNode(isNull, DeoptimizationReason.NullCheckException, DeoptimizationAction.None, true)); Stamp newStamp = valueStamp.improveWith(StampFactory.objectNonNull()); - return add(new PiNode(value, newStamp, fixedGuard)); + return add(PiNode.create(value, newStamp, fixedGuard)); } } @@ -245,12 +270,12 @@ * non-null} stamp. */ default ValueNode nullCheckedValue(ValueNode value, DeoptimizationAction action) { - if (!StampTool.isPointerNonNull(value.stamp())) { + if (!StampTool.isPointerNonNull(value)) { LogicNode condition = getGraph().unique(IsNullNode.create(value)); ObjectStamp receiverStamp = (ObjectStamp) value.stamp(); Stamp stamp = receiverStamp.join(objectNonNull()); FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, action, true)); - PiNode nonNullReceiver = getGraph().unique(new PiNode(value, stamp, fixedGuard)); + ValueNode nonNullReceiver = getGraph().addOrUnique(PiNode.create(value, stamp, fixedGuard)); // TODO: Propogating the non-null into the frame state would // remove subsequent null-checks on the same value. However, // it currently causes an assertion failure when merging states. diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodeIntrinsicPluginFactory.java Thu Apr 06 14:31:32 2017 -0700 @@ -30,7 +30,14 @@ T getInjectedArgument(Class type); - Stamp getReturnStamp(Class type, boolean nonNull); + /** + * Gets a stamp denoting a given type and non-nullness property. + * + * @param type the type the returned stamp represents + * @param nonNull specifies if the returned stamp denotes a value that is guaranteed to be + * non-null + */ + Stamp getInjectedStamp(Class type, boolean nonNull); } void registerPlugins(InvocationPlugins plugins, InjectionProvider injection); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -24,6 +24,8 @@ import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampPair; @@ -51,6 +53,7 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; +import org.graalvm.compiler.options.OptionValues; /** * The {@code LoadFieldNode} represents a read of a static or instance field. @@ -71,10 +74,21 @@ return new LoadFieldNode(StampFactory.forDeclaredType(assumptions, field.getType(), false), object, field); } + public static ValueNode create(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, + OptionValues options, Assumptions assumptions, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { + return canonical(null, StampFactory.forDeclaredType(assumptions, field.getType(), false), object, + field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable); + } + public static LoadFieldNode createOverrideStamp(StampPair stamp, ValueNode object, ResolvedJavaField field) { return new LoadFieldNode(stamp, object, field); } + public static ValueNode createOverrideStamp(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, + OptionValues options, StampPair stamp, ValueNode object, ResolvedJavaField field, boolean canonicalizeReads, boolean allUsagesAvailable) { + return canonical(null, stamp, object, field, constantFields, constantReflection, options, metaAccess, canonicalizeReads, allUsagesAvailable); + } + @Override public ValueNode getValue() { return object(); @@ -85,33 +99,50 @@ if (tool.allUsagesAvailable() && hasNoUsages() && !isVolatile() && (isStatic() || StampTool.isPointerNonNull(forObject.stamp()))) { return null; } - MetaAccessProvider metaAccess = tool.getMetaAccess(); - if (tool.canonicalizeReads() && metaAccess != null) { - ConstantNode constant = asConstant(tool, forObject); + return canonical(this, StampPair.create(stamp, uncheckedStamp), forObject, field, tool.getConstantFieldProvider(), + tool.getConstantReflection(), tool.getOptions(), tool.getMetaAccess(), tool.canonicalizeReads(), tool.allUsagesAvailable()); + } + + private static ValueNode canonical(LoadFieldNode loadFieldNode, StampPair stamp, ValueNode forObject, ResolvedJavaField field, + ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, + OptionValues options, MetaAccessProvider metaAccess, boolean canonicalizeReads, boolean allUsagesAvailable) { + LoadFieldNode self = loadFieldNode; + if (canonicalizeReads && metaAccess != null) { + ConstantNode constant = asConstant(constantFields, constantReflection, metaAccess, options, forObject, field); if (constant != null) { return constant; } - if (tool.allUsagesAvailable()) { - PhiNode phi = asPhi(tool, forObject); + if (allUsagesAvailable) { + PhiNode phi = asPhi(constantFields, constantReflection, metaAccess, options, forObject, + field, stamp.getTrustedStamp()); if (phi != null) { return phi; } } } - if (!isStatic() && forObject.isNullConstant()) { + if (self != null && !field.isStatic() && forObject.isNullConstant()) { return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException); } - return this; + if (self == null) { + self = new LoadFieldNode(stamp, forObject, field); + } + return self; } /** * Gets a constant value for this load if possible. */ public ConstantNode asConstant(CanonicalizerTool tool, ValueNode forObject) { - if (isStatic()) { - return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), null, getOptions()); + return asConstant(tool.getConstantFieldProvider(), tool.getConstantReflection(), + tool.getMetaAccess(), tool.getOptions(), forObject, field); + } + + private static ConstantNode asConstant(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, + MetaAccessProvider metaAccess, OptionValues options, ValueNode forObject, ResolvedJavaField field) { + if (field.isStatic()) { + return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, null, options); } else if (forObject.isConstant() && !forObject.isNullConstant()) { - return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), forObject.asJavaConstant(), getOptions()); + return ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAccess, field, forObject.asJavaConstant(), options); } return null; } @@ -120,19 +151,20 @@ return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, getOptions()); } - private PhiNode asPhi(CanonicalizerTool tool, ValueNode forObject) { - if (!isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) { + private static PhiNode asPhi(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection, + MetaAccessProvider metaAcccess, OptionValues options, ValueNode forObject, ResolvedJavaField field, Stamp stamp) { + if (!field.isStatic() && field.isFinal() && forObject instanceof ValuePhiNode && ((ValuePhiNode) forObject).values().filter(isNotA(ConstantNode.class)).isEmpty()) { PhiNode phi = (PhiNode) forObject; ConstantNode[] constantNodes = new ConstantNode[phi.valueCount()]; for (int i = 0; i < phi.valueCount(); i++) { - ConstantNode constant = ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), phi.valueAt(i).asJavaConstant(), - getOptions()); + ConstantNode constant = ConstantFoldUtil.tryConstantFold(constantFields, constantReflection, metaAcccess, field, phi.valueAt(i).asJavaConstant(), + options); if (constant == null) { return null; } constantNodes[i] = constant; } - return new ValuePhiNode(stamp(), phi.merge(), constantNodes); + return new ValuePhiNode(stamp, phi.merge(), constantNodes); } return null; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MethodCallTargetNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -239,8 +239,8 @@ LogicNode condition = graph().addOrUniqueWithInputs(InstanceOfNode.create(speculatedType, receiver, getProfile(), anchor)); FixedGuardNode guard = graph().add(new FixedGuardNode(condition, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, false)); graph().addBeforeFixed(invoke().asNode(), guard); - PiNode piNode = graph().unique(new PiNode(receiver, StampFactory.objectNonNull(speculatedType), guard)); - arguments().set(0, piNode); + ValueNode valueNode = graph().addOrUnique(new PiNode(receiver, StampFactory.objectNonNull(speculatedType), guard)); + arguments().set(0, valueNode); if (speculatedType.isExact()) { setInvokeKind(InvokeKind.Special); } else { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/MonitorIdNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -45,6 +45,7 @@ public static final NodeClass TYPE = NodeClass.create(MonitorIdNode.class); protected int lockDepth; + protected boolean eliminated; public MonitorIdNode(int lockDepth) { this(TYPE, lockDepth); @@ -63,6 +64,14 @@ this.lockDepth = lockDepth; } + public boolean isEliminated() { + return eliminated; + } + + public void setEliminated() { + eliminated = true; + } + @Override public void generate(NodeLIRBuilderTool generator) { // nothing to do diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/NodeValueMap.java Thu Apr 06 14:31:32 2017 -0700 @@ -53,7 +53,7 @@ Value setResult(ValueNode node, Value operand); /** - * Gets the the {@link ValueNode} that produced a {@code value}. If the {@code value} is not + * Gets the {@link ValueNode} that produced a {@code value}. If the {@code value} is not * associated with a {@link ValueNode} {@code null} is returned. * * This method is intended for debugging purposes only. diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/StampTool.java Thu Apr 06 14:31:32 2017 -0700 @@ -78,7 +78,7 @@ public static Stamp unsignedCompare(Stamp stamp, Stamp stamp2) { IntegerStamp x = (IntegerStamp) stamp; IntegerStamp y = (IntegerStamp) stamp2; - if (x == x.unrestricted() && y == y.unrestricted()) { + if (x.isUnrestricted() && y.isUnrestricted()) { // Don't know anything. return null; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,21 +32,19 @@ import org.graalvm.compiler.code.SourceStackTraceBailoutException; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.debug.Debug; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.graph.NodeStack; import org.graalvm.compiler.graph.NodeWorkList; import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.graph.iterators.NodeIterable; import org.graalvm.compiler.graph.spi.SimplifierTool; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ControlSplitNode; import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; @@ -60,7 +58,6 @@ import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.calc.FloatingNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; import org.graalvm.compiler.nodes.spi.LimitedValueProxy; @@ -70,8 +67,10 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.util.EconomicMap; import org.graalvm.util.EconomicSet; import org.graalvm.util.Equivalence; +import org.graalvm.util.MapCursor; import jdk.vm.ci.code.BailoutException; import jdk.vm.ci.code.BytecodePosition; @@ -88,14 +87,142 @@ public static final OptionKey VerifyKillCFGUnusedNodes = new OptionKey<>(false); } + private static void killCFGInner(FixedNode node) { + EconomicSet markedNodes = EconomicSet.create(); + EconomicMap> unmarkedMerges = EconomicMap.create(); + + // Detach this node from CFG + node.replaceAtPredecessor(null); + + markFixedNodes(node, markedNodes, unmarkedMerges); + + fixSurvivingAffectedMerges(markedNodes, unmarkedMerges); + + Debug.dump(Debug.DETAILED_LEVEL, node.graph(), "After fixing merges (killCFG %s)", node); + + // Mark non-fixed nodes + markUsages(markedNodes); + + // Detach marked nodes from non-marked nodes + for (Node marked : markedNodes) { + for (Node input : marked.inputs()) { + if (!markedNodes.contains(input)) { + marked.replaceFirstInput(input, null); + tryKillUnused(input); + } + } + } + Debug.dump(Debug.VERY_DETAILED_LEVEL, node.graph(), "After disconnecting non-marked inputs (killCFG %s)", node); + // Kill marked nodes + for (Node marked : markedNodes) { + if (marked.isAlive()) { + marked.markDeleted(); + } + } + } + + private static void markFixedNodes(FixedNode node, EconomicSet markedNodes, EconomicMap> unmarkedMerges) { + NodeStack workStack = new NodeStack(); + workStack.push(node); + while (!workStack.isEmpty()) { + Node fixedNode = workStack.pop(); + markedNodes.add(fixedNode); + if (fixedNode instanceof AbstractMergeNode) { + unmarkedMerges.removeKey((AbstractMergeNode) fixedNode); + } + while (fixedNode instanceof FixedWithNextNode) { + fixedNode = ((FixedWithNextNode) fixedNode).next(); + if (fixedNode != null) { + markedNodes.add(fixedNode); + } + } + if (fixedNode instanceof ControlSplitNode) { + for (Node successor : fixedNode.successors()) { + workStack.push(successor); + } + } else if (fixedNode instanceof AbstractEndNode) { + AbstractEndNode end = (AbstractEndNode) fixedNode; + AbstractMergeNode merge = end.merge(); + if (merge != null) { + assert !markedNodes.contains(merge) || (merge instanceof LoopBeginNode && end instanceof LoopEndNode) : merge; + if (merge instanceof LoopBeginNode) { + if (end == ((LoopBeginNode) merge).forwardEnd()) { + workStack.push(merge); + continue; + } + if (markedNodes.contains(merge)) { + continue; + } + } + List endsSeen = unmarkedMerges.get(merge); + if (endsSeen == null) { + endsSeen = new ArrayList<>(merge.forwardEndCount()); + unmarkedMerges.put(merge, endsSeen); + } + endsSeen.add(end); + if (!(end instanceof LoopEndNode) && endsSeen.size() == merge.forwardEndCount()) { + assert merge.forwardEnds().filter(n -> !markedNodes.contains(n)).isEmpty(); + // all this merge's forward ends are marked: it needs to be killed + workStack.push(merge); + } + } + } + } + } + + private static void fixSurvivingAffectedMerges(EconomicSet markedNodes, EconomicMap> unmarkedMerges) { + MapCursor> cursor = unmarkedMerges.getEntries(); + while (cursor.advance()) { + AbstractMergeNode merge = cursor.getKey(); + for (AbstractEndNode end : cursor.getValue()) { + merge.removeEnd(end); + } + if (merge.phiPredecessorCount() == 1) { + if (merge instanceof LoopBeginNode) { + LoopBeginNode loopBegin = (LoopBeginNode) merge; + assert merge.forwardEndCount() == 1; + for (LoopExitNode loopExit : loopBegin.loopExits().snapshot()) { + if (markedNodes.contains(loopExit)) { + /* + * disconnect from loop begin so that reduceDegenerateLoopBegin doesn't + * transform it into a new beginNode + */ + loopExit.replaceFirstInput(loopBegin, null); + } + } + merge.graph().reduceDegenerateLoopBegin(loopBegin); + } else { + merge.graph().reduceTrivialMerge(merge); + } + } else { + assert merge.phiPredecessorCount() > 1 : merge; + } + } + } + + private static void markUsages(EconomicSet markedNodes) { + NodeStack workStack = new NodeStack(markedNodes.size() + 4); + for (Node marked : markedNodes) { + workStack.push(marked); + } + while (!workStack.isEmpty()) { + Node marked = workStack.pop(); + for (Node usage : marked.usages()) { + if (!markedNodes.contains(usage)) { + workStack.push(usage); + markedNodes.add(usage); + } + } + } + } + @SuppressWarnings("try") - public static void killCFG(FixedNode node, SimplifierTool tool) { + public static void killCFG(FixedNode node) { try (Debug.Scope scope = Debug.scope("KillCFG", node)) { EconomicSet unusedNodes = null; EconomicSet unsafeNodes = null; Graph.NodeEventScope nodeEventScope = null; OptionValues options = node.getOptions(); - StructuredGraph graph = node.graph(); if (Graph.Options.VerifyGraalGraphEdges.getValue(options)) { unsafeNodes = collectUnsafeNodes(node.graph()); } @@ -110,14 +237,9 @@ } }); } - Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "Before killCFG %s", node); - NodeWorkList worklist = killCFG(node, tool, null); - if (worklist != null) { - for (Node n : worklist) { - NodeWorkList list = killCFG(n, tool, worklist); - assert list == worklist; - } - } + Debug.dump(Debug.VERY_DETAILED_LEVEL, node.graph(), "Before killCFG %s", node); + killCFGInner(node); + Debug.dump(Debug.VERY_DETAILED_LEVEL, node.graph(), "After killCFG %s", node); if (Graph.Options.VerifyGraalGraphEdges.getValue(options)) { EconomicSet newUnsafeNodes = collectUnsafeNodes(node.graph()); newUnsafeNodes.removeAll(unsafeNodes); @@ -133,7 +255,6 @@ } } assert unusedNodes.isEmpty() : "New unused nodes: " + unusedNodes; - assert graph.getNodes().filter(PoisonNode.class).isEmpty(); } } catch (Throwable t) { throw Debug.handle(t); @@ -158,253 +279,10 @@ return unsafeNodes; } - private static NodeWorkList killCFG(Node node, SimplifierTool tool, NodeWorkList worklist) { - NodeWorkList newWorklist = worklist; - if (node instanceof FixedNode) { - newWorklist = killCFGLinear((FixedNode) node, newWorklist, tool); - } else { - if (node instanceof PoisonNode && ((PoisonNode) node).processNonPhiUsagesFirst()) { - if (node.isAlive()) { - if (node.hasNoUsages()) { - node.safeDelete(); - } else { - if (newWorklist == null) { - newWorklist = node.graph().createIterativeNodeWorkList(false, 0); - } - for (Node usage : node.usages()) { - if (isFloatingNode(usage) && !(usage instanceof PhiNode)) { - newWorklist.add(usage); - } - } - newWorklist.add(node); - } - } - } else { - newWorklist = propagateKill(node, newWorklist); - Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, node.graph(), "killCFG (Floating) %s", node); - } - } - return newWorklist; - } - - private static NodeWorkList killCFGLinear(FixedNode in, NodeWorkList worklist, SimplifierTool tool) { - NodeWorkList newWorklist = worklist; - FixedNode current = in; - while (current != null) { - FixedNode next = null; - assert current.isAlive(); - if (current instanceof AbstractEndNode) { - // We reached a control flow end. - AbstractEndNode end = (AbstractEndNode) current; - newWorklist = killEnd(end, newWorklist, tool); - } else if (current instanceof FixedWithNextNode) { - // Node guaranteed to have a single successor - FixedWithNextNode fixedWithNext = (FixedWithNextNode) current; - assert fixedWithNext.successors().count() == 1 || fixedWithNext.successors().count() == 0; - assert fixedWithNext.successors().first() == fixedWithNext.next(); - next = fixedWithNext.next(); - } else { - /* - * We do not take a successor snapshot because this iterator supports concurrent - * modifications as long as they do not change the size of the successor list. Not - * taking a snapshot allows us to see modifications to other branches that may - * happen while processing one branch. - */ - Iterator successors = current.successors().iterator(); - if (successors.hasNext()) { - Node first = successors.next(); - if (!successors.hasNext()) { - next = (FixedNode) first; - } else { - if (newWorklist == null) { - newWorklist = in.graph().createIterativeNodeWorkList(false, 0); - } - for (Node successor : current.successors()) { - newWorklist.add(successor); - if (successor instanceof LoopExitNode) { - LoopExitNode exit = (LoopExitNode) successor; - exit.replaceFirstInput(exit.loopBegin(), null); - } - } - } - } - } - current.replaceAtPredecessor(null); - newWorklist = propagateKill(current, newWorklist); - Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, current.graph(), "killCFGLinear %s", current); - current = next; - } - Debug.dump(Debug.DETAILED_LOG_LEVEL, in.graph(), "killCFGLinear %s", in); - return newWorklist; - } - - public static void killCFG(FixedNode node) { - killCFG(node, null); - } - - /** - * Node type used temporarily while deleting loops. - * - * It is used as replacement for the loop {@link PhiNode PhiNodes} in order to break data-flow - * cycles before deleting the loop. The control-flow of the whole loop is killed before killing - * the poison node if they are still alive. - */ - @NodeInfo(allowedUsageTypes = InputType.Unchecked) - private static final class PoisonNode extends FloatingNode { - public static final NodeClass TYPE = NodeClass.create(PoisonNode.class); - protected boolean loopPoison; - - protected PoisonNode(boolean loopPoison) { - super(TYPE, StampFactory.forVoid()); - this.loopPoison = loopPoison; - } - - public boolean processNonPhiUsagesFirst() { - return !this.loopPoison; - } - } - - private static NodeWorkList killEnd(AbstractEndNode end, NodeWorkList worklist, SimplifierTool tool) { - NodeWorkList newWorklist = worklist; - AbstractMergeNode merge = end.merge(); - if (merge != null) { - merge.removeEnd(end); - StructuredGraph graph = end.graph(); - if (merge instanceof LoopBeginNode && merge.forwardEndCount() == 0) { - // dead loop - LoopBeginNode begin = (LoopBeginNode) merge; - // disconnect and delete loop ends & loop exits - for (LoopEndNode loopend : begin.loopEnds().snapshot()) { - loopend.predecessor().replaceFirstSuccessor(loopend, null); - loopend.safeDelete(); - } - // clean unused proxies to avoid creating new unused nodes - for (LoopExitNode exit : begin.loopExits()) { - for (ProxyNode vpn : exit.proxies().snapshot()) { - tryKillUnused(vpn); - } - } - begin.removeExits(); - PoisonNode poison = null; - if (merge.phis().isNotEmpty()) { - poison = graph.addWithoutUnique(new PoisonNode(true)); - for (PhiNode phi : merge.phis()) { - phi.replaceAtUsages(poison); - } - for (PhiNode phi : merge.phis().snapshot()) { - killWithUnusedFloatingInputs(phi); - } - } - FixedNode loopBody = begin.next(); - Debug.dump(Debug.VERY_DETAILED_LOG_LEVEL, end.graph(), "killEnd (Loop) %s after initial loop cleanup", end); - if (loopBody != null) { - // for small infinite loops, the body may already be killed while killing the - // LoopEnds - newWorklist = killCFG(loopBody, tool, newWorklist); - } - FrameState frameState = begin.stateAfter(); - begin.safeDelete(); - if (frameState != null) { - tryKillUnused(frameState); - } - if (poison != null && poison.isAlive()) { - if (newWorklist == null) { - newWorklist = graph.createIterativeNodeWorkList(false, 0); - } - // drain the worklist to finish the loop before adding the poison - List waitingPoisons = null; - for (Node n : newWorklist) { - if (n instanceof PoisonNode && ((PoisonNode) n).processNonPhiUsagesFirst() && n.hasUsages()) { - assert n != poison; - if (waitingPoisons == null) { - waitingPoisons = new ArrayList<>(2); - } - waitingPoisons.add(n); - } else { - NodeWorkList list = killCFG(n, tool, newWorklist); - assert list == newWorklist; - } - } - if (poison.isAlive()) { - newWorklist.add(poison); - } - if (waitingPoisons != null) { - newWorklist.addAll(waitingPoisons); - } - } - } else if (merge instanceof LoopBeginNode && ((LoopBeginNode) merge).loopEnds().isEmpty()) { - // not a loop anymore - if (tool != null) { - for (PhiNode phi : merge.phis()) { - tool.addToWorkList(phi.usages()); - } - } - graph.reduceDegenerateLoopBegin((LoopBeginNode) merge); - } else if (merge.phiPredecessorCount() == 1) { - // not a merge anymore - for (PhiNode phi : merge.phis()) { - if (tool != null) { - tool.addToWorkList(phi.usages()); - } - ValueNode value = phi.valueAt(0); - if (value instanceof PoisonNode) { - if (newWorklist == null) { - newWorklist = graph.createIterativeNodeWorkList(false, 0); - } - newWorklist.add(value); - } - } - graph.reduceTrivialMerge(merge); - } - } - return newWorklist; - } - public static boolean isFloatingNode(Node n) { return !(n instanceof FixedNode); } - private static NodeWorkList propagateKill(Node node, NodeWorkList workList) { - NodeWorkList newWorkList = workList; - if (node != null && node.isAlive()) { - if (node.hasUsages()) { - for (Node usage : node.usages().snapshot()) { - assert usage.isAlive(); - if (isFloatingNode(usage)) { - boolean addUsage = false; - if (usage instanceof PhiNode) { - PhiNode phi = (PhiNode) usage; - assert phi.merge() != null; - if (phi.merge() == node) { - // we reach the phi directly through he merge, queue it. - addUsage = true; - } else { - // we reach it though a value - assert phi.values().contains(node); - // let that be handled when we reach the corresponding End node - } - } else { - addUsage = true; - } - if (addUsage) { - if (newWorkList == null) { - newWorkList = node.graph().createIterativeNodeWorkList(false, 0); - } - newWorkList.add(usage); - } else { - usage.replaceFirstInput(node, node.graph().unique(new PoisonNode(false))); - continue; - } - } - usage.replaceFirstInput(node, null); - } - } - assert node.hasNoUsages() : node + " " + node.usages().snapshot(); - killWithUnusedFloatingInputs(node, true); - } - return newWorkList; - } - private static boolean checkKill(Node node, boolean mayKillGuard) { node.assertTrue(mayKillGuard || !(node instanceof GuardNode), "must not be a guard node %s", node); node.assertTrue(node.isAlive(), "must be alive"); @@ -972,7 +850,7 @@ public void deleteBranch(Node branch) { FixedNode fixedBranch = (FixedNode) branch; fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); - GraphUtil.killCFG(fixedBranch, this); + GraphUtil.killCFG(fixedBranch); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java Thu Apr 06 14:31:32 2017 -0700 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.graalvm.compiler.options; + +import java.util.concurrent.atomic.AtomicReference; + +import org.graalvm.util.EconomicMap; +import org.graalvm.util.Equivalence; +import org.graalvm.util.UnmodifiableEconomicMap; +import org.graalvm.util.UnmodifiableMapCursor; + +/** + * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be + * updated. Updates have atomic copy-on-write semantics which means a thread may see an old value + * when reading but writers will never loose updates. + */ +public class ModifiableOptionValues extends OptionValues { + + private final AtomicReference, Object>> v = new AtomicReference<>(); + + private static final EconomicMap, Object> EMPTY_MAP = newOptionMap(); + + public ModifiableOptionValues(UnmodifiableEconomicMap, Object> values) { + super(EMPTY_MAP); + EconomicMap, Object> map = newOptionMap(); + initMap(map, values); + v.set(map); + } + + /** + * Updates this object with the given key/value pair. + */ + public void update(OptionKey key, Object value) { + UnmodifiableEconomicMap, Object> expect; + EconomicMap, Object> newMap; + do { + expect = v.get(); + newMap = EconomicMap.create(Equivalence.IDENTITY, expect); + key.update(newMap, value); + // Need to do the null encoding here as `key.update()` doesn't do it + newMap.put(key, encodeNull(value)); + } while (!v.compareAndSet(expect, newMap)); + } + + /** + * Updates this object with the key/value pairs in {@code values}. + */ + public void update(UnmodifiableEconomicMap, Object> values) { + if (values.isEmpty()) { + return; + } + UnmodifiableEconomicMap, Object> expect; + EconomicMap, Object> newMap; + do { + expect = v.get(); + newMap = EconomicMap.create(Equivalence.IDENTITY, expect); + UnmodifiableMapCursor, Object> cursor = values.getEntries(); + while (cursor.advance()) { + OptionKey key = cursor.getKey(); + Object value = cursor.getValue(); + key.update(newMap, value); + // Need to do the null encoding here as `key.update()` doesn't do it + newMap.put(key, encodeNull(value)); + } + } while (!v.compareAndSet(expect, newMap)); + } + + @Override + protected T get(OptionKey key) { + return OptionValues.get(v.get(), key); + } + + @Override + protected boolean containsKey(OptionKey key) { + return v.get().containsKey(key); + } + + @Override + public UnmodifiableEconomicMap, Object> getMap() { + return v.get(); + } +} diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java Thu Apr 06 14:31:32 2017 -0700 @@ -33,7 +33,6 @@ import org.graalvm.util.EconomicMap; import org.graalvm.util.Equivalence; -import org.graalvm.util.MapCursor; import org.graalvm.util.UnmodifiableEconomicMap; import org.graalvm.util.UnmodifiableMapCursor; @@ -42,25 +41,19 @@ */ public class OptionValues { - private final EconomicMap, Object> values = newOptionMap(); + private final UnmodifiableEconomicMap, Object> values; - protected OptionValues set(OptionKey key, Object value) { - values.put(key, encodeNull(value)); - return this; - } - - boolean containsKey(OptionKey key) { + protected boolean containsKey(OptionKey key) { return values.containsKey(key); } public OptionValues(OptionValues initialValues, UnmodifiableEconomicMap, Object> extraPairs) { + EconomicMap, Object> map = newOptionMap(); if (initialValues != null) { - values.putAll(initialValues.values); + map.putAll(initialValues.values); } - UnmodifiableMapCursor, Object> cursor = extraPairs.getEntries(); - while (cursor.advance()) { - values.put(cursor.getKey(), encodeNull(cursor.getValue())); - } + initMap(map, extraPairs); + this.values = map; } public OptionValues(OptionValues initialValues, OptionKey key1, Object value1, Object... extraPairs) { @@ -75,7 +68,8 @@ } /** - * Gets an immutable view of the key/value pairs in this object. + * Gets an immutable view of the key/value pairs in this object. Values read from this view + * should be {@linkplain #decodeNull(Object) decoded} before being used. */ public UnmodifiableEconomicMap, Object> getMap() { return values; @@ -98,15 +92,25 @@ return map; } - public OptionValues(EconomicMap, Object> values) { - MapCursor, Object> cursor = values.getEntries(); + public OptionValues(UnmodifiableEconomicMap, Object> values) { + EconomicMap, Object> map = newOptionMap(); + initMap(map, values); + this.values = map; + } + + protected static void initMap(EconomicMap, Object> map, UnmodifiableEconomicMap, Object> values) { + UnmodifiableMapCursor, Object> cursor = values.getEntries(); while (cursor.advance()) { - this.values.put(cursor.getKey(), encodeNull(cursor.getValue())); + map.put(cursor.getKey(), encodeNull(cursor.getValue())); } } + protected T get(OptionKey key) { + return get(values, key); + } + @SuppressWarnings("unchecked") - T get(OptionKey key) { + protected static T get(UnmodifiableEconomicMap, Object> values, OptionKey key) { Object value = values.get(key); if (value == null) { return key.getDefaultValue(); @@ -116,16 +120,23 @@ private static final Object NULL = new Object(); - private static Object encodeNull(Object value) { + protected static Object encodeNull(Object value) { return value == null ? NULL : value; } - private static Object decodeNull(Object value) { + /** + * Decodes a value that may be the sentinel value for {@code null} in a map. + */ + protected static Object decodeNull(Object value) { return value == NULL ? null : value; } @Override public String toString() { + return toString(getMap()); + } + + public static String toString(UnmodifiableEconomicMap, Object> values) { Comparator> comparator = new Comparator>() { @Override public int compare(OptionKey o1, OptionKey o2) { @@ -133,9 +144,9 @@ } }; SortedMap, Object> sorted = new TreeMap<>(comparator); - MapCursor, Object> cursor = values.getEntries(); + UnmodifiableMapCursor, Object> cursor = values.getEntries(); while (cursor.advance()) { - sorted.put(cursor.getKey(), cursor.getValue()); + sorted.put(cursor.getKey(), decodeNull(cursor.getValue())); } return sorted.toString(); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java Thu Apr 06 14:31:32 2017 -0700 @@ -23,6 +23,7 @@ package org.graalvm.compiler.options; import java.util.ArrayList; +import java.util.Collection; import java.util.Formatter; import java.util.List; import java.util.ServiceLoader; @@ -225,13 +226,29 @@ private static List fuzzyMatch(Iterable loader, String optionName) { List matches = new ArrayList<>(); for (OptionDescriptors options : loader) { - for (OptionDescriptor option : options) { - float score = stringSimiliarity(option.getName(), optionName); - if (score >= FUZZY_MATCH_THRESHOLD) { - matches.add(option); - } - } + collectFuzzyMatches(options, optionName, matches); } return matches; } + + /** + * Collects the set of options that fuzzy match a given option name. String similarity for fuzzy + * matching is based on Dice's coefficient. + * + * @param toSearch the set of option descriptors to search + * @param name the option name to search for + * @param matches the collection to which fuzzy matches of {@code name} will be added + * @return whether any fuzzy matches were found + */ + public static boolean collectFuzzyMatches(Iterable toSearch, String name, Collection matches) { + boolean found = false; + for (OptionDescriptor option : toSearch) { + float score = stringSimiliarity(option.getName(), name); + if (score >= FUZZY_MATCH_THRESHOLD) { + found = true; + matches.add(option); + } + } + return found; + } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/UniquePathUtilities.java Thu Apr 06 14:31:32 2017 -0700 @@ -113,6 +113,6 @@ if (result.isAbsolute() || defaultDirectory == null) { return result; } - return Paths.get(defaultDirectory.getValue(options), name); + return Paths.get(defaultDirectory.getValue(options), name).normalize(); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AbstractInliningPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -29,4 +29,8 @@ * Common superclass for phases that perform inlining. */ public abstract class AbstractInliningPhase extends BasePhase { + @Override + protected boolean isInliningPhase() { + return true; + } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -218,13 +218,13 @@ public void usagesDroppedToZero(Node node) { workList.add(node); } + }; - }; try (NodeEventScope nes = graph.trackNodeEvents(listener)) { for (Node n : workList) { boolean changed = processNode(n); - if (changed && Debug.isDumpEnabled(Debug.DETAILED_LOG_LEVEL)) { - Debug.dump(Debug.DETAILED_LOG_LEVEL, graph, "CanonicalizerPhase %s", n); + if (changed && Debug.isDumpEnabled(Debug.DETAILED_LEVEL)) { + Debug.dump(Debug.DETAILED_LEVEL, graph, "CanonicalizerPhase %s", n); } } } @@ -329,7 +329,7 @@ } if (nodeClass.isSimplifiable() && simplify) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Canonicalizer: simplifying %s", node); + Debug.log(Debug.VERBOSE_LEVEL, "Canonicalizer: simplifying %s", node); COUNTER_SIMPLIFICATION_CONSIDERED_NODES.increment(); node.simplify(tool); return node.isDeleted(); @@ -356,7 +356,7 @@ // @formatter:on private boolean performReplacement(final Node node, Node newCanonical) { if (newCanonical == node) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Canonicalizer: work on %1s", node); + Debug.log(Debug.VERBOSE_LEVEL, "Canonicalizer: work on %1s", node); return false; } else { Node canonical = newCanonical; @@ -448,7 +448,7 @@ public void deleteBranch(Node branch) { FixedNode fixedBranch = (FixedNode) branch; fixedBranch.predecessor().replaceFirstSuccessor(fixedBranch, null); - GraphUtil.killCFG(fixedBranch, this); + GraphUtil.killCFG(fixedBranch); } @Override diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DominatorConditionalEliminationPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -908,6 +908,10 @@ @Override public Node apply(Node node, Node curNode) { + if (!ok) { + // Abort the recursion + return curNode; + } if (!(curNode instanceof ValueNode)) { ok = false; return curNode; @@ -990,7 +994,7 @@ } public void pushElement(InfoElement element) { - Debug.log(Debug.VERBOSE_LOG_LEVEL, "Pushing an info element:%s", element); + Debug.log(Debug.VERBOSE_LEVEL, "Pushing an info element:%s", element); infos.add(element); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LockEliminationPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -28,6 +28,7 @@ import org.graalvm.compiler.nodes.java.AccessMonitorNode; import org.graalvm.compiler.nodes.java.MonitorEnterNode; import org.graalvm.compiler.nodes.java.MonitorExitNode; +import org.graalvm.compiler.nodes.java.MonitorIdNode; import org.graalvm.compiler.nodes.java.RawMonitorEnterNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.phases.Phase; @@ -36,16 +37,25 @@ @Override protected void run(StructuredGraph graph) { - for (MonitorExitNode node : graph.getNodes(MonitorExitNode.TYPE)) { - FixedNode next = node.next(); + for (MonitorExitNode monitorExitNode : graph.getNodes(MonitorExitNode.TYPE)) { + FixedNode next = monitorExitNode.next(); if ((next instanceof MonitorEnterNode || next instanceof RawMonitorEnterNode)) { // should never happen, osr monitor enters are always direct successors of the graph // start assert !(next instanceof OSRMonitorEnterNode); AccessMonitorNode monitorEnterNode = (AccessMonitorNode) next; - if (GraphUtil.unproxify(monitorEnterNode.object()) == GraphUtil.unproxify(node.object())) { + if (GraphUtil.unproxify(monitorEnterNode.object()) == GraphUtil.unproxify(monitorExitNode.object())) { + /* + * We've coarsened the lock so use the same monitor id for the whole region, + * otherwise the monitor operations appear to be unrelated. + */ + MonitorIdNode enterId = monitorEnterNode.getMonitorId(); + MonitorIdNode exitId = monitorExitNode.getMonitorId(); + if (enterId != exitId) { + enterId.replaceAndDelete(exitId); + } GraphUtil.removeFixedWithUnusedInputs(monitorEnterNode); - GraphUtil.removeFixedWithUnusedInputs(node); + GraphUtil.removeFixedWithUnusedInputs(monitorExitNode); } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/NewConditionalEliminationPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -135,8 +135,8 @@ } AbstractBeginNode beginNode = b.getBeginNode(); - if (beginNode instanceof MergeNode && anchorBlock != b) { - MergeNode mergeNode = (MergeNode) beginNode; + if (beginNode instanceof AbstractMergeNode && anchorBlock != b) { + AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode; for (GuardNode guard : mergeNode.guards().snapshot()) { try (DebugCloseable closeable = guard.withNodeSourcePosition()) { GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation()); @@ -411,7 +411,7 @@ allow = true; } else if (integerStamp.asConstant() != null) { allow = true; - } else if (oldStamp.unrestricted().equals(oldStamp)) { + } else if (oldStamp.isUnrestricted()) { allow = true; } } else { @@ -432,8 +432,8 @@ if (input == null) { input = valueAt; } - PiNode piNode = graph.unique(new PiNode(input, curBestStamp, (ValueNode) infoElement.guard)); - valueAt = piNode; + ValueNode valueNode = graph.maybeAddOrUnique(PiNode.create(input, curBestStamp, (ValueNode) infoElement.guard)); + valueAt = valueNode; } newPhi.addInput(valueAt); } @@ -948,6 +948,10 @@ @Override public Node apply(Node node, Node curNode) { + if (!ok) { + // Abort the recursion + return curNode; + } if (!(curNode instanceof ValueNode)) { ok = false; return curNode; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java Thu Apr 06 14:31:32 2017 -0700 @@ -402,7 +402,7 @@ EconomicSet parameterUsages = calleeInfo.inline(new Providers(context)); canonicalizedNodes.addAll(parameterUsages); counterInliningRuns.increment(); - Debug.dump(Debug.INFO_LOG_LEVEL, callerGraph, "after %s", calleeInfo); + Debug.dump(Debug.DETAILED_LEVEL, callerGraph, "after %s", calleeInfo); Graph.Mark markBeforeCanonicalization = callerGraph.getMark(); @@ -572,7 +572,7 @@ * Gets the call hierarchy of this inlining from outer most call to inner most callee. */ private Object[] inliningContext() { - if (!Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { + if (!Debug.isDumpEnabled(Debug.INFO_LEVEL)) { return NO_CONTEXT; } Object[] result = new Object[graphQueue.size()]; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -135,6 +135,55 @@ apply(graph, context, true); } + private BasePhase getEnclosingPhase() { + for (Object c : Debug.context()) { + if (c != this && c instanceof BasePhase) { + if (!(c instanceof PhaseSuite)) { + return (BasePhase) c; + } + } + } + return null; + } + + private BasePhase dumpBefore(StructuredGraph graph) { + BasePhase enclosingPhase = getEnclosingPhase(); + boolean isTopLevel = enclosingPhase == null; + if (isTopLevel) { + if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL)) { + Debug.dump(Debug.VERBOSE_LEVEL, graph, "Before phase %s", getName()); + } + } else { + if (Debug.isDumpEnabled(Debug.VERBOSE_LEVEL + 1)) { + Debug.dump(Debug.VERBOSE_LEVEL + 1, graph, "Before phase %s", getName()); + } + } + return enclosingPhase; + } + + protected boolean isInliningPhase() { + return false; + } + + private void dumpAfter(BasePhase enclosingPhase, StructuredGraph graph) { + boolean isTopLevel = enclosingPhase == null; + if (isTopLevel) { + if (isInliningPhase()) { + if (Debug.isDumpEnabled(Debug.BASIC_LEVEL)) { + Debug.dump(Debug.BASIC_LEVEL, graph, "After phase %s", getName()); + } + } else { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { + Debug.dump(Debug.INFO_LEVEL, graph, "After phase %s", getName()); + } + } + } else { + if (Debug.isDumpEnabled(Debug.INFO_LEVEL + 1)) { + Debug.dump(Debug.INFO_LEVEL + 1, graph, "After phase %s", getName()); + } + } + } + @SuppressWarnings("try") protected final void apply(final StructuredGraph graph, final C context, final boolean dumpGraph) { graph.checkCancellation(); @@ -149,8 +198,9 @@ before = graph.getMark(); } } - if (dumpGraph && Debug.isDumpEnabled(Debug.VERBOSE_LOG_LEVEL)) { - Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "Before phase %s", getName()); + BasePhase enclosingPhase = null; + if (dumpGraph && Debug.isEnabled()) { + enclosingPhase = dumpBefore(graph); } inputNodesCount.add(graph.getNodeCount()); this.run(graph, context); @@ -163,8 +213,9 @@ } } } - if (dumpGraph && Debug.isDumpEnabled(Debug.BASIC_LOG_LEVEL)) { - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "%s", getName()); + + if (dumpGraph && Debug.isEnabled()) { + dumpAfter(enclosingPhase, graph); } if (Fingerprint.ENABLED) { String graphDesc = graph.method() == null ? graph.name : graph.method().format("%H.%n(%p)"); @@ -204,5 +255,4 @@ public float codeSizeIncrease() { return 1.25f; } - } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/MergeableState.java Thu Apr 06 14:31:32 2017 -0700 @@ -40,7 +40,7 @@ * contains the states of the of the other branches in the order of the merge's end nodes. * * @param merge the merge node - * @param withStates the state at the the merge's end node except the first one. + * @param withStates the state at the merge's end node except the first one. */ public abstract boolean merge(AbstractMergeNode merge, List withStates); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java Thu Apr 06 14:31:32 2017 -0700 @@ -22,9 +22,19 @@ */ package org.graalvm.compiler.phases.verify; +import static org.graalvm.compiler.debug.Debug.BASIC_LEVEL; +import static org.graalvm.compiler.debug.Debug.DETAILED_LEVEL; +import static org.graalvm.compiler.debug.Debug.INFO_LEVEL; +import static org.graalvm.compiler.debug.Debug.VERBOSE_LEVEL; +import static org.graalvm.compiler.debug.Debug.VERY_DETAILED_LEVEL; + import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.debug.Debug; import org.graalvm.compiler.debug.DebugMethodMetrics; import org.graalvm.compiler.debug.GraalError; @@ -33,12 +43,16 @@ import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.Invoke; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; import org.graalvm.compiler.nodes.java.NewArrayNode; import org.graalvm.compiler.nodes.java.StoreIndexedNode; import org.graalvm.compiler.phases.VerifyPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; @@ -61,20 +75,24 @@ return false; } + MetaAccessProvider metaAccess; + @Override protected boolean verify(StructuredGraph graph, PhaseContext context) { - ResolvedJavaType debugType = context.getMetaAccess().lookupJavaType(Debug.class); - ResolvedJavaType nodeType = context.getMetaAccess().lookupJavaType(Node.class); - ResolvedJavaType stringType = context.getMetaAccess().lookupJavaType(String.class); - ResolvedJavaType debugMethodMetricsType = context.getMetaAccess().lookupJavaType(DebugMethodMetrics.class); - ResolvedJavaType graalErrorType = context.getMetaAccess().lookupJavaType(GraalError.class); + metaAccess = context.getMetaAccess(); + ResolvedJavaType debugType = metaAccess.lookupJavaType(Debug.class); + ResolvedJavaType nodeType = metaAccess.lookupJavaType(Node.class); + ResolvedJavaType stringType = metaAccess.lookupJavaType(String.class); + ResolvedJavaType debugMethodMetricsType = metaAccess.lookupJavaType(DebugMethodMetrics.class); + ResolvedJavaType graalErrorType = metaAccess.lookupJavaType(GraalError.class); for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) { ResolvedJavaMethod callee = t.targetMethod(); String calleeName = callee.getName(); if (callee.getDeclaringClass().equals(debugType)) { - if (calleeName.equals("log") || calleeName.equals("logAndIndent") || calleeName.equals("verify") || calleeName.equals("dump")) { - verifyParameters(t, graph, t.arguments(), stringType, calleeName.equals("dump") ? 2 : 1); + boolean isDump = calleeName.equals("dump"); + if (calleeName.equals("log") || calleeName.equals("logAndIndent") || calleeName.equals("verify") || isDump) { + verifyParameters(t, graph, t.arguments(), stringType, isDump ? 2 : 1); } } if (callee.getDeclaringClass().isAssignableFrom(nodeType)) { @@ -99,10 +117,10 @@ return true; } - private static void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList args, ResolvedJavaType stringType, int startArgIdx) { + private void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList args, ResolvedJavaType stringType, int startArgIdx) { if (callTarget.targetMethod().isVarArgs() && args.get(args.count() - 1) instanceof NewArrayNode) { // unpack the arguments to the var args - List unpacked = new ArrayList<>(args.snapshot()); + List unpacked = new ArrayList<>(args.snapshot()); NewArrayNode varArgParameter = (NewArrayNode) unpacked.remove(unpacked.size() - 1); int firstVarArg = unpacked.size(); for (Node usage : varArgParameter.usages()) { @@ -111,18 +129,57 @@ unpacked.add(si.value()); } } - verifyParameters(callerGraph, callTarget.targetMethod(), unpacked, stringType, startArgIdx, firstVarArg); + verifyParameters(callerGraph, callTarget, unpacked, stringType, startArgIdx, firstVarArg); } else { - verifyParameters(callerGraph, callTarget.targetMethod(), args, stringType, startArgIdx, -1); + verifyParameters(callerGraph, callTarget, args, stringType, startArgIdx, -1); } } - private static void verifyParameters(StructuredGraph callerGraph, ResolvedJavaMethod verifiedCallee, List args, ResolvedJavaType stringType, int startArgIdx, int varArgsIndex) { + private static final Set DebugLevels = new HashSet<>(Arrays.asList(BASIC_LEVEL, INFO_LEVEL, VERBOSE_LEVEL, DETAILED_LEVEL, VERY_DETAILED_LEVEL)); + + /** + * The set of methods allowed to call a {@code Debug.dump(...)} method with the {@code level} + * parameter bound to {@link Debug#BASIC_LEVEL} and the {@code object} parameter bound to a + * {@link StructuredGraph} value. + * + * This whitelist exists to ensure any increase in graph dumps is in line with the policy + * outlined by {@link Debug#BASIC_LEVEL}. If you add a *justified* graph dump at this level, + * then update the whitelist. + */ + private static final Set BasicLevelStructuredGraphDumpWhitelist = new HashSet<>(Arrays.asList( + "org.graalvm.compiler.phases.BasePhase.dumpAfter", + "org.graalvm.compiler.core.GraalCompiler.emitFrontEnd", + "org.graalvm.compiler.truffle.PartialEvaluator.fastPartialEvaluation", + "org.graalvm.compiler.truffle.PartialEvaluator.reportPerformanceWarnings", + "org.graalvm.compiler.truffle.TruffleCompiler.compileMethodHelper", + "org.graalvm.compiler.core.test.VerifyDebugUsageTest$ValidDumpUsagePhase.run", + "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidConcatDumpUsagePhase.run", + "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidDumpUsagePhase.run")); + + /** + * The set of methods allowed to call a {@code Debug.dump(...)} method with the {@code level} + * parameter bound to {@link Debug#INFO_LEVEL} and the {@code object} parameter bound to a + * {@link StructuredGraph} value. + * + * This whitelist exists to ensure any increase in graph dumps is in line with the policy + * outlined by {@link Debug#INFO_LEVEL}. If you add a *justified* graph dump at this level, then + * update the whitelist. + */ + private static final Set InfoLevelStructuredGraphDumpWhitelist = new HashSet<>(Arrays.asList( + "org.graalvm.compiler.core.GraalCompiler.emitFrontEnd", + "org.graalvm.compiler.phases.BasePhase.dumpAfter", + "org.graalvm.compiler.replacements.ReplacementsImpl$GraphMaker.makeGraph", + "org.graalvm.compiler.replacements.SnippetTemplate.instantiate")); + + private void verifyParameters(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, List args, ResolvedJavaType stringType, int startArgIdx, + int varArgsIndex) { + ResolvedJavaMethod verifiedCallee = debugCallTarget.targetMethod(); + Integer dumpLevel = null; int argIdx = startArgIdx; int varArgsElementIndex = 0; boolean reportVarArgs = false; for (int i = 0; i < args.size(); i++) { - Node arg = args.get(i); + ValueNode arg = args.get(i); if (arg instanceof Invoke) { reportVarArgs = varArgsIndex >= 0 && argIdx >= varArgsIndex; Invoke invoke = (Invoke) arg; @@ -142,6 +199,15 @@ } } } + if (i == 0) { + if (verifiedCallee.getName().equals("dump")) { + dumpLevel = verifyDumpLevelParameter(callerGraph, debugCallTarget, verifiedCallee, arg); + } + } else if (i == 1) { + if (dumpLevel != null) { + verifyDumpObjectParameter(callerGraph, debugCallTarget, args, verifiedCallee, dumpLevel); + } + } if (varArgsIndex >= 0 && i >= varArgsIndex) { varArgsElementIndex++; } @@ -150,6 +216,63 @@ } /** + * The {@code level} arg for the {@code Debug.dump(...)} methods must be a reference to one of + * the {@code Debug.*_LEVEL} constants. + */ + protected Integer verifyDumpLevelParameter(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, ResolvedJavaMethod verifiedCallee, ValueNode arg) + throws org.graalvm.compiler.phases.VerifyPhase.VerificationError { + // The 'level' arg for the Debug.dump(...) methods must be a reference to one of + // the Debug.*_LEVEL constants. + + Constant c = arg.asConstant(); + if (c != null) { + Integer dumpLevel = ((PrimitiveConstant) c).asInt(); + if (!DebugLevels.contains(dumpLevel)) { + StackTraceElement e = callerGraph.method().asStackTraceElement(debugCallTarget.invoke().bci()); + throw new VerificationError( + "In %s: parameter 0 of call to %s does not match a Debug.*_LEVEL constant.%n", e, verifiedCallee.format("%H.%n(%p)")); + } + return dumpLevel; + } + StackTraceElement e = callerGraph.method().asStackTraceElement(debugCallTarget.invoke().bci()); + throw new VerificationError( + "In %s: parameter 0 of call to %s must be a constant.%n", e, verifiedCallee.format("%H.%n(%p)")); + } + + protected void verifyDumpObjectParameter(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, List args, ResolvedJavaMethod verifiedCallee, Integer dumpLevel) + throws org.graalvm.compiler.phases.VerifyPhase.VerificationError { + ResolvedJavaType arg1Type = ((ObjectStamp) args.get(1).stamp()).type(); + if (metaAccess.lookupJavaType(StructuredGraph.class).isAssignableFrom(arg1Type)) { + verifyStructuredGraphDumping(callerGraph, debugCallTarget, verifiedCallee, dumpLevel); + } + } + + /** + * Verifies that dumping a {@link StructuredGraph} at level {@link Debug#BASIC_LEVEL} or + * {@link Debug#INFO_LEVEL} only occurs in white-listed methods. + */ + protected void verifyStructuredGraphDumping(StructuredGraph callerGraph, MethodCallTargetNode debugCallTarget, ResolvedJavaMethod verifiedCallee, Integer dumpLevel) + throws org.graalvm.compiler.phases.VerifyPhase.VerificationError { + if (dumpLevel == Debug.BASIC_LEVEL) { + StackTraceElement e = callerGraph.method().asStackTraceElement(debugCallTarget.invoke().bci()); + String qualifiedMethod = e.getClassName() + "." + e.getMethodName(); + if (!BasicLevelStructuredGraphDumpWhitelist.contains(qualifiedMethod)) { + throw new VerificationError( + "In %s: call to %s with level == Debug.BASIC_LEVEL not in %s.BasicLevelDumpWhitelist.%n", e, verifiedCallee.format("%H.%n(%p)"), + getClass().getName()); + } + } else if (dumpLevel == Debug.INFO_LEVEL) { + StackTraceElement e = callerGraph.method().asStackTraceElement(debugCallTarget.invoke().bci()); + String qualifiedMethod = e.getClassName() + "." + e.getMethodName(); + if (!InfoLevelStructuredGraphDumpWhitelist.contains(qualifiedMethod)) { + throw new VerificationError( + "In %s: call to %s with level == Debug.INFO_LEVEL not in %s.InfoLevelDumpWhitelist.%n", e, verifiedCallee.format("%H.%n(%p)"), + getClass().getName()); + } + } + } + + /** * Checks that a given call is not to {@link StringBuffer#toString()} or * {@link StringBuilder#toString()}. */ diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Thu Apr 06 14:31:32 2017 -0700 @@ -158,7 +158,7 @@ } else if (isToStringTrusted(c)) { return value.toString(); } - return MetaUtil.getSimpleName(c, true) + "@" + System.identityHashCode(value); + return MetaUtil.getSimpleName(c, true) + "@" + Integer.toHexString(System.identityHashCode(value)); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java Thu Apr 06 14:31:32 2017 -0700 @@ -173,6 +173,9 @@ Map properties = new HashMap<>(); properties.put("graph", graph.toString()); properties.put("scope", Debug.currentScope()); + if (graph instanceof StructuredGraph) { + properties.put("compilationIdentifier", ((StructuredGraph) graph).compilationId()); + } addCFGFileName(properties); printer.print(graph, nextDumpId() + ":" + message, properties); } catch (IOException e) { @@ -298,7 +301,6 @@ } private void openScope(String name, int inlineDepth, Map properties) { - String prefix = inlineDepth == 0 ? Thread.currentThread().getName() + ":" : ""; try { Map props = properties; if (inlineDepth == 0) { @@ -312,7 +314,7 @@ } props.put("date", new Date().toString()); } - printer.beginGroup(prefix + name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1, props); + printer.beginGroup(name, name, Debug.contextLookup(ResolvedJavaMethod.class), -1, props); } catch (IOException e) { handleException(e); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/InstanceOfTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -488,7 +488,7 @@ try (Scope s = Debug.scope("InstanceOfTest", getMetaAccess().lookupJavaMethod(getMethod(snippet)))) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); compile(graph.method(), graph); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, snippet); + Debug.dump(Debug.BASIC_LEVEL, graph, snippet); return graph; } catch (Throwable e) { throw Debug.handle(e); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -56,9 +56,9 @@ try (Scope s = Debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); HighTierContext context = getDefaultHighTierContext(); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new InliningPhase(new CanonicalizerPhase()).apply(graph, context); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph"); + Debug.dump(Debug.BASIC_LEVEL, graph, "Graph"); new CanonicalizerPhase().apply(graph, context); new DeadCodeEliminationPhase().apply(graph); // Try to ensure any macro nodes are lowered to expose any resulting invokes diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/PEGraphDecoderTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -133,11 +133,12 @@ try (Debug.Scope scope = Debug.scope("GraphPETest", testMethod)) { GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true); registerPlugins(graphBuilderConfig.getPlugins().getInvocationPlugins()); - CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, getTarget().arch, getInitialOptions()); + targetGraph = new StructuredGraph.Builder(getInitialOptions(), AllowAssumptions.YES).method(testMethod).build(); + CachingPEGraphDecoder decoder = new CachingPEGraphDecoder(getTarget().arch, targetGraph, getProviders(), graphBuilderConfig, OptimisticOptimizations.NONE, AllowAssumptions.YES, + getInitialOptions(), null, null, new InlineInvokePlugin[]{new InlineAll()}, null); - targetGraph = new StructuredGraph.Builder(getInitialOptions(), AllowAssumptions.YES).method(testMethod).build(); - decoder.decode(targetGraph, testMethod, null, null, new InlineInvokePlugin[]{new InlineAll()}, null); - Debug.dump(Debug.BASIC_LOG_LEVEL, targetGraph, "Target Graph"); + decoder.decode(testMethod); + Debug.dump(Debug.BASIC_LEVEL, targetGraph, "Target Graph"); targetGraph.verify(); PhaseContext context = new PhaseContext(getProviders()); @@ -146,7 +147,7 @@ } catch (Throwable ex) { if (targetGraph != null) { - Debug.dump(Debug.BASIC_LOG_LEVEL, targetGraph, ex.toString()); + Debug.dump(Debug.BASIC_LEVEL, targetGraph, ex.toString()); } Debug.handle(ex); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionsTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -133,7 +133,7 @@ @Override protected Plugins getDefaultGraphBuilderPlugins() { Plugins ret = super.getDefaultGraphBuilderPlugins(); - // manually register generated factories, jvmci service providers don't work from unit tests + // manually register generated factories, Graal service providers don't work from unit tests new PluginFactory_SubstitutionsTest().registerPlugins(ret.getInvocationPlugins(), null); return ret; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,12 +32,10 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.tools.Diagnostic.Kind; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.graph.Node.InjectedNodeParameter; import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency; /** * Create graph builder plugins for {@link NodeIntrinsic} methods. @@ -124,10 +122,6 @@ } out.printf(");\n"); - if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) { - out.printf(" node.setStamp(%s);\n", deps.use(WellKnownDependency.RETURN_STAMP)); - } - if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) { out.printf(" b.add(node);\n"); } else { @@ -164,10 +158,6 @@ out.printf(", arg%d", i); } out.printf(");\n"); - - if (intrinsicMethod.getAnnotation(NodeIntrinsic.class).setStampFromReturnType()) { - env.getMessager().printMessage(Kind.WARNING, "Ignoring setStampFromReturnType because a custom 'intrinsify' method is used.", intrinsicMethod); - } } } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java Thu Apr 06 14:31:32 2017 -0700 @@ -60,23 +60,24 @@ } } - private static final class StampDependency extends Dependency { + private static final class InjectedStampDependency extends Dependency { - private StampDependency() { - super("returnStamp", "org.graalvm.compiler.core.common.type.Stamp"); + private InjectedStampDependency() { + super("stamp", "org.graalvm.compiler.core.common.type.Stamp"); } @Override public String inject(ExecutableElement inject) { NodeIntrinsic nodeIntrinsic = inject.getAnnotation(NodeIntrinsic.class); - return String.format("injection.getReturnStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nodeIntrinsic != null && nodeIntrinsic.returnStampIsNonNull()); + boolean nonNull = nodeIntrinsic != null && nodeIntrinsic.injectedStampIsNonNull(); + return String.format("injection.getInjectedStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nonNull); } } public enum WellKnownDependency { CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"), META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"), - RETURN_STAMP(new StampDependency()), + INJECTED_STAMP(new InjectedStampDependency()), SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "org.graalvm.compiler.api.replacements.SnippetReflectionProvider")), STAMP_PROVIDER("b.getStampProvider()", "org.graalvm.compiler.nodes.spi.StampProvider"), STRUCTURED_GRAPH("b.getGraph()", "org.graalvm.compiler.nodes.StructuredGraph"); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,7 +25,11 @@ import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; +import java.util.Formatter; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.AnnotationMirror; @@ -57,6 +61,10 @@ return env.getElementUtils().getTypeElement("org.graalvm.compiler.graph.Node").asType(); } + private TypeMirror stampType() { + return env.getElementUtils().getTypeElement("org.graalvm.compiler.core.common.type.Stamp").asType(); + } + private TypeMirror valueNodeType() { return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType(); } @@ -118,32 +126,68 @@ } } - if (intrinsicMethod.getReturnType() instanceof TypeVariable) { + TypeMirror returnType = intrinsicMethod.getReturnType(); + if (returnType instanceof TypeVariable) { env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation); } + boolean injectedStampIsNonNull = intrinsicMethod.getAnnotation(NodeIntrinsic.class).injectedStampIsNonNull(); + + if (returnType.getKind() == TypeKind.VOID) { + for (VariableElement parameter : intrinsicMethod.getParameters()) { + if (parameter.getAnnotation(InjectedNodeParameter.class) != null) { + env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic with an injected Stamp parameter cannot have a void return type.", element, annotation); + break; + } + } + } + TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod); - ExecutableElement custom = findCustomIntrinsifyMethod(nodeClass, constructorSignature); - if (custom != null) { - generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, custom, constructorSignature)); + Map nonMatches = new HashMap<>(); + List factories = findIntrinsifyFactoryMethod(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull); + List constructors = Collections.emptyList(); + if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) { + if (factories.isEmpty()) { + env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make a node intrinsic for an abstract class %s.", nodeClass.getSimpleName()), element, annotation); + } + } else if (!isNodeType(nodeClass)) { + if (factories.isEmpty()) { + env.getMessager().printMessage(Kind.ERROR, String.format("%s is not a subclass of %s.", nodeClass.getSimpleName(), nodeType()), element, annotation); + } } else { - if (isNodeType(nodeClass)) { - if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) { - env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make @NodeIntrinsic for abstract node class %s.", nodeClass.getSimpleName()), element, annotation); - } else { - TypeMirror ret = intrinsicMethod.getReturnType(); - if (env.getTypeUtils().isAssignable(ret, structuralInputType())) { - checkInputType(nodeClass, ret, element, annotation); - } + TypeMirror ret = returnType; + if (env.getTypeUtils().isAssignable(ret, structuralInputType())) { + checkInputType(nodeClass, ret, element, annotation); + } - ExecutableElement constructor = findConstructor(nodeClass, constructorSignature, intrinsicMethod, annotation); - if (constructor != null) { - generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructor, constructorSignature)); - } + constructors = findConstructors(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull); + } + Formatter msg = new Formatter(); + if (factories.size() > 1) { + msg.format("Found more than one factory in %s matching node intrinsic:", nodeClass); + for (ExecutableElement candidate : factories) { + msg.format("%n %s", candidate); + } + env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation); + } else if (constructors.size() > 1) { + msg.format("Found more than one constructor in %s matching node intrinsic:", nodeClass); + for (ExecutableElement candidate : constructors) { + msg.format("%n %s", candidate); + } + env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation); + } else if (factories.size() == 1) { + generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, factories.get(0), constructorSignature)); + } else if (constructors.size() == 1) { + generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructors.get(0), constructorSignature)); + } else { + msg.format("Could not find any factories or constructors in %s matching node intrinsic", nodeClass); + if (!nonMatches.isEmpty()) { + msg.format("%nFactories and constructors that failed to match:"); + for (Map.Entry e : nonMatches.entrySet()) { + msg.format("%n %s: %s", e.getKey(), e.getValue()); } - } else { - env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is not a Node subclass.", nodeClass.getSimpleName()), element, annotation); } + env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation); } } @@ -201,34 +245,20 @@ return parameters; } - private ExecutableElement findConstructor(TypeElement nodeClass, TypeMirror[] signature, ExecutableElement intrinsicMethod, AnnotationMirror intrinsicAnnotation) { + private List findConstructors(TypeElement nodeClass, TypeMirror[] signature, Map nonMatches, boolean requiresInjectedStamp) { List constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements()); - List failureReasons = new ArrayList<>(); - + List found = new ArrayList<>(constructors.size()); for (ExecutableElement constructor : constructors) { - String failureReason = matchSignature(0, constructor, signature); - if (failureReason == null) { - // found - return constructor; - } - - failureReasons.add(failureReason); - } - - // not found - if (failureReasons.isEmpty()) { - env.getMessager().printMessage(Kind.ERROR, "Could not find matching constructor for node intrinsic.", intrinsicMethod, intrinsicAnnotation); - } else { - for (String reason : failureReasons) { - env.getMessager().printMessage(Kind.ERROR, reason, intrinsicMethod, intrinsicAnnotation); + if (matchSignature(0, constructor, signature, nonMatches, requiresInjectedStamp)) { + found.add(constructor); } } - - return null; + return found; } - private ExecutableElement findCustomIntrinsifyMethod(TypeElement nodeClass, TypeMirror[] signature) { + private List findIntrinsifyFactoryMethod(TypeElement nodeClass, TypeMirror[] signature, Map nonMatches, boolean requiresInjectedStamp) { List methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements()); + List found = new ArrayList<>(methods.size()); for (ExecutableElement method : methods) { if (!method.getSimpleName().toString().equals("intrinsify")) { continue; @@ -248,50 +278,64 @@ continue; } - String failureReason = matchSignature(2, method, signature); - if (failureReason == null) { - // found - return method; + if (method.getReturnType().getKind() != TypeKind.BOOLEAN) { + continue; + } + + if (matchSignature(2, method, signature, nonMatches, requiresInjectedStamp)) { + found.add(method); } } - - return null; + return found; } - private String matchSignature(int numSkippedParameters, ExecutableElement method, TypeMirror[] signature) { + private boolean matchSignature(int numSkippedParameters, ExecutableElement method, TypeMirror[] signature, Map nonMatches, boolean requiresInjectedStamp) { int sIdx = 0; int cIdx = numSkippedParameters; + boolean missingStampArgument = requiresInjectedStamp; while (cIdx < method.getParameters().size()) { VariableElement parameter = method.getParameters().get(cIdx++); + TypeMirror paramType = parameter.asType(); if (parameter.getAnnotation(InjectedNodeParameter.class) != null) { + if (missingStampArgument && env.getTypeUtils().isSameType(paramType, stampType())) { + missingStampArgument = false; + } // skip injected parameters continue; } + if (missingStampArgument) { + nonMatches.put(method, String.format("missing injected %s argument", stampType())); + return false; + } - TypeMirror paramType = parameter.asType(); if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) { // last argument of constructor is varargs, match remaining intrinsic arguments TypeMirror varargsType = ((ArrayType) paramType).getComponentType(); while (sIdx < signature.length) { if (!isTypeCompatible(varargsType, signature[sIdx++])) { - return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, varargsType, signature[sIdx - 1]); + nonMatches.put(method, String.format("the types of argument %d are incompatible: %s != %s", sIdx, varargsType, signature[sIdx - 1])); + return false; } } } else if (sIdx >= signature.length) { // too many arguments in intrinsic method - return String.format("Too many arguments for %s", method); + nonMatches.put(method, "too many arguments"); + return false; } else if (!isTypeCompatible(paramType, signature[sIdx++])) { - return String.format("%s failed because the types of argument %d are incompatible: %s != %s", method, sIdx, paramType, signature[sIdx - 1]); + nonMatches.put(method, String.format("the type of argument %d is incompatible: %s != %s", sIdx, paramType, signature[sIdx - 1])); + return false; } } + if (missingStampArgument) { + nonMatches.put(method, String.format("missing injected %s argument", stampType())); + return false; + } - if (sIdx == signature.length) { - // found - return null; + if (sIdx != signature.length) { + nonMatches.put(method, "not enough arguments"); + return false; } - - // too many arguments in constructor - return String.format("Not enough arguments for %s", method); + return true; } private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -32,7 +32,11 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; +import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.common.CanonicalizerPhase; @@ -56,9 +60,11 @@ private final AllowAssumptions allowAssumptions; private final EconomicMap graphCache; - public CachingPEGraphDecoder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, AllowAssumptions allowAssumptions, - Architecture architecture, OptionValues options) { - super(providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), architecture, options); + public CachingPEGraphDecoder(Architecture architecture, StructuredGraph graph, Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, + AllowAssumptions allowAssumptions, OptionValues options, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, + ParameterPlugin parameterPlugin) { + super(architecture, graph, providers.getMetaAccess(), providers.getConstantReflection(), providers.getConstantFieldProvider(), providers.getStampProvider(), options, loopExplosionPlugin, + invocationPlugins, inlineInvokePlugins, parameterPlugin); this.providers = providers; this.graphBuilderConfig = graphBuilderConfig; @@ -74,22 +80,22 @@ @SuppressWarnings("try") private EncodedGraph createGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider) { - StructuredGraph graph = new StructuredGraph.Builder(options, allowAssumptions).useProfilingInfo(false).method(method).build(); - try (Debug.Scope scope = Debug.scope("createGraph", graph)) { + StructuredGraph graphToEncode = new StructuredGraph.Builder(options, allowAssumptions).useProfilingInfo(false).method(method).build(); + try (Debug.Scope scope = Debug.scope("createGraph", graphToEncode)) { IntrinsicContext initialIntrinsicContext = intrinsicBytecodeProvider != null ? new IntrinsicContext(method, method, intrinsicBytecodeProvider, INLINE_AFTER_PARSING) : null; GraphBuilderPhase.Instance graphBuilderPhaseInstance = createGraphBuilderPhaseInstance(initialIntrinsicContext); - graphBuilderPhaseInstance.apply(graph); + graphBuilderPhaseInstance.apply(graphToEncode); PhaseContext context = new PhaseContext(providers); - new CanonicalizerPhase().apply(graph, context); + new CanonicalizerPhase().apply(graphToEncode, context); /* * ConvertDeoptimizeToGuardPhase reduces the number of merges in the graph, so that * fewer frame states will be created. This significantly reduces the number of nodes in * the initial graph. */ - new ConvertDeoptimizeToGuardPhase().apply(graph, context); + new ConvertDeoptimizeToGuardPhase().apply(graphToEncode, context); - EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, architecture); + EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graphToEncode, architecture); graphCache.put(method, encodedGraph); return encodedGraph; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Thu Apr 06 14:31:32 2017 -0700 @@ -44,7 +44,6 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.type.IntegerStamp; -import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; @@ -78,11 +77,11 @@ import org.graalvm.compiler.nodes.extended.JavaWriteNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.extended.RawLoadNode; +import org.graalvm.compiler.nodes.extended.RawStoreNode; import org.graalvm.compiler.nodes.extended.UnboxNode; -import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode; import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode; -import org.graalvm.compiler.nodes.extended.RawStoreNode; import org.graalvm.compiler.nodes.java.AbstractNewObjectNode; import org.graalvm.compiler.nodes.java.AccessIndexedNode; import org.graalvm.compiler.nodes.java.ArrayLengthNode; @@ -374,7 +373,7 @@ */ public AddressNode createArrayIndexAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index, GuardingNode boundsCheck) { IntegerStamp indexStamp = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1); - ValueNode positiveIndex = graph.unique(new PiNode(index, indexStamp, boundsCheck != null ? boundsCheck.asNode() : null)); + ValueNode positiveIndex = graph.maybeAddOrUnique(PiNode.create(index, indexStamp, boundsCheck != null ? boundsCheck.asNode() : null)); return createArrayAddress(graph, array, elementKind, positiveIndex); } @@ -961,7 +960,7 @@ arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength); } - LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength, tool.getConstantReflection()); + LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength); if (boundsCheck.isTautology()) { return null; } else { @@ -981,7 +980,7 @@ if (nullCheck == null) { return object; } else { - return before.graph().unique(new PiNode(object, ((ObjectStamp) object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck)); + return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck)); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Thu Apr 06 14:31:32 2017 -0700 @@ -358,7 +358,7 @@ * {@link #endIf} to close the if-block. * * @param condition The condition for the if-block - * @param trueProbability The estimated probability the the condition is true + * @param trueProbability The estimated probability the condition is true */ public void startIf(LogicNode condition, double trueProbability) { AbstractBeginNode thenSuccessor = graph.add(new BeginNode()); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java Thu Apr 06 14:31:32 2017 -0700 @@ -50,7 +50,7 @@ } @Override - public Stamp getReturnStamp(Class type, boolean nonNull) { + public Stamp getInjectedStamp(Class type, boolean nonNull) { JavaKind kind = JavaKind.fromJavaClass(type); if (kind == JavaKind.Object) { ResolvedJavaType returnType = metaAccess.lookupJavaType(type); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Thu Apr 06 14:31:32 2017 -0700 @@ -23,14 +23,12 @@ package org.graalvm.compiler.replacements; import static org.graalvm.compiler.debug.GraalError.unimplemented; -import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -54,6 +52,7 @@ import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; +import org.graalvm.compiler.nodes.ControlSinkNode; import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.nodes.EncodedGraph; import org.graalvm.compiler.nodes.FixedNode; @@ -137,10 +136,6 @@ protected final InvokeData invokeData; protected final int inliningDepth; - protected final LoopExplosionPlugin loopExplosionPlugin; - protected final InvocationPlugins invocationPlugins; - protected final InlineInvokePlugin[] inlineInvokePlugins; - protected final ParameterPlugin parameterPlugin; protected final ValueNode[] arguments; protected FrameState outerState; @@ -149,21 +144,17 @@ protected NodeSourcePosition callerBytecodePosition; protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, - int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin, - ValueNode[] arguments) { + int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, ValueNode[] arguments) { super(callerLoopScope, targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); this.caller = caller; this.method = method; this.invokeData = invokeData; this.inliningDepth = inliningDepth; - this.loopExplosionPlugin = loopExplosionPlugin; - this.invocationPlugins = invocationPlugins; - this.inlineInvokePlugins = inlineInvokePlugins; - this.parameterPlugin = parameterPlugin; this.arguments = arguments; } + @Override public boolean isInlinedMethod() { return caller != null; } @@ -219,7 +210,7 @@ @Override public StructuredGraph getGraph() { - return methodScope.graph; + return graph; } @Override @@ -399,10 +390,19 @@ } protected final OptionValues options; + private final LoopExplosionPlugin loopExplosionPlugin; + private final InvocationPlugins invocationPlugins; + private final InlineInvokePlugin[] inlineInvokePlugins; + private final ParameterPlugin parameterPlugin; - public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider, - Architecture architecture, OptionValues options) { - super(metaAccess, constantReflection, constantFieldProvider, stampProvider, true, architecture); + public PEGraphDecoder(Architecture architecture, StructuredGraph graph, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, + StampProvider stampProvider, OptionValues options, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, + ParameterPlugin parameterPlugin) { + super(architecture, graph, metaAccess, constantReflection, constantFieldProvider, stampProvider, true); + this.loopExplosionPlugin = loopExplosionPlugin; + this.invocationPlugins = invocationPlugins; + this.inlineInvokePlugins = inlineInvokePlugins; + this.parameterPlugin = parameterPlugin; this.options = options; } @@ -414,20 +414,17 @@ } } - public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, - ParameterPlugin parameterPlugin) { - PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, invocationPlugins, - inlineInvokePlugins, - parameterPlugin, null); + public void decode(ResolvedJavaMethod method) { + PEMethodScope methodScope = new PEMethodScope(graph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, null); decode(createInitialLoopScope(methodScope, null)); cleanupGraph(methodScope); - Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After graph cleanup"); - assert methodScope.graph.verify(); + Debug.dump(Debug.VERBOSE_LEVEL, graph, "After graph cleanup"); + assert graph.verify(); try { /* Check that the control flow graph can be computed, to catch problems early. */ - assert CFGVerifier.verify(ControlFlowGraph.compute(methodScope.graph, true, true, true, true)); + assert CFGVerifier.verify(ControlFlowGraph.compute(graph, true, true, true, true)); } catch (Throwable ex) { throw GraalError.shouldNotReachHere("Control flow graph not valid after partial evaluation"); } @@ -437,7 +434,7 @@ protected void cleanupGraph(MethodScope methodScope) { super.cleanupGraph(methodScope); - for (FrameState frameState : methodScope.graph.getNodes(FrameState.TYPE)) { + for (FrameState frameState : graph.getNodes(FrameState.TYPE)) { if (frameState.bci == BytecodeFrame.UNWIND_BCI) { /* * handleMissingAfterExceptionFrameState is called during graph decoding from @@ -492,7 +489,7 @@ } /* We know that we need an invoke, so now we can add the call target to the graph. */ - methodScope.graph.add(callTarget); + graph.add(callTarget); registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); return super.handleInvoke(methodScope, loopScope, invokeData); } @@ -519,21 +516,21 @@ return inlineLoopScope; } - for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) { + for (InlineInvokePlugin plugin : inlineInvokePlugins) { plugin.notifyNotInlined(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); } return null; } protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { - if (methodScope.invocationPlugins == null) { + if (invocationPlugins == null) { return false; } Invoke invoke = invokeData.invoke; ResolvedJavaMethod targetMethod = callTarget.targetMethod(); - InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod); + InvocationPlugin invocationPlugin = invocationPlugins.lookupInvocation(targetMethod); if (invocationPlugin == null) { return false; } @@ -546,8 +543,7 @@ */ invoke.asNode().replaceAtPredecessor(null); - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin, - methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments); + PEMethodScope inlineScope = new PEMethodScope(graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, loopExplosionPlugin, arguments); PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor); InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); @@ -587,7 +583,7 @@ ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); - for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) { + for (InlineInvokePlugin plugin : inlineInvokePlugins) { InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments); if (inlineInfo != null) { if (inlineInfo.getMethodToInline() == null) { @@ -611,7 +607,7 @@ throw tooDeepInlining(methodScope); } - for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) { + for (InlineInvokePlugin plugin : inlineInvokePlugins) { plugin.notifyBeforeInline(inlineMethod); } @@ -620,16 +616,8 @@ FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); invokeNode.replaceAtPredecessor(null); - PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, - methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments); - - /* - * After decoding all the nodes of the inlined method, we need to re-wire the return and - * unwind nodes. Since inlining is non-recursive, this cannot be done at the end of this - * method, but must be registered as a cleanup task that runs when all nodes of the inlined - * methods have been decoded. - */ - inlineScope.cleanupTasks.add(() -> finishInlining(methodScope, loopScope, invokeData, inlineMethod, inlineScope)); + PEMethodScope inlineScope = new PEMethodScope(graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, + loopExplosionPlugin, arguments); /* * Do the actual inlining by returning the initial loop scope for the inlined method scope. @@ -637,32 +625,43 @@ return createInitialLoopScope(inlineScope, predecessor); } - protected void finishInlining(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, ResolvedJavaMethod inlineMethod, PEMethodScope inlineScope) { + @Override + protected void finishInlining(MethodScope is) { + PEMethodScope inlineScope = (PEMethodScope) is; + ResolvedJavaMethod inlineMethod = inlineScope.method; + PEMethodScope methodScope = inlineScope.caller; + LoopScope loopScope = inlineScope.callerLoopScope; + InvokeData invokeData = inlineScope.invokeData; Invoke invoke = invokeData.invoke; FixedNode invokeNode = invoke.asNode(); ValueNode exceptionValue = null; - List unwindNodes = inlineScope.unwindNodes; - Iterator iter = unwindNodes.iterator(); - while (iter.hasNext()) { - if (iter.next().isDeleted()) { - iter.remove(); + int returnNodeCount = 0; + int unwindNodeCount = 0; + List returnAndUnwindNodes = inlineScope.returnAndUnwindNodes; + for (int i = 0; i < returnAndUnwindNodes.size(); i++) { + FixedNode fixedNode = returnAndUnwindNodes.get(i); + if (fixedNode instanceof ReturnNode) { + returnNodeCount++; + } else if (fixedNode.isAlive()) { + assert fixedNode instanceof UnwindNode; + unwindNodeCount++; } } - if (!unwindNodes.isEmpty()) { + if (unwindNodeCount > 0) { FixedNode unwindReplacement; if (invoke instanceof InvokeWithExceptionNode) { /* Decoding continues for the exception handler. */ unwindReplacement = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); } else { /* No exception handler available, so the only thing we can do is deoptimize. */ - unwindReplacement = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); + unwindReplacement = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); } - if (unwindNodes.size() == 1) { + if (unwindNodeCount == 1) { /* Only one UnwindNode, we can use the exception directly. */ - UnwindNode unwindNode = unwindNodes.get(0); + UnwindNode unwindNode = getSingleMatchingNode(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class); exceptionValue = unwindNode.exception(); unwindNode.replaceAndDelete(unwindReplacement); @@ -673,8 +672,9 @@ * also explode exception paths. Merge the exception in a similar way as multiple * return values. */ - MergeNode unwindMergeNode = methodScope.graph.add(new MergeNode()); - exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, unwindNodes, unwindNode -> unwindNode.exception()); + MergeNode unwindMergeNode = graph.add(new MergeNode()); + exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, getMatchingNodes(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class, unwindNodeCount), + unwindNode -> unwindNode.exception()); unwindMergeNode.setNext(unwindReplacement); ensureExceptionStateDecoded(inlineScope); @@ -686,22 +686,19 @@ assert !(invoke instanceof InvokeWithExceptionNode) || ((InvokeWithExceptionNode) invoke).exceptionEdge() == null; ValueNode returnValue; - List returnNodes = inlineScope.returnNodes; - if (!returnNodes.isEmpty()) { - if (returnNodes.size() == 1) { - ReturnNode returnNode = returnNodes.get(0); - returnValue = returnNode.result(); - FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode)); - returnNode.replaceAndDelete(n); - } else { - AbstractMergeNode merge = methodScope.graph.add(new MergeNode()); - merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); - returnValue = InliningUtil.mergeReturns(merge, returnNodes); - FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge); - merge.setNext(n); - } + if (returnNodeCount == 0) { + returnValue = null; + } else if (returnNodeCount == 1) { + ReturnNode returnNode = getSingleMatchingNode(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class); + returnValue = returnNode.result(); + FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode)); + returnNode.replaceAndDelete(n); } else { - returnValue = null; + AbstractMergeNode merge = graph.add(new MergeNode()); + merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); + returnValue = InliningUtil.mergeReturns(merge, getMatchingNodes(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class, returnNodeCount)); + FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge); + merge.setNext(n); } invokeNode.replaceAtUsages(returnValue); @@ -718,13 +715,42 @@ } deleteInvoke(invoke); - for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) { + for (InlineInvokePlugin plugin : inlineInvokePlugins) { plugin.notifyAfterInline(inlineMethod); } + } + + @SuppressWarnings("unchecked") + private static T getSingleMatchingNode(List returnAndUnwindNodes, boolean hasNonMatchingEntries, Class clazz) { + if (!hasNonMatchingEntries) { + assert returnAndUnwindNodes.size() == 1; + return (T) returnAndUnwindNodes.get(0); + } - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue(options)) { - Debug.dump(Debug.INFO_LOG_LEVEL, methodScope.graph, "Inline finished: %s.%s", inlineMethod.getDeclaringClass().getUnqualifiedName(), inlineMethod.getName()); + for (int i = 0; i < returnAndUnwindNodes.size(); i++) { + ControlSinkNode node = returnAndUnwindNodes.get(i); + if (clazz.isInstance(node)) { + return (T) node; + } } + throw GraalError.shouldNotReachHere(); + } + + @SuppressWarnings("unchecked") + private static List getMatchingNodes(List returnAndUnwindNodes, boolean hasNonMatchingEntries, Class clazz, int resultCount) { + if (!hasNonMatchingEntries) { + return (List) returnAndUnwindNodes; + } + + List result = new ArrayList<>(resultCount); + for (int i = 0; i < returnAndUnwindNodes.size(); i++) { + ControlSinkNode node = returnAndUnwindNodes.get(i); + if (clazz.isInstance(node)) { + result.add((T) node); + } + } + assert result.size() == resultCount; + return result; } private static RuntimeException tooDeepInlining(PEMethodScope methodScope) { @@ -809,25 +835,27 @@ } @Override - protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) { + protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node n) { PEMethodScope methodScope = (PEMethodScope) s; + Node node = n; if (node instanceof ParameterNode) { ParameterNode param = (ParameterNode) node; - if (methodScope.arguments != null) { + if (methodScope.isInlinedMethod()) { Node result = methodScope.arguments[param.index()]; assert result != null; return result; - } else if (methodScope.parameterPlugin != null) { + } else if (parameterPlugin != null) { + assert !methodScope.isInlinedMethod(); GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); - Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, param.index(), + Node result = parameterPlugin.interceptParameter(graphBuilderContext, param.index(), StampPair.create(param.stamp(), param.uncheckedStamp())); if (result != null) { return result; } } - + node = param.copyWithInputs(); } return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node); @@ -841,7 +869,7 @@ } JavaKind invokeReturnKind = methodScope.invokeData.invoke.asNode().getStackKind(); - FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null); + FrameState outerState = stateAtReturn.duplicateModified(graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null); /* * When the encoded graph has methods inlining, we can already have a proper caller @@ -866,7 +894,7 @@ ensureStateAfterDecoded(methodScope); assert methodScope.exceptionPlaceholderNode == null; - methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode()); + methodScope.exceptionPlaceholderNode = graph.add(new ExceptionPlaceholderNode()); registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Thu Apr 06 14:31:32 2017 -0700 @@ -322,7 +322,7 @@ finalizeGraph(graph); - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "%s: Final", method.getName()); + Debug.dump(Debug.INFO_LEVEL, graph, "%s: Final", method.getName()); return graph; } catch (Throwable e) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,6 +25,7 @@ import static java.util.FormattableFlags.ALTERNATE; import static org.graalvm.compiler.core.common.LocationIdentity.any; import static org.graalvm.compiler.debug.Debug.applyFormattingFlagsAndWidth; +import static org.graalvm.compiler.debug.GraalDebugConfig.Options.DebugStubsAndSnippets; import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; @@ -57,7 +58,9 @@ import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.debug.Debug; import org.graalvm.compiler.debug.Debug.Scope; +import org.graalvm.compiler.debug.internal.DebugScope; import org.graalvm.compiler.debug.DebugCloseable; +import org.graalvm.compiler.debug.DebugConfig; import org.graalvm.compiler.debug.DebugCounter; import org.graalvm.compiler.debug.DebugTimer; import org.graalvm.compiler.debug.GraalError; @@ -82,8 +85,8 @@ import org.graalvm.compiler.nodes.MergeNode; import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.PhiNode; -import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.PiNode.Placeholder; +import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp; import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StartNode; import org.graalvm.compiler.nodes.StateSplit; @@ -632,7 +635,8 @@ SnippetTemplate template = Options.UseSnippetTemplateCache.getValue(options) && args.cacheable ? templates.get(args.cacheKey) : null; if (template == null) { SnippetTemplates.increment(); - try (DebugCloseable a = SnippetTemplateCreationTime.start(); Scope s = Debug.scope("SnippetSpecialization", args.info.method)) { + DebugConfig config = DebugStubsAndSnippets.getValue(options) ? DebugScope.getConfig() : Debug.silentConfig(); + try (DebugCloseable a = SnippetTemplateCreationTime.start(); Scope s = Debug.sandbox("SnippetSpecialization", config, args.info.method)) { template = new SnippetTemplate(options, providers, snippetReflection, args); if (Options.UseSnippetTemplateCache.getValue(options) && args.cacheable) { templates.put(args.cacheKey, template); @@ -744,7 +748,7 @@ } snippetCopy.addDuplicates(snippetGraph.getNodes(), snippetGraph, snippetGraph.getNodeCount(), nodeReplacements); - Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "Before specialization"); + Debug.dump(Debug.INFO_LEVEL, snippetCopy, "Before specialization"); // Gather the template parameters parameters = new Object[parameterCount]; @@ -772,10 +776,10 @@ for (Node usage : placeholder.usages().snapshot()) { if (usage instanceof LoadIndexedNode) { LoadIndexedNode loadIndexed = (LoadIndexedNode) usage; - Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "Before replacing %s", loadIndexed); + Debug.dump(Debug.INFO_LEVEL, snippetCopy, "Before replacing %s", loadIndexed); LoadSnippetVarargParameterNode loadSnippetParameter = snippetCopy.add(new LoadSnippetVarargParameterNode(params, loadIndexed.index(), loadIndexed.stamp())); snippetCopy.replaceFixedWithFixed(loadIndexed, loadSnippetParameter); - Debug.dump(Debug.INFO_LOG_LEVEL, snippetCopy, "After replacing %s", loadIndexed); + Debug.dump(Debug.INFO_LEVEL, snippetCopy, "After replacing %s", loadIndexed); } else if (usage instanceof StoreIndexedNode) { /* * The template lowering doesn't really treat this as an array so @@ -813,11 +817,15 @@ ArrayList curSideEffectNodes = new ArrayList<>(); ArrayList curDeoptNodes = new ArrayList<>(); - ArrayList curStampNodes = new ArrayList<>(); + ArrayList curPlaceholderStampedNodes = new ArrayList<>(); for (Node node : snippetCopy.getNodes()) { - if (node instanceof ValueNode && ((ValueNode) node).stamp() == StampFactory.forNodeIntrinsic()) { - curStampNodes.add((ValueNode) node); + if (node instanceof ValueNode) { + ValueNode valueNode = (ValueNode) node; + if (valueNode.stamp() == PlaceholderStamp.singleton()) { + curPlaceholderStampedNodes.add(valueNode); + } } + if (node instanceof StateSplit) { StateSplit stateSplit = (StateSplit) node; FrameState frameState = stateSplit.stateAfter(); @@ -889,7 +897,7 @@ this.memoryAnchor = null; } } - Debug.dump(Debug.INFO_LOG_LEVEL, snippet, "SnippetTemplate after fixing memory anchoring"); + Debug.dump(Debug.INFO_LEVEL, snippet, "SnippetTemplate after fixing memory anchoring"); List returnNodes = snippet.getNodes(ReturnNode.TYPE).snapshot(); if (returnNodes.isEmpty()) { @@ -924,7 +932,7 @@ this.sideEffectNodes = curSideEffectNodes; this.deoptNodes = curDeoptNodes; - this.stampNodes = curStampNodes; + this.placeholderStampedNodes = curPlaceholderStampedNodes; nodes = new ArrayList<>(snippet.getNodeCount()); for (Node node : snippet.getNodes()) { @@ -934,7 +942,7 @@ } Debug.counter("SnippetTemplateNodeCount[%#s]", args).add(nodes.size()); - Debug.dump(Debug.INFO_LOG_LEVEL, snippet, "SnippetTemplate final state"); + Debug.dump(Debug.INFO_LEVEL, snippet, "SnippetTemplate final state"); } catch (Throwable ex) { throw Debug.handle(ex); @@ -1043,9 +1051,9 @@ private final ArrayList deoptNodes; /** - * The nodes that inherit the {@link ValueNode#stamp()} from the replacee during instantiation. + * Nodes that have a stamp originating from a {@link Placeholder}. */ - private final ArrayList stampNodes; + private final ArrayList placeholderStampedNodes; /** * The nodes to be inlined when this specialization is instantiated. @@ -1364,6 +1372,21 @@ */ @SuppressWarnings("try") public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args) { + return instantiate(metaAccess, replacee, replacer, args, true); + } + + /** + * Replaces a given fixed node with this specialized snippet. + * + * @param metaAccess + * @param replacee the node that will be replaced + * @param replacer object that replaces the usages of {@code replacee} + * @param args the arguments to be bound to the flattened positional parameters of the snippet + * @param killReplacee is true, the replacee node is deleted + * @return the map of duplicated nodes (original -> duplicate) + */ + @SuppressWarnings("try") + public UnmodifiableEconomicMap instantiate(MetaAccessProvider metaAccess, FixedNode replacee, UsageReplacer replacer, Arguments args, boolean killReplacee) { assert assertSnippetKills(replacee); try (DebugCloseable a = args.info.instantiationTimer.start(); DebugCloseable b = instantiationTimer.start()) { args.info.instantiationCounter.increment(); @@ -1375,7 +1398,7 @@ EconomicMap replacements = bind(replaceeGraph, metaAccess, args); replacements.put(entryPointNode, AbstractBeginNode.prevBegin(replacee)); UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); // Re-wire the control flow graph around the replacee FixedNode firstCFGNodeDuplicate = (FixedNode) duplicates.get(firstCFGNode); @@ -1458,10 +1481,12 @@ } } - // Remove the replacee from its graph - GraphUtil.killCFG(replacee); + if (killReplacee) { + // Remove the replacee from its graph + GraphUtil.killCFG(replacee); + } - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); return duplicates; } } @@ -1478,14 +1503,14 @@ } private void updateStamps(ValueNode replacee, UnmodifiableEconomicMap duplicates) { - for (ValueNode stampNode : stampNodes) { - Node stampDup = duplicates.get(stampNode); - if (stampDup instanceof PiNode.Placeholder) { - PiNode.Placeholder placeholder = (Placeholder) stampDup; - PiNode pi = placeholder.getReplacement(replacee.stamp()); - placeholder.replaceAndDelete(pi); + for (ValueNode node : placeholderStampedNodes) { + ValueNode dup = (ValueNode) duplicates.get(node); + Stamp replaceeStamp = replacee.stamp(); + if (node instanceof Placeholder) { + Placeholder placeholderDup = (Placeholder) dup; + placeholderDup.makeReplacement(replaceeStamp); } else { - ((ValueNode) stampDup).setStamp(replacee.stamp()); + dup.setStamp(replaceeStamp); } } for (ParameterNode paramNode : snippet.getNodes(ParameterNode.TYPE)) { @@ -1526,7 +1551,7 @@ EconomicMap replacements = bind(replaceeGraph, metaAccess, args); replacements.put(entryPointNode, tool.getCurrentGuardAnchor().asNode()); UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(nodes, snippet, snippet.getNodeCount(), replacements); - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); FixedWithNextNode lastFixedNode = tool.lastFixedNode(); assert lastFixedNode != null && lastFixedNode.isAlive() : replaceeGraph + " lastFixed=" + lastFixedNode; @@ -1550,7 +1575,7 @@ returnDuplicate.replaceAndDelete(next); } - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); } } @@ -1588,7 +1613,7 @@ } } UnmodifiableEconomicMap duplicates = replaceeGraph.addDuplicates(floatingNodes, snippet, floatingNodes.size(), replacements); - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After inlining snippet %s", snippet.method()); rewireFrameStates(replacee, duplicates); updateStamps(replacee, duplicates); @@ -1600,7 +1625,7 @@ ValueNode returnValue = (ValueNode) duplicates.get(returnNode.result()); replacer.replace(replacee, returnValue); - Debug.dump(Debug.INFO_LOG_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); + Debug.dump(Debug.DETAILED_LEVEL, replaceeGraph, "After lowering %s with %s", replacee, this); } } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Thu Apr 06 14:31:32 2017 -0700 @@ -42,6 +42,7 @@ import org.graalvm.compiler.core.common.LocationIdentity; import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.calc.UnsignedMath; +import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; @@ -76,23 +77,23 @@ import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.extended.RawLoadNode; +import org.graalvm.compiler.nodes.extended.RawStoreNode; import org.graalvm.compiler.nodes.extended.UnboxNode; -import org.graalvm.compiler.nodes.extended.RawLoadNode; import org.graalvm.compiler.nodes.extended.UnsafeMemoryLoadNode; import org.graalvm.compiler.nodes.extended.UnsafeMemoryStoreNode; -import org.graalvm.compiler.nodes.extended.RawStoreNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration; import org.graalvm.compiler.nodes.java.ClassIsAssignableFromNode; -import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode; import org.graalvm.compiler.nodes.java.DynamicNewArrayNode; import org.graalvm.compiler.nodes.java.DynamicNewInstanceNode; import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode; import org.graalvm.compiler.nodes.java.LoadFieldNode; import org.graalvm.compiler.nodes.java.RegisterFinalizerNode; +import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode; import org.graalvm.compiler.replacements.nodes.ReverseBytesNode; @@ -173,7 +174,8 @@ @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { ResolvedJavaField field = b.getMetaAccess().lookupJavaField(STRING_VALUE_FIELD); - b.addPush(JavaKind.Object, LoadFieldNode.create(b.getAssumptions(), value, field)); + b.addPush(JavaKind.Object, LoadFieldNode.create(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), + b.getOptions(), b.getAssumptions(), value, field, false, false)); return true; } }); @@ -557,8 +559,8 @@ r.register2("get" + c.getSimpleName() + "Unsafe", Node.class, long.class, new InvocationPlugin() { @Override public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode node, ValueNode offset) { - RawLoadNode value = b.add(new RawLoadNode(node, offset, JavaKind.Object, LocationIdentity.any())); - value.setStamp(StampFactory.object(TypeReference.createTrusted(b.getAssumptions(), metaAccess.lookupJavaType(c)))); + ObjectStamp stamp = StampFactory.object(TypeReference.createTrusted(b.getAssumptions(), metaAccess.lookupJavaType(c))); + RawLoadNode value = b.add(new RawLoadNode(stamp, node, offset, LocationIdentity.any(), JavaKind.Object)); b.addPush(JavaKind.Object, value); return true; } @@ -881,8 +883,8 @@ if (totalCount == 0) { b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter)); } else if (falseCount == 0 || trueCount == 0) { - boolean expected = falseCount == 0 ? true : false; - LogicNode condition = b.add(IntegerEqualsNode.create(result, b.add(ConstantNode.forBoolean(!expected)), /* constantReflection */ null)); + boolean expected = falseCount == 0; + LogicNode condition = b.addWithInputs(IntegerEqualsNode.create(result, b.add(ConstantNode.forBoolean(!expected)))); b.append(new FixedGuardNode(condition, DeoptimizationReason.UnreachedCode, DeoptimizationAction.InvalidateReprofile, true)); newResult = b.add(ConstantNode.forBoolean(expected)); } else { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -204,10 +204,7 @@ return; } VirtualArrayNode srcVirtual = (VirtualArrayNode) srcAlias; - if (destVirtual.componentType().getJavaKind() != JavaKind.Object) { - return; - } - if (srcVirtual.componentType().getJavaKind() != JavaKind.Object) { + if (destVirtual.componentType().getJavaKind() != srcVirtual.componentType().getJavaKind()) { return; } if (!checkBounds(srcPosInt, len, srcVirtual)) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MacroNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -174,7 +174,7 @@ } } InliningUtil.inline(invoke, replacementGraph, false, targetMethod); - Debug.dump(Debug.INFO_LOG_LEVEL, graph(), "After inlining replacement %s", replacementGraph); + Debug.dump(Debug.DETAILED_LEVEL, graph(), "After inlining replacement %s", replacementGraph); } else { if (isPlaceholderBci(invoke.bci())) { throw new GraalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -335,8 +335,8 @@ adder.add(new ValueAnchorNode(newGuard)); guard = newGuard; } - PiNode piNode = adder.add(new PiNode(argument, StampFactory.object(targetType), guard.asNode())); - arguments[index] = piNode; + ValueNode valueNode = adder.add(PiNode.create(argument, StampFactory.object(targetType), guard.asNode())); + arguments[index] = valueNode; } else { inst.safeDelete(); } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ReadRegisterNode.java Thu Apr 06 14:31:32 2017 -0700 @@ -26,6 +26,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -71,8 +72,8 @@ this.incoming = incoming; } - public ReadRegisterNode(Register register, boolean directUse, boolean incoming) { - super(TYPE, StampFactory.forNodeIntrinsic()); + public ReadRegisterNode(@InjectedNodeParameter Stamp stamp, Register register, boolean directUse, boolean incoming) { + super(TYPE, stamp); assert register != null; this.register = register; this.directUse = directUse; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,7 +25,10 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import javax.annotation.processing.AbstractProcessor; @@ -53,6 +56,7 @@ public class ServiceProviderProcessor extends AbstractProcessor { private final Set processed = new HashSet<>(); + private final Map serviceProviders = new HashMap<>(); @Override public SourceVersion getSupportedSourceVersion() { @@ -82,23 +86,22 @@ } catch (MirroredTypeException ex) { TypeMirror serviceInterface = ex.getTypeMirror(); if (verifyAnnotation(serviceInterface, serviceProvider)) { - String interfaceName = ex.getTypeMirror().toString(); - createProviderFile(serviceProvider, interfaceName); + if (serviceProvider.getNestingKind().isNested()) { + /* + * This is a simplifying constraint that means we don't have to process the + * qualified name to insert '$' characters at the relevant positions. + */ + String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); + processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); + } else { + serviceProviders.put(serviceProvider, ex.getTypeMirror().toString()); + } } } } } - private void createProviderFile(TypeElement serviceProvider, String interfaceName) { - if (serviceProvider.getNestingKind().isNested()) { - // This is a simplifying constraint that means we don't have to - // processed the qualified name to insert '$' characters at - // the relevant positions. - String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName()); - processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider); - return; - } - + private void writeProviderFile(TypeElement serviceProvider, String interfaceName) { String filename = "META-INF/providers/" + serviceProvider.getQualifiedName(); try { FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider); @@ -114,7 +117,7 @@ * Determines if a given exception is (most likely) caused by * Bug 367599. */ - public static boolean isBug367599(Throwable t) { + private static boolean isBug367599(Throwable t) { if (t instanceof FilerException) { for (StackTraceElement ste : t.getStackTrace()) { if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) { @@ -123,15 +126,16 @@ } } } - if (t.getCause() != null) { - return isBug367599(t.getCause()); - } - return false; + return t.getCause() != null && isBug367599(t.getCause()); } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { + for (Entry e : serviceProviders.entrySet()) { + writeProviderFile(e.getKey(), e.getValue()); + } + serviceProviders.clear(); return true; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Thu Apr 06 14:31:32 2017 -0700 @@ -124,8 +124,6 @@ Class expectedClass = expected.getClass(); Class actualClass = actual.getClass(); if (expectedClass.isArray()) { - Assert.assertTrue(message, expected != null); - Assert.assertTrue(message, actual != null); Assert.assertEquals(message, expectedClass, actual.getClass()); if (expected instanceof int[]) { Assert.assertArrayEquals(message, (int[]) expected, (int[]) actual); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java Thu Apr 06 14:31:32 2017 -0700 @@ -25,8 +25,13 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.Arrays; +import java.util.ArrayList; +import java.util.Formatter; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.graalvm.util.CollectionsUtil; /** * Utility methods for spawning a VM in a subprocess during unit tests. @@ -54,6 +59,63 @@ } /** + * Pattern for a single shell command argument that does not need to quoted. + */ + private static final Pattern SAFE_SHELL_ARG = Pattern.compile("[A-Za-z0-9@%_\\-\\+=:,\\./]+"); + + /** + * Reliably quote a string as a single shell command argument. + */ + public static String quoteShellArg(String arg) { + if (arg.isEmpty()) { + return "\"\""; + } + Matcher m = SAFE_SHELL_ARG.matcher(arg); + if (m.matches()) { + return arg; + } + // See http://stackoverflow.com/a/1250279 + return "'" + arg.replace("'", "'\"'\"'") + "'"; + } + + /** + * Formats an executed shell command followed by its output. The command is formatted such that + * it can be copy and pasted into a console for re-execution. + * + * @param command the list containing the program and its arguments + * @param outputLines the output of the command broken into lines + * @param header if non null, the returned string has a prefix of this value plus a newline + * @param trailer if non null, the returned string has a suffix of this value plus a newline + */ + public static String formatExecutedCommand(List command, List outputLines, String header, String trailer) { + Formatter msg = new Formatter(); + if (header != null) { + msg.format("%s%n", header); + } + msg.format("%s%n", CollectionsUtil.mapAndJoin(command, e -> quoteShellArg(String.valueOf(e)), " ")); + for (String line : outputLines) { + msg.format("%s%n", line); + } + if (trailer != null) { + msg.format("%s%n", trailer); + } + return msg.toString(); + } + + /** + * Returns a new copy {@code args} with debugger arguments removed. + */ + public static List withoutDebuggerArguments(List args) { + List result = new ArrayList<>(args.size()); + for (String arg : args) { + if (!(arg.equals("-Xdebug") || arg.startsWith("-Xrunjdwp:"))) { + result.add(arg); + } + } + return result; + } + + /** * Gets the command line used to start the current Java VM, including all VM arguments, but not * including the main class or any Java arguments. This can be used to spawn an identical VM, * but running different Java code. @@ -68,9 +130,28 @@ } } - public static final List JVM_OPTIONS_WITH_ONE_ARG = System.getProperty("java.specification.version").compareTo("1.9") < 0 ? // - Arrays.asList("-cp", "-classpath") : // - Arrays.asList("-cp", "-classpath", "-mp", "-modulepath", "-upgrademodulepath", "-addmods", "-m", "-limitmods"); + private static final boolean isJava8OrEarlier = System.getProperty("java.specification.version").compareTo("1.9") < 0; + + private static boolean hasArg(String optionName) { + if (optionName.equals("-cp") || optionName.equals("-classpath")) { + return true; + } + if (!isJava8OrEarlier) { + if (optionName.equals("--version") || + optionName.equals("--show-version") || + optionName.equals("--dry-run") || + optionName.equals("--disable-@files") || + optionName.equals("--dry-run") || + optionName.equals("--help") || + optionName.equals("--help-extra")) { + return false; + } + if (optionName.startsWith("--")) { + return optionName.indexOf('=') == -1; + } + } + return false; + } private static int findMainClassIndex(List commandLine) { int i = 1; // Skip the java executable @@ -79,7 +160,7 @@ String s = commandLine.get(i); if (s.charAt(0) != '-') { return i; - } else if (JVM_OPTIONS_WITH_ONE_ARG.contains(s)) { + } else if (hasArg(s)) { i += 2; } else { i++; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Thu Apr 06 14:31:32 2017 -0700 @@ -194,7 +194,7 @@ Debug.log(" ==== cfg kill effects"); effects.apply(graph, obsoleteNodes, true); } - Debug.dump(Debug.VERBOSE_LOG_LEVEL, graph, "After applying effects"); + Debug.dump(Debug.DETAILED_LEVEL, graph, "After applying effects"); assert VirtualUtil.assertNonReachable(graph, obsoleteNodes); for (Node node : obsoleteNodes) { if (node.isAlive() && node.hasNoUsages()) { diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Thu Apr 06 14:31:32 2017 -0700 @@ -100,8 +100,8 @@ closure.applyEffects(); } - if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL)) { - Debug.dump(Debug.INFO_LOG_LEVEL, graph, "%s iteration", getName()); + if (Debug.isDumpEnabled(Debug.INFO_LEVEL)) { + Debug.dump(Debug.DETAILED_LEVEL, graph, "%s iteration", getName()); } new DeadCodeEliminationPhase(Required).apply(graph); diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Thu Apr 06 14:31:32 2017 -0700 @@ -118,6 +118,7 @@ private ObjectState[] getObjectStateArrayForModification() { if (arrayRefCount.refCount > 1) { objectStates = objectStates.clone(); + arrayRefCount.refCount--; arrayRefCount = new RefCount(); } return objectStates; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Thu Apr 06 14:31:32 2017 -0700 @@ -23,7 +23,7 @@ package org.graalvm.compiler.virtual.phases.ea; import java.util.ArrayList; -import java.util.Arrays; +import java.util.BitSet; import java.util.Iterator; import java.util.List; import java.util.function.IntFunction; @@ -432,15 +432,16 @@ counter.increment(); VirtualObjectNode virtual = virtualObjects.get(object); state.materializeBefore(materializeBefore, virtual, effects); - updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue()); + assert !updateStatesForMaterialized(state, virtual, state.getObjectState(object).getMaterializedValue()) : "method must already have been called before"; return true; } else { return false; } } - public static void updateStatesForMaterialized(PartialEscapeBlockState state, VirtualObjectNode virtual, ValueNode materializedValue) { + public static boolean updateStatesForMaterialized(PartialEscapeBlockState state, VirtualObjectNode virtual, ValueNode materializedValue) { // update all existing states with the newly materialized object + boolean change = false; for (int i = 0; i < state.getStateCount(); i++) { ObjectState objState = state.getObjectStateOptional(i); if (objState != null && objState.isVirtual()) { @@ -448,10 +449,12 @@ for (int i2 = 0; i2 < entries.length; i2++) { if (entries[i2] == virtual) { state.setEntry(i, i2, materializedValue); + change = true; } } } } + return change; } @Override @@ -470,25 +473,25 @@ int length = initialState.getStateCount(); boolean change; - boolean[] ensureVirtualized = new boolean[length]; + BitSet ensureVirtualized = new BitSet(length); for (int i = 0; i < length; i++) { ObjectState state = initialState.getObjectStateOptional(i); if (state != null && state.isVirtual() && state.getEnsureVirtualized()) { - ensureVirtualized[i] = true; + ensureVirtualized.set(i); } } do { // propagate "ensureVirtualized" flag change = false; for (int i = 0; i < length; i++) { - if (!ensureVirtualized[i]) { + if (!ensureVirtualized.get(i)) { ObjectState state = initialState.getObjectStateOptional(i); if (state != null && state.isVirtual()) { for (ValueNode entry : state.getEntries()) { if (entry instanceof VirtualObjectNode) { - if (ensureVirtualized[((VirtualObjectNode) entry).getObjectId()]) { + if (ensureVirtualized.get(((VirtualObjectNode) entry).getObjectId())) { change = true; - ensureVirtualized[i] = true; + ensureVirtualized.set(i); break; } } @@ -500,7 +503,7 @@ for (int i = 0; i < length; i++) { ObjectState state = initialState.getObjectStateOptional(i); - if (state != null && state.isVirtual() && !ensureVirtualized[i]) { + if (state != null && state.isVirtual() && !ensureVirtualized.get(i)) { initialState.materializeBefore(end, virtualObjects.get(i), blockEffects.get(loopPredecessor)); } } @@ -690,7 +693,6 @@ } else { for (int object : virtualObjTemp) { - if (PartialEscapeBlockState.identicalObjectStates(states, object)) { newState.addObject(object, states[0].getObjectState(object).share()); continue; @@ -745,7 +747,7 @@ for (PhiNode phi : getPhis()) { aliases.set(phi, null); if (hasVirtualInputs.isMarked(phi) && phi instanceof ValuePhiNode) { - materialized |= processPhi((ValuePhiNode) phi, states, virtualObjTemp); + materialized |= processPhi((ValuePhiNode) phi, states); } } if (materialized) { @@ -761,31 +763,35 @@ for (int i = 1; i < states.length; i++) { length = Math.min(length, states[i].getStateCount()); } - boolean[] result = new boolean[length]; - Arrays.fill(result, true); - int count = length; - for (int i = 0; i < states.length; i++) { - PartialEscapeBlockState state = states[i]; - for (int i2 = 0; i2 < length; i2++) { - if (result[i2]) { - if (state.getObjectStateOptional(i2) == null) { - result[i2] = false; - count--; - } - } + + int count = 0; + for (int objectIndex = 0; objectIndex < length; objectIndex++) { + if (intersectObjectState(states, objectIndex)) { + count++; } } - int[] resultInts = new int[count]; + int index = 0; - for (int i = 0; i < length; i++) { - if (result[i]) { - resultInts[index++] = i; + int[] resultInts = new int[count]; + for (int objectIndex = 0; objectIndex < length; objectIndex++) { + if (intersectObjectState(states, objectIndex)) { + resultInts[index++] = objectIndex; } } assert index == count; return resultInts; } + private boolean intersectObjectState(PartialEscapeBlockState[] states, int objectIndex) { + for (int i = 0; i < states.length; i++) { + PartialEscapeBlockState state = states[i]; + if (state.getObjectStateOptional(objectIndex) == null) { + return false; + } + } + return true; + } + /** * Try to merge multiple virtual object states into a single object state. If the incoming * object states are compatible, then this method will create PhiNodes for the object's @@ -960,11 +966,9 @@ * * @param phi the PhiNode that should be processed * @param states the predecessor block states of the merge - * @param mergedVirtualObjects the set of virtual objects that exist in all incoming states, - * and therefore also exist in the merged state * @return true if materialization happened during the merge, false otherwise */ - private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState[] states, int[] mergedVirtualObjects) { + private boolean processPhi(ValuePhiNode phi, PartialEscapeBlockState[] states) { // determine how many inputs are virtual and if they're all the same virtual object int virtualInputs = 0; diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java Thu Apr 06 14:31:32 2017 -0700 @@ -115,7 +115,7 @@ } if (!success) { TTY.println(); - Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "assertNonReachable"); + Debug.forceDump(graph, "assertNonReachable"); } return success; } diff -r b9a1aa504eb5 -r 0337d0617e7b hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java --- a/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java Wed Apr 05 22:48:35 2017 +0000 +++ b/hotspot/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java Thu Apr 06 14:31:32 2017 -0700 @@ -59,7 +59,7 @@ } /** - * Creates a new map that guarantees insertion order on the key set with the the default + * Creates a new map that guarantees insertion order on the key set with the default * {@link Equivalence#DEFAULT} comparison strategy for keys. */ static EconomicMap create() { @@ -67,7 +67,7 @@ } /** - * Creates a new map that guarantees insertion order on the key set with the the default + * Creates a new map that guarantees insertion order on the key set with the default * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified * capacity. */ @@ -84,7 +84,7 @@ } /** - * Creates a new map that guarantees insertion order on the key set with the the default + * Creates a new map that guarantees insertion order on the key set with the default * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the * specified existing map. */