--- a/make/CompileToolsHotspot.gmk Mon Nov 06 14:12:37 2017 -0500
+++ b/make/CompileToolsHotspot.gmk Mon Nov 06 20:29:49 2017 -0800
@@ -67,6 +67,7 @@
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
+ $(SRC_DIR)/org.graalvm.graphio/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
@@ -125,6 +126,7 @@
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+ $(SRC_DIR)/org.graalvm.graphio/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
--- a/src/hotspot/share/aot/aotCodeHeap.cpp Mon Nov 06 14:12:37 2017 -0500
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp Mon Nov 06 20:29:49 2017 -0800
@@ -490,6 +490,8 @@
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
+ SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_generic_arraycopy", address, StubRoutines::_generic_arraycopy);
+
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_decryptBlock", address, StubRoutines::_aescrypt_decryptBlock);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_encryptAESCrypt", address, StubRoutines::_cipherBlockChaining_encryptAESCrypt);
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc.binformat/src/jdk/tools/jaotc/binformat/BinaryContainer.java Mon Nov 06 20:29:49 2017 -0800
@@ -192,6 +192,8 @@
{"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
+ {"StubRoutines::_generic_arraycopy", "_aot_stub_routines_generic_arraycopy"},
+
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/BlackholeDirectiveTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -34,6 +34,9 @@
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.ParameterNode;
import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
/**
* Tests for {@link GraalDirectives#blackhole}.
@@ -129,6 +132,11 @@
}
@Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
+ @Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);
ParameterNode arg = graph.getParameter(0);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ControlFlowAnchorDirectiveTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -46,6 +46,9 @@
import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
@@ -239,6 +242,11 @@
}
@Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
+ @Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();
for (int i = 0; i < anchors.size(); i++) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/OpaqueDirectiveTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,6 +37,9 @@
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
/**
* Tests for {@link GraalDirectives#opaque}.
@@ -128,6 +131,11 @@
}
@Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
+ @Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);
for (ReturnNode returnNode : graph.getNodes(ReturnNode.TYPE)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/Snippet.java Mon Nov 06 20:29:49 2017 -0800
@@ -36,6 +36,13 @@
public @interface Snippet {
/**
+ * A partial intrinsic exits by (effectively) calling the intrinsified method. Normally, this
+ * call must use exactly the same arguments as the call that is being intrinsified. For well
+ * known snippets that are used after frame state assignment, we want to relax this restriction.
+ */
+ boolean allowPartialIntrinsicArgumentMismatch() default false;
+
+ /**
* Denotes a snippet parameter representing 0 or more arguments that will be bound during
* snippet template instantiation. During snippet template creation, its value must be an array
* whose length specifies the number of arguments (the contents of the array are ignored) bound
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,10 +22,14 @@
*/
package org.graalvm.compiler.asm.amd64;
-import static org.graalvm.compiler.core.common.NumUtil.isByte;
-import static org.graalvm.compiler.core.common.NumUtil.isInt;
-import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
-import static org.graalvm.compiler.core.common.NumUtil.isUByte;
+import static jdk.vm.ci.amd64.AMD64.CPU;
+import static jdk.vm.ci.amd64.AMD64.XMM;
+import static jdk.vm.ci.amd64.AMD64.r12;
+import static jdk.vm.ci.amd64.AMD64.r13;
+import static jdk.vm.ci.amd64.AMD64.rbp;
+import static jdk.vm.ci.amd64.AMD64.rip;
+import static jdk.vm.ci.amd64.AMD64.rsp;
+import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
@@ -47,25 +51,24 @@
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
-import static jdk.vm.ci.amd64.AMD64.CPU;
-import static jdk.vm.ci.amd64.AMD64.XMM;
-import static jdk.vm.ci.amd64.AMD64.r12;
-import static jdk.vm.ci.amd64.AMD64.r13;
-import static jdk.vm.ci.amd64.AMD64.rbp;
-import static jdk.vm.ci.amd64.AMD64.rip;
-import static jdk.vm.ci.amd64.AMD64.rsp;
-import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
+import static org.graalvm.compiler.core.common.NumUtil.isByte;
+import static org.graalvm.compiler.core.common.NumUtil.isInt;
+import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
+import static org.graalvm.compiler.core.common.NumUtil.isUByte;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64.CPUFeature;
+import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.Register.RegisterCategory;
import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.PlatformKind;
/**
* This class implements an assembler that can encode most X86 instructions.
@@ -225,7 +228,7 @@
* The x86 operand sizes.
*/
public enum OperandSize {
- BYTE(1) {
+ BYTE(1, AMD64Kind.BYTE) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
assert imm == (byte) imm;
@@ -238,7 +241,7 @@
}
},
- WORD(2, 0x66) {
+ WORD(2, AMD64Kind.WORD, 0x66) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
assert imm == (short) imm;
@@ -251,7 +254,7 @@
}
},
- DWORD(4) {
+ DWORD(4, AMD64Kind.DWORD) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
asm.emitInt(imm);
@@ -263,7 +266,7 @@
}
},
- QWORD(8) {
+ QWORD(8, AMD64Kind.QWORD) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
asm.emitInt(imm);
@@ -275,34 +278,35 @@
}
},
- SS(4, 0xF3, true),
-
- SD(8, 0xF2, true),
-
- PS(16, true),
-
- PD(16, 0x66, true);
+ SS(4, AMD64Kind.SINGLE, 0xF3, true),
+
+ SD(8, AMD64Kind.DOUBLE, 0xF2, true),
+
+ PS(16, AMD64Kind.V128_SINGLE, true),
+
+ PD(16, AMD64Kind.V128_DOUBLE, 0x66, true);
private final int sizePrefix;
-
private final int bytes;
private final boolean xmm;
-
- OperandSize(int bytes) {
- this(bytes, 0);
+ private final AMD64Kind kind;
+
+ OperandSize(int bytes, AMD64Kind kind) {
+ this(bytes, kind, 0);
}
- OperandSize(int bytes, int sizePrefix) {
- this(bytes, sizePrefix, false);
+ OperandSize(int bytes, AMD64Kind kind, int sizePrefix) {
+ this(bytes, kind, sizePrefix, false);
}
- OperandSize(int bytes, boolean xmm) {
- this(bytes, 0, xmm);
+ OperandSize(int bytes, AMD64Kind kind, boolean xmm) {
+ this(bytes, kind, 0, xmm);
}
- OperandSize(int bytes, int sizePrefix, boolean xmm) {
+ OperandSize(int bytes, AMD64Kind kind, int sizePrefix, boolean xmm) {
this.sizePrefix = sizePrefix;
this.bytes = bytes;
+ this.kind = kind;
this.xmm = xmm;
}
@@ -314,6 +318,19 @@
return xmm;
}
+ public AMD64Kind getKind() {
+ return kind;
+ }
+
+ public static OperandSize get(PlatformKind kind) {
+ for (OperandSize operandSize : OperandSize.values()) {
+ if (operandSize.kind.equals(kind)) {
+ return operandSize;
+ }
+ }
+ throw GraalError.shouldNotReachHere("Unexpected kind: " + kind.toString());
+ }
+
/**
* Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
* as sign-extended 32-bit values.
@@ -2230,6 +2247,14 @@
emitOperandHelper(dst, src, 0);
}
+ public final void movzbl(Register dst, Register src) {
+ AMD64RMOp.MOVZXB.emit(this, OperandSize.DWORD, dst, src);
+ }
+
+ public final void movzbq(Register dst, Register src) {
+ AMD64RMOp.MOVZXB.emit(this, OperandSize.QWORD, dst, src);
+ }
+
public final void movzwl(Register dst, AMD64Address src) {
prefix(src, dst);
emitByte(0x0F);
@@ -3198,6 +3223,13 @@
emitByte(0xC0 | encode);
}
+ public final void setb(ConditionFlag cc, Register dst) {
+ int encode = prefixAndEncode(dst.encoding, true);
+ emitByte(0x0F);
+ emitByte(0x90 | cc.getValue());
+ emitByte(0xC0 | encode);
+ }
+
public final void cmovq(ConditionFlag cc, Register dst, AMD64Address src) {
prefixq(src, dst);
emitByte(0x0F);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java Mon Nov 06 20:29:49 2017 -0800
@@ -31,8 +31,8 @@
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
@@ -281,6 +281,16 @@
}
+ public final void setl(ConditionFlag cc, Register dst) {
+ setb(cc, dst);
+ movzbl(dst, dst);
+ }
+
+ public final void setq(ConditionFlag cc, Register dst) {
+ setb(cc, dst);
+ movzbq(dst, dst);
+ }
+
public final void flog(Register dest, Register value, boolean base10) {
if (base10) {
fldlg2();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test/AMD64AddressLoweringTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,126 @@
+/*
+ * 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.amd64.test;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
+import org.graalvm.compiler.core.amd64.AMD64AddressLowering;
+import org.graalvm.compiler.core.amd64.AMD64AddressNode;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.vm.ci.amd64.AMD64;
+
+public class AMD64AddressLoweringTest extends GraalCompilerTest {
+
+ private StructuredGraph graph;
+ private AMD64AddressLowering lowering;
+
+ @Before
+ public void checkAMD64() {
+ assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
+ graph = new StructuredGraph.Builder(getInitialOptions(), getDebugContext()).build();
+ lowering = new AMD64AddressLowering();
+ }
+
+ @Test
+ public void convertBaseAndIndexToDisplacement() {
+ ValueNode base = graph.unique(const64(1000));
+ ValueNode index = graph.unique(const64(10));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times1, 1010);
+ }
+
+ @Test
+ public void convertBaseToDisplacement() {
+ ValueNode constantAddress = graph.addOrUniqueWithInputs(const64(1000));
+ AddressNode result = lowering.lower(constantAddress, null);
+ assertAddress(result, null, null, Scale.Times1, 1000);
+ }
+
+ @Test
+ public void convertBaseAndShiftedIndexToDisplacement() {
+ ValueNode base = graph.addOrUniqueWithInputs(const64(1000));
+ ValueNode index = graph.addOrUniqueWithInputs(new LeftShiftNode(const64(10), const32(1)));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times2, 1020);
+ }
+
+ @Test
+ public void convertBaseAndNegatedShiftedIndexToDisplacement() {
+ ValueNode base = graph.addOrUniqueWithInputs(const64(1000));
+ ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times4, 960);
+ }
+
+ @Test
+ public void convertNegatedBaseAndNegatedShiftedIndexToDisplacement() {
+ ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(const64(1000)));
+ ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times4, -1040);
+ }
+
+ @Test
+ public void convertNegatedShiftedBaseAndNegatedIndexToDisplacement() {
+ ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
+ ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(const64(1000)));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times4, -1040);
+ }
+
+ @Test
+ public void convertTwoLevelsOfNegatedShiftedBaseAndNegatedIndexToDisplacement() {
+ ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(new NegateNode(new LeftShiftNode(const64(500), const32(1))), const32(1))));
+ ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new AddNode(new NegateNode(const64(13)), const64(3))));
+ AddressNode result = lowering.lower(base, index);
+ assertAddress(result, null, null, Scale.Times4, 2010);
+ }
+
+ private static ConstantNode const64(long value) {
+ return ConstantNode.forIntegerBits(Long.SIZE, value);
+ }
+
+ private static ConstantNode const32(long value) {
+ return ConstantNode.forIntegerBits(Integer.SIZE, value);
+ }
+
+ private static void assertAddress(AddressNode actual, ValueNode expectedBase, ValueNode expectedIndex, Scale expectedScale, int expectedDisplacement) {
+ AMD64AddressNode address = (AMD64AddressNode) actual;
+ Assert.assertEquals(expectedBase, address.getBase());
+ Assert.assertEquals(expectedIndex, address.getIndex());
+ Assert.assertEquals(expectedScale, address.getScale());
+ Assert.assertEquals(expectedDisplacement, address.getDisplacement());
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java Mon Nov 06 20:29:49 2017 -0800
@@ -23,21 +23,22 @@
package org.graalvm.compiler.core.amd64;
-import jdk.vm.ci.meta.JavaConstant;
-
+import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
+import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
+import jdk.vm.ci.meta.JavaConstant;
+
public class AMD64AddressLowering extends AddressLowering {
-
@Override
public AddressNode lower(ValueNode address) {
return lower(address, null);
@@ -46,24 +47,37 @@
@Override
public AddressNode lower(ValueNode base, ValueNode offset) {
AMD64AddressNode ret = new AMD64AddressNode(base, offset);
+ StructuredGraph graph = base.graph();
+
boolean changed;
do {
- changed = improve(base.getDebug(), ret);
+ changed = improve(graph, base.getDebug(), ret, false, false);
} while (changed);
- return base.graph().unique(ret);
+
+ return graph.unique(ret);
}
/**
- * @param debug
+ * Tries to optimize addresses so that they match the AMD64-specific addressing mode better
+ * (base + index * scale + displacement).
+ *
+ * @param graph the current graph
+ * @param debug the current debug context
+ * @param ret the address that should be optimized
+ * @param isBaseNegated determines if the address base is negated. if so, all values that are
+ * extracted from the base will be negated as well
+ * @param isIndexNegated determines if the index is negated. if so, all values that are
+ * extracted from the index will be negated as well
+ * @return true if the address was modified
*/
- protected boolean improve(DebugContext debug, AMD64AddressNode ret) {
- ValueNode newBase = improveInput(ret, ret.getBase(), 0);
+ protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode ret, boolean isBaseNegated, boolean isIndexNegated) {
+ ValueNode newBase = improveInput(ret, ret.getBase(), 0, isBaseNegated);
if (newBase != ret.getBase()) {
ret.setBase(newBase);
return true;
}
- ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2);
+ ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2, isIndexNegated);
if (newIdx != ret.getIndex()) {
ret.setIndex(newIdx);
return true;
@@ -83,55 +97,122 @@
}
if (ret.getScale() == Scale.Times1) {
- if (ret.getBase() == null || ret.getIndex() == null) {
- if (ret.getBase() instanceof AddNode) {
- AddNode add = (AddNode) ret.getBase();
- ret.setBase(add.getX());
- ret.setIndex(add.getY());
- return true;
- } else if (ret.getIndex() instanceof AddNode) {
- AddNode add = (AddNode) ret.getIndex();
- ret.setBase(add.getX());
- ret.setIndex(add.getY());
- return true;
- }
+ if (ret.getIndex() == null && ret.getBase() instanceof AddNode) {
+ AddNode add = (AddNode) ret.getBase();
+ ret.setBase(add.getX());
+ ret.setIndex(considerNegation(graph, add.getY(), isBaseNegated));
+ return true;
+ } else if (ret.getBase() == null && ret.getIndex() instanceof AddNode) {
+ AddNode add = (AddNode) ret.getIndex();
+ ret.setBase(considerNegation(graph, add.getX(), isIndexNegated));
+ ret.setIndex(add.getY());
+ return true;
}
if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) {
ValueNode tmp = ret.getBase();
- ret.setBase(ret.getIndex());
- ret.setIndex(tmp);
+ ret.setBase(considerNegation(graph, ret.getIndex(), isIndexNegated != isBaseNegated));
+ ret.setIndex(considerNegation(graph, tmp, isIndexNegated != isBaseNegated));
return true;
}
}
+ return improveNegation(graph, debug, ret, isBaseNegated, isIndexNegated);
+ }
+
+ private boolean improveNegation(StructuredGraph graph, DebugContext debug, AMD64AddressNode ret, boolean originalBaseNegated, boolean originalIndexNegated) {
+ boolean baseNegated = originalBaseNegated;
+ boolean indexNegated = originalIndexNegated;
+
+ ValueNode originalBase = ret.getBase();
+ ValueNode originalIndex = ret.getIndex();
+
+ if (ret.getBase() instanceof NegateNode) {
+ NegateNode negate = (NegateNode) ret.getBase();
+ ret.setBase(negate.getValue());
+ baseNegated = !baseNegated;
+ }
+
+ if (ret.getIndex() instanceof NegateNode) {
+ NegateNode negate = (NegateNode) ret.getIndex();
+ ret.setIndex(negate.getValue());
+ indexNegated = !indexNegated;
+ }
+
+ if (baseNegated != originalBaseNegated || indexNegated != originalIndexNegated) {
+ ValueNode base = ret.getBase();
+ ValueNode index = ret.getIndex();
+
+ boolean improved = improve(graph, debug, ret, baseNegated, indexNegated);
+ if (baseNegated != originalBaseNegated) {
+ if (base == ret.getBase()) {
+ ret.setBase(originalBase);
+ } else if (ret.getBase() != null) {
+ ret.setBase(graph.maybeAddOrUnique(NegateNode.create(ret.getBase())));
+ }
+ }
+
+ if (indexNegated != originalIndexNegated) {
+ if (index == ret.getIndex()) {
+ ret.setIndex(originalIndex);
+ } else if (ret.getIndex() != null) {
+ ret.setIndex(graph.maybeAddOrUnique(NegateNode.create(ret.getIndex())));
+ }
+ }
+ return improved;
+ } else {
+ assert ret.getBase() == originalBase && ret.getIndex() == originalIndex;
+ }
return false;
}
- private static ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) {
+ private static ValueNode considerNegation(StructuredGraph graph, ValueNode value, boolean negate) {
+ if (negate && value != null) {
+ return graph.maybeAddOrUnique(NegateNode.create(value));
+ }
+ return value;
+ }
+
+ private ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift, boolean negateExtractedDisplacement) {
if (node == null) {
return null;
}
JavaConstant c = node.asJavaConstant();
if (c != null) {
- return improveConstDisp(address, node, c, null, shift);
+ return improveConstDisp(address, node, c, null, shift, negateExtractedDisplacement);
} else {
- if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) {
- if (node instanceof ZeroExtendNode) {
- if (((ZeroExtendNode) node).getInputBits() == 32) {
- /*
- * We can just swallow a zero-extend from 32 bit to 64 bit because the upper
- * half of the register will always be zero.
- */
- return ((ZeroExtendNode) node).getValue();
+ if (node.stamp() instanceof IntegerStamp) {
+ if (node instanceof ZeroExtendNode && (((ZeroExtendNode) node).getInputBits() == 32)) {
+ /*
+ * we can't just swallow all zero-extends as we might encounter something like
+ * the following: ZeroExtend(Add(negativeValue, positiveValue)).
+ *
+ * if we swallow the zero-extend in this case and subsequently optimize the add,
+ * we might end up with a negative value that has less than 64 bits in base or
+ * index. such a value would require sign extension instead of zero-extension
+ * but the backend can only do zero-extension. if we ever want to optimize that
+ * further, we would also need to be careful about over-/underflows.
+ *
+ * furthermore, we also can't swallow zero-extends with less than 32 bits as
+ * most of these values are immediately sign-extended to 32 bit by the backend
+ * (therefore, the subsequent implicit zero-extension to 64 bit won't do what we
+ * expect).
+ */
+ ValueNode value = ((ZeroExtendNode) node).getValue();
+ if (!mightBeOptimized(value)) {
+ // if the value is not optimized further by the address lowering, then we
+ // can safely rely on the backend doing the implicitly zero-extension.
+ return value;
}
- } else if (node instanceof AddNode) {
+ }
+
+ if (node instanceof AddNode) {
AddNode add = (AddNode) node;
if (add.getX().isConstant()) {
- return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift);
+ return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift, negateExtractedDisplacement);
} else if (add.getY().isConstant()) {
- return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift);
+ return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift, negateExtractedDisplacement);
}
}
}
@@ -140,15 +221,30 @@
return node;
}
- private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) {
+ /**
+ * This method returns true for all nodes that might be optimized by the address lowering.
+ */
+ protected boolean mightBeOptimized(ValueNode value) {
+ return value instanceof AddNode || value instanceof LeftShiftNode || value instanceof NegateNode || value instanceof ZeroExtendNode;
+ }
+
+ private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift, boolean negateExtractedDisplacement) {
if (c.getJavaKind().isNumericInteger()) {
- long disp = address.getDisplacement();
- disp += c.asLong() << shift;
- if (NumUtil.isInt(disp)) {
- address.setDisplacement((int) disp);
+ long delta = c.asLong() << shift;
+ if (updateDisplacement(address, delta, negateExtractedDisplacement)) {
return other;
}
}
return original;
}
+
+ protected static boolean updateDisplacement(AMD64AddressNode address, long displacementDelta, boolean negateDelta) {
+ long sign = negateDelta ? -1 : 1;
+ long disp = address.getDisplacement() + displacementDelta * sign;
+ if (NumUtil.isInt(disp)) {
+ address.setDisplacement((int) disp);
+ return true;
+ }
+ return false;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java Mon Nov 06 20:29:49 2017 -0800
@@ -33,15 +33,17 @@
import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
+import static org.graalvm.compiler.lir.LIRValueUtil.isIntConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
-import org.graalvm.compiler.core.common.NumUtil;
+import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
@@ -58,13 +60,17 @@
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
+import org.graalvm.compiler.lir.amd64.AMD64Binary;
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
import org.graalvm.compiler.lir.amd64.AMD64ByteSwapOp;
import org.graalvm.compiler.lir.amd64.AMD64Call;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondMoveOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondSetOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatBranchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondMoveOp;
+import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondSetOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
@@ -257,8 +263,7 @@
@Override
public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
- boolean mirrored = emitCompare(cmpKind, left, right);
- Condition finalCondition = mirrored ? cond.mirror() : cond;
+ Condition finalCondition = emitCompare(cmpKind, left, right, cond);
if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
} else {
@@ -290,14 +295,60 @@
@Override
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
- boolean mirrored = emitCompare(cmpKind, left, right);
- Condition finalCondition = mirrored ? cond.mirror() : cond;
+ boolean isFloatComparison = cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE;
- Variable result = newVariable(trueValue.getValueKind());
- if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
- append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
+ Condition finalCondition = cond;
+ Value finalTrueValue = trueValue;
+ Value finalFalseValue = falseValue;
+ if (isFloatComparison) {
+ // eliminate the parity check in case of a float comparison
+ Value finalLeft = left;
+ Value finalRight = right;
+ if (unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition)) {
+ if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.mirror())) {
+ finalCondition = finalCondition.mirror();
+ finalLeft = right;
+ finalRight = left;
+ } else if (finalCondition != Condition.EQ && finalCondition != Condition.NE) {
+ // negating EQ and NE does not make any sense as we would need to negate
+ // unorderedIsTrue as well (otherwise, we would no longer fulfill the Java
+ // NaN semantics)
+ assert unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate());
+ finalCondition = finalCondition.negate();
+ finalTrueValue = falseValue;
+ finalFalseValue = trueValue;
+ }
+ }
+ emitRawCompare(cmpKind, finalLeft, finalRight);
} else {
- append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
+ finalCondition = emitCompare(cmpKind, left, right, cond);
+ }
+
+ boolean isParityCheckNecessary = isFloatComparison && unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition);
+ Variable result = newVariable(finalTrueValue.getValueKind());
+ if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 1) && isIntConstant(finalFalseValue, 0)) {
+ if (isFloatComparison) {
+ append(new FloatCondSetOp(result, finalCondition));
+ } else {
+ append(new CondSetOp(result, finalCondition));
+ }
+ } else if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 0) && isIntConstant(finalFalseValue, 1)) {
+ if (isFloatComparison) {
+ if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate())) {
+ append(new FloatCondSetOp(result, finalCondition.negate()));
+ } else {
+ append(new FloatCondSetOp(result, finalCondition));
+ Variable negatedResult = newVariable(result.getValueKind());
+ append(new AMD64Binary.ConstOp(AMD64BinaryArithmetic.XOR, OperandSize.get(result.getPlatformKind()), negatedResult, result, 1));
+ result = negatedResult;
+ }
+ } else {
+ append(new CondSetOp(result, finalCondition.negate()));
+ }
+ } else if (isFloatComparison) {
+ append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(finalTrueValue), load(finalFalseValue)));
+ } else {
+ append(new CondMoveOp(result, finalCondition, load(finalTrueValue), loadNonConst(finalFalseValue)));
}
return result;
}
@@ -394,23 +445,21 @@
*
* @param a the left operand of the comparison
* @param b the right operand of the comparison
+ * @param cond the condition of the comparison
* @return true if the left and right operands were switched, false otherwise
*/
- private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
- Variable left;
- Value right;
- boolean mirrored;
+ private Condition emitCompare(PlatformKind cmpKind, Value a, Value b, Condition cond) {
if (LIRValueUtil.isVariable(b)) {
- left = load(b);
- right = loadNonConst(a);
- mirrored = true;
+ emitRawCompare(cmpKind, b, a);
+ return cond.mirror();
} else {
- left = load(a);
- right = loadNonConst(b);
- mirrored = false;
+ emitRawCompare(cmpKind, a, b);
+ return cond;
}
- ((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, left, right);
- return mirrored;
+ }
+
+ private void emitRawCompare(PlatformKind cmpKind, Value left, Value right) {
+ ((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, load(left), loadNonConst(right));
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRKindTool.java Mon Nov 06 20:29:49 2017 -0800
@@ -28,7 +28,7 @@
import jdk.vm.ci.amd64.AMD64Kind;
-public class AMD64LIRKindTool implements LIRKindTool {
+public abstract class AMD64LIRKindTool implements LIRKindTool {
@Override
public LIRKind getIntegerKind(int bits) {
@@ -67,12 +67,8 @@
}
@Override
- public LIRKind getNarrowOopKind() {
- return LIRKind.reference(AMD64Kind.DWORD);
- }
+ public abstract LIRKind getNarrowOopKind();
@Override
- public LIRKind getNarrowPointerKind() {
- return LIRKind.value(AMD64Kind.DWORD);
- }
+ public abstract LIRKind getNarrowPointerKind();
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompressEncoding.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/CompressEncoding.java Mon Nov 06 20:29:49 2017 -0800
@@ -34,14 +34,6 @@
this.shift = shift;
}
- public int compress(long ptr) {
- if (ptr == 0L) {
- return 0;
- } else {
- return (int) ((ptr - base) >>> shift);
- }
- }
-
public boolean hasBase() {
return base != 0;
}
@@ -58,14 +50,6 @@
return shift;
}
- public long uncompress(int ptr) {
- if (ptr == 0) {
- return 0L;
- } else {
- return ((ptr & 0xFFFFFFFFL) << shift) + base;
- }
- }
-
@Override
public String toString() {
return "base: " + base + " shift: " + shift;
@@ -85,8 +69,7 @@
if (obj instanceof CompressEncoding) {
CompressEncoding other = (CompressEncoding) obj;
return base == other.base && shift == other.shift;
- } else {
- return false;
}
+ return false;
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/FloatConvert.java Mon Nov 06 20:29:49 2017 -0800
@@ -25,21 +25,23 @@
import org.graalvm.compiler.debug.GraalError;
public enum FloatConvert {
- F2I(FloatConvertCategory.FloatingPointToInteger),
- D2I(FloatConvertCategory.FloatingPointToInteger),
- F2L(FloatConvertCategory.FloatingPointToInteger),
- D2L(FloatConvertCategory.FloatingPointToInteger),
- I2F(FloatConvertCategory.IntegerToFloatingPoint),
- L2F(FloatConvertCategory.IntegerToFloatingPoint),
- D2F(FloatConvertCategory.FloatingPointToFloatingPoint),
- I2D(FloatConvertCategory.IntegerToFloatingPoint),
- L2D(FloatConvertCategory.IntegerToFloatingPoint),
- F2D(FloatConvertCategory.FloatingPointToFloatingPoint);
+ F2I(FloatConvertCategory.FloatingPointToInteger, 32),
+ D2I(FloatConvertCategory.FloatingPointToInteger, 64),
+ F2L(FloatConvertCategory.FloatingPointToInteger, 32),
+ D2L(FloatConvertCategory.FloatingPointToInteger, 64),
+ I2F(FloatConvertCategory.IntegerToFloatingPoint, 32),
+ L2F(FloatConvertCategory.IntegerToFloatingPoint, 64),
+ D2F(FloatConvertCategory.FloatingPointToFloatingPoint, 64),
+ I2D(FloatConvertCategory.IntegerToFloatingPoint, 32),
+ L2D(FloatConvertCategory.IntegerToFloatingPoint, 64),
+ F2D(FloatConvertCategory.FloatingPointToFloatingPoint, 32);
- private FloatConvertCategory category;
+ private final FloatConvertCategory category;
+ private final int inputBits;
- FloatConvert(FloatConvertCategory category) {
+ FloatConvert(FloatConvertCategory category, int inputBits) {
this.category = category;
+ this.inputBits = inputBits;
}
public FloatConvertCategory getCategory() {
@@ -72,4 +74,8 @@
throw GraalError.shouldNotReachHere();
}
}
+
+ public int getInputBits() {
+ return inputBits;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/Loop.java Mon Nov 06 20:29:49 2017 -0800
@@ -41,7 +41,6 @@
this.parent = parent;
if (parent != null) {
this.depth = parent.getDepth() + 1;
- parent.getChildren().add(this);
} else {
this.depth = 1;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java Mon Nov 06 20:29:49 2017 -0800
@@ -96,6 +96,22 @@
}
}
+ public BinaryOp<?>[] getBinaryOps() {
+ return new BinaryOp<?>[]{add, sub, mul, mulHigh, umulHigh, div, rem, and, or, xor};
+ }
+
+ public UnaryOp<?>[] getUnaryOps() {
+ return new UnaryOp<?>[]{neg, not, abs, sqrt};
+ }
+
+ public ShiftOp<?>[] getShiftOps() {
+ return new ShiftOp<?>[]{shl, shr, ushr};
+ }
+
+ public IntegerConvertOp<?>[] getIntegerConvertOps() {
+ return new IntegerConvertOp<?>[]{zeroExtend, signExtend, narrow};
+ }
+
public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
public interface ArithmeticOpWrapper {
@@ -562,7 +578,10 @@
}
/**
- * Apply the operation to two {@linkplain Constant Constants}.
+ * Applies this operation to {@code a} and {@code b}.
+ *
+ * @return the result of applying this operation or {@code null} if applying it would raise
+ * an exception (e.g., {@link ArithmeticException} for dividing by 0)
*/
public abstract Constant foldConstant(Constant a, Constant b);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/FloatStamp.java Mon Nov 06 20:29:49 2017 -0800
@@ -291,7 +291,7 @@
@Override
public JavaConstant asConstant() {
- if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
+ if (isConstant()) {
switch (getBits()) {
case 32:
return JavaConstant.forFloat((float) lowerBound);
@@ -302,6 +302,68 @@
return null;
}
+ private boolean isConstant() {
+ /*
+ * There are many forms of NaNs and any operations on them can silently convert them into
+ * the canonical NaN.
+ */
+ return (Double.compare(lowerBound, upperBound) == 0 && nonNaN);
+ }
+
+ private static FloatStamp stampForConstant(Constant constant) {
+ FloatStamp result;
+ PrimitiveConstant value = (PrimitiveConstant) constant;
+ switch (value.getJavaKind()) {
+ case Float:
+ if (Float.isNaN(value.asFloat())) {
+ result = new FloatStamp(32, Double.NaN, Double.NaN, false);
+ } else {
+ result = new FloatStamp(32, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
+ }
+ break;
+ case Double:
+ if (Double.isNaN(value.asDouble())) {
+ result = new FloatStamp(64, Double.NaN, Double.NaN, false);
+ } else {
+ result = new FloatStamp(64, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
+ }
+ break;
+ default:
+ throw GraalError.shouldNotReachHere();
+ }
+ if (result.isConstant()) {
+ return result;
+ }
+ return null;
+ }
+
+ private static Stamp maybeFoldConstant(UnaryOp<?> op, FloatStamp stamp) {
+ if (stamp.isConstant()) {
+ JavaConstant constant = stamp.asConstant();
+ Constant folded = op.foldConstant(constant);
+ if (folded != null) {
+ return FloatStamp.stampForConstant(folded);
+ }
+ }
+ return null;
+ }
+
+ private static Stamp maybeFoldConstant(BinaryOp<?> op, FloatStamp stamp1, FloatStamp stamp2) {
+ if (stamp1.isConstant() && stamp2.isConstant()) {
+ JavaConstant constant1 = stamp1.asConstant();
+ JavaConstant constant2 = stamp2.asConstant();
+ Constant folded = op.foldConstant(constant1, constant2);
+ if (folded != null) {
+ FloatStamp stamp = stampForConstant(folded);
+ if (stamp != null && stamp.isConstant()) {
+ assert stamp.asConstant().equals(folded);
+ return stamp;
+ }
+ }
+ }
+ return null;
+ }
+
public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
new UnaryOp.Neg() {
@@ -322,8 +384,13 @@
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
+ Stamp folded = maybeFoldConstant(this, stamp);
+ if (folded != null) {
+ return folded;
+ }
return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
}
+
},
new BinaryOp.Add(false, true) {
@@ -344,8 +411,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
- // TODO
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -381,8 +453,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
- // TODO
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -418,9 +495,14 @@
}
@Override
- public Stamp foldStamp(Stamp a, Stamp b) {
- // TODO
- return a.unrestricted();
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
+ return stamp1.unrestricted();
}
@Override
@@ -450,17 +532,24 @@
assert a.getJavaKind() == b.getJavaKind();
switch (a.getJavaKind()) {
case Float:
- return JavaConstant.forFloat(a.asFloat() / b.asFloat());
+ float floatDivisor = b.asFloat();
+ return (floatDivisor == 0) ? null : JavaConstant.forFloat(a.asFloat() / floatDivisor);
case Double:
- return JavaConstant.forDouble(a.asDouble() / b.asDouble());
+ double doubleDivisor = b.asDouble();
+ return (doubleDivisor == 0) ? null : JavaConstant.forDouble(a.asDouble() / doubleDivisor);
default:
throw GraalError.shouldNotReachHere();
}
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
- // TODO
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -496,8 +585,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
- // TODO
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
},
@@ -521,6 +615,17 @@
@Override
public Stamp foldStamp(Stamp s) {
+ FloatStamp stamp = (FloatStamp) s;
+ JavaConstant constant = stamp.asConstant();
+ if (constant != null) {
+ Constant folded = foldConstant(constant);
+ if (folded != null) {
+ FloatStamp result = stampForConstant(folded);
+ if (result != null && result.isConstant()) {
+ return result;
+ }
+ }
+ }
return s.unrestricted();
}
},
@@ -547,7 +652,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -576,7 +687,9 @@
case Float:
int fa = Float.floatToRawIntBits(a.asFloat());
int fb = Float.floatToRawIntBits(b.asFloat());
- return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb));
+ float floatOr = Float.intBitsToFloat(fa | fb);
+ assert (fa | fb) == Float.floatToRawIntBits((floatOr));
+ return JavaConstant.forFloat(floatOr);
case Double:
long da = Double.doubleToRawLongBits(a.asDouble());
long db = Double.doubleToRawLongBits(b.asDouble());
@@ -587,7 +700,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -627,7 +746,13 @@
}
@Override
- public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
+ public Stamp foldStamp(Stamp s1, Stamp s2) {
+ FloatStamp stamp1 = (FloatStamp) s1;
+ FloatStamp stamp2 = (FloatStamp) s2;
+ Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
+ if (folded != null) {
+ return folded;
+ }
return stamp1.unrestricted();
}
@@ -665,6 +790,10 @@
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
+ Stamp folded = maybeFoldConstant(this, stamp);
+ if (folded != null) {
+ return folded;
+ }
if (stamp.isNaN()) {
return stamp;
}
@@ -689,6 +818,11 @@
@Override
public Stamp foldStamp(Stamp s) {
+ FloatStamp stamp = (FloatStamp) s;
+ Stamp folded = maybeFoldConstant(this, stamp);
+ if (folded != null) {
+ return folded;
+ }
return s.unrestricted();
}
},
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Mon Nov 06 20:29:49 2017 -0800
@@ -597,6 +597,10 @@
public Stamp foldStamp(Stamp s) {
IntegerStamp stamp = (IntegerStamp) s;
int bits = stamp.getBits();
+ if (stamp.lowerBound == stamp.upperBound) {
+ long value = CodeUtil.convert(-stamp.lowerBound(), stamp.getBits(), false);
+ return StampFactory.forInteger(stamp.getBits(), value, value);
+ }
if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
// TODO(ls) check if the mask calculation is correct...
return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
@@ -624,6 +628,11 @@
int bits = a.getBits();
assert bits == b.getBits();
+ if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound) {
+ long value = CodeUtil.convert(a.lowerBound() + b.lowerBound(), a.getBits(), false);
+ return StampFactory.forInteger(a.getBits(), value, value);
+ }
+
if (a.isUnrestricted()) {
return a;
} else if (b.isUnrestricted()) {
@@ -711,6 +720,12 @@
int bits = a.getBits();
assert bits == b.getBits();
+
+ if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound) {
+ long value = CodeUtil.convert(a.lowerBound() * b.lowerBound(), a.getBits(), false);
+ return StampFactory.forInteger(a.getBits(), value, value);
+ }
+
// if a==0 or b==0 result of a*b is always 0
if (a.upMask() == 0) {
return a;
@@ -791,7 +806,7 @@
long maxPosB = b.upperBound();
// multiplication has shift semantics
- long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
+ long newUpMask = ~CodeUtil.mask(Math.min(64, Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask))) & CodeUtil.mask(bits);
if (a.canBePositive()) {
if (b.canBePositive()) {
@@ -1023,6 +1038,9 @@
PrimitiveConstant a = (PrimitiveConstant) const1;
PrimitiveConstant b = (PrimitiveConstant) const2;
assert a.getJavaKind() == b.getJavaKind();
+ if (b.asLong() == 0) {
+ return null;
+ }
return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() / b.asLong());
}
@@ -1031,9 +1049,12 @@
IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits();
- if (b.isStrictlyPositive()) {
- long newLowerBound = a.lowerBound() / b.upperBound();
- long newUpperBound = a.upperBound() / b.lowerBound();
+ if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound && b.lowerBound != 0) {
+ long value = CodeUtil.convert(a.lowerBound() / b.lowerBound(), a.getBits(), false);
+ return StampFactory.forInteger(a.getBits(), value, value);
+ } else if (b.isStrictlyPositive()) {
+ long newLowerBound = a.lowerBound() < 0 ? a.lowerBound() / b.lowerBound() : a.lowerBound() / b.upperBound();
+ long newUpperBound = a.upperBound() < 0 ? a.upperBound() / b.upperBound() : a.upperBound() / b.lowerBound();
return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
} else {
return a.unrestricted();
@@ -1054,6 +1075,9 @@
PrimitiveConstant a = (PrimitiveConstant) const1;
PrimitiveConstant b = (PrimitiveConstant) const2;
assert a.getJavaKind() == b.getJavaKind();
+ if (b.asLong() == 0) {
+ return null;
+ }
return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() % b.asLong());
}
@@ -1062,6 +1086,12 @@
IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits();
+
+ if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound && b.lowerBound != 0) {
+ long value = CodeUtil.convert(a.lowerBound() % b.lowerBound(), a.getBits(), false);
+ return StampFactory.forInteger(a.getBits(), value, value);
+ }
+
// zero is always possible
long newLowerBound = Math.min(a.lowerBound(), 0);
long newUpperBound = Math.max(a.upperBound(), 0);
@@ -1364,6 +1394,10 @@
public Stamp foldStamp(Stamp input) {
IntegerStamp stamp = (IntegerStamp) input;
int bits = stamp.getBits();
+ if (stamp.lowerBound == stamp.upperBound) {
+ long value = CodeUtil.convert(Math.abs(stamp.lowerBound()), stamp.getBits(), false);
+ return StampFactory.forInteger(stamp.getBits(), value, value);
+ }
if (stamp.lowerBound() == CodeUtil.minValue(bits)) {
return input.unrestricted();
} else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java Mon Nov 06 20:29:49 2017 -0800
@@ -49,8 +49,8 @@
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
@@ -73,6 +73,8 @@
import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
import org.graalvm.compiler.phases.verify.VerifyCallerSensitiveMethods;
import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
+import org.graalvm.compiler.phases.verify.VerifyGetOptionsUsage;
+import org.graalvm.compiler.phases.verify.VerifyGraphAddUsage;
import org.graalvm.compiler.phases.verify.VerifyInstanceOfUsage;
import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
@@ -381,6 +383,8 @@
new VerifyUpdateUsages().apply(graph, context);
new VerifyBailoutUsage().apply(graph, context);
new VerifyInstanceOfUsage().apply(graph, context);
+ new VerifyGraphAddUsage().apply(graph, context);
+ new VerifyGetOptionsUsage().apply(graph, context);
if (graph.method().isBridge()) {
BridgeMethodUtils.getBridgedMethod(graph.method());
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest14.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.memory.FloatingReadNode;
+import org.graalvm.compiler.nodes.memory.ReadNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.DeoptimizationReason;
+
+/**
+ * Check that multiple bounds checks are correctly grouped together.
+ */
+public class ConditionalEliminationTest14 extends ConditionalEliminationTestBase {
+
+ public static void test1Snippet(Object[] args) {
+ Object a5 = args[5];
+ Object a7 = args[7];
+ Object a6 = args[6];
+
+ /*
+ * The order of the conditions matters: The scheduler processes the floating reads for the
+ * array loads in the order of the conditions here, and we want the index 7 access to be
+ * processed before the index 6 access.
+ */
+ if (a5 != null && a7 != null && a6 != null) {
+ sink1 = 1;
+ }
+ sink0 = 0;
+ }
+
+ @Test
+ public void test1() {
+ StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+ PhaseContext context = new PhaseContext(getProviders());
+
+ /* Convert the LoadIndexNode to ReadNode with floating guards. */
+ new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+ /* Convert the ReadNode to FloatingReadNode. */
+ new FloatingReadPhase().apply(graph);
+ /* Apply the phase that we want to test. */
+ new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+
+ Assert.assertEquals("All guards must be floating", 0, graph.getNodes(FixedGuardNode.TYPE).count());
+ Assert.assertEquals("All array accesses must have been lowered", 0, graph.getNodes().filter(LoadIndexedNode.class).count());
+ Assert.assertEquals("All reads must be floating", 0, graph.getNodes().filter(ReadNode.class).count());
+ Assert.assertEquals("Must have floating reads (3 array accesses, 1 array length)", 4, graph.getNodes().filter(FloatingReadNode.class).count());
+
+ NodeIterable<GuardNode> boundsChecks = graph.getNodes(GuardNode.TYPE).filter(n -> ((GuardNode) n).getReason() == DeoptimizationReason.BoundsCheckException);
+ Assert.assertEquals("Must have only 1 bounds check remaining", 1, boundsChecks.count());
+ LogicNode condition = boundsChecks.first().getCondition();
+ Assert.assertTrue("Bounds check must check for array length 8", condition instanceof IntegerBelowNode && ((IntegerBelowNode) condition).getY().valueEquals(ConstantNode.forInt(8)));
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java Mon Nov 06 20:29:49 2017 -0800
@@ -27,12 +27,15 @@
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Assert;
@@ -45,6 +48,15 @@
protected static int sink1;
protected static int sink2;
+ /**
+ * These tests assume all code paths in called routines are reachable so disable removal of dead
+ * code based on method profiles.
+ */
+ @Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
protected void testConditionalElimination(String snippet, String referenceSnippet) {
testConditionalElimination(snippet, referenceSnippet, false, false);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,111 @@
+/*
+ * 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 java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.graalvm.compiler.debug.DebugOptions;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.util.EconomicMap;
+import org.junit.Test;
+
+/**
+ * Check that setting the dump path results in files ending up in the right directory with matching
+ * names.
+ */
+public class DumpPathTest extends GraalCompilerTest {
+
+ public static Object snippet() {
+ return new String("snippet");
+ }
+
+ @Test
+ public void testDump() throws IOException {
+ Path dumpDirectoryPath = Files.createTempDirectory("DumpPathTest");
+ String[] extensions = new String[]{".cfg", ".bgv", ".graph-strings"};
+ EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
+ overrides.put(DebugOptions.DumpPath, dumpDirectoryPath.toString());
+ overrides.put(DebugOptions.PrintGraphFile, true);
+ overrides.put(DebugOptions.PrintCanonicalGraphStrings, true);
+ overrides.put(DebugOptions.Dump, "*");
+
+ // Generate dump files.
+ test(new OptionValues(getInitialOptions(), overrides), "snippet");
+ // Check that Ideal files got created, in the right place.
+ checkForFiles(dumpDirectoryPath, extensions);
+
+ // Clean up the generated files.
+ scrubDirectory(dumpDirectoryPath);
+ }
+
+ /**
+ * Check that the given directory contains file or directory names with all the given
+ * extensions.
+ */
+ private static void checkForFiles(Path directoryPath, String[] extensions) throws IOException {
+ String[] paths = new String[extensions.length];
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
+ for (Path filePath : stream) {
+ String fileName = filePath.getFileName().toString();
+ for (int i = 0; i < extensions.length; i++) {
+ String extension = extensions[i];
+ if (fileName.endsWith(extensions[i])) {
+ assertTrue(paths[i] == null, "multiple files found for %s in %s", extension, directoryPath);
+ paths[i] = fileName.replace(extensions[i], "");
+ }
+ }
+ }
+ }
+ for (int i = 0; i < paths.length; i++) {
+ assertTrue(paths[i] != null, "missing file for extension %s in %s", extensions[i], directoryPath);
+ }
+ // Ensure that all file names are the same.
+ for (int i = 1; i < paths.length; i++) {
+ assertTrue(paths[0].equals(paths[i]), paths[0] + " != " + paths[i]);
+ }
+ }
+
+ /**
+ * Remove the temporary directory.
+ */
+ private static void scrubDirectory(Path directoryPath) {
+ try {
+ try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
+ for (Path filePath : stream) {
+ if (Files.isRegularFile(filePath)) {
+ Files.delete(filePath);
+ } else if (Files.isDirectory(filePath)) {
+ scrubDirectory(filePath);
+ }
+ }
+ }
+ Files.delete(directoryPath);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/FinalizableSubclassTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -72,7 +72,7 @@
Assert.assertTrue(constructors.length == 1);
final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]);
OptionValues options = getInitialOptions();
- StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options), allowAssumptions).method(javaMethod).build();
+ StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), allowAssumptions).method(javaMethod).build();
GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins());
new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -389,7 +389,7 @@
* {@link DebugDumpHandler}s closed in {@link #afterTest()}.
*/
protected DebugContext getDebugContext() {
- return getDebugContext(getInitialOptions());
+ return getDebugContext(getInitialOptions(), null, null);
}
@Override
@@ -862,7 +862,7 @@
Result actual = executeActual(options, method, receiver, args);
profile = method.getProfilingInfo(); // profile can change after execution
for (DeoptimizationReason reason : shouldNotDeopt) {
- Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
+ Assert.assertEquals("wrong number of deopt counts for " + reason, (int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
}
return actual;
}
@@ -1216,15 +1216,15 @@
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
OptionValues options = getInitialOptions();
- return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(getCompilationId(method));
+ return new Builder(options, getDebugContext(options, null, method), allowAssumptions).method(method).compilationId(getCompilationId(method));
}
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId, OptionValues options) {
- return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(compilationId);
+ return new Builder(options, getDebugContext(options, compilationId.toString(CompilationIdentifier.Verbosity.ID), method), allowAssumptions).method(method).compilationId(compilationId);
}
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, OptionValues options) {
- return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(getCompilationId(method));
+ return new Builder(options, getDebugContext(options, null, method), allowAssumptions).method(method).compilationId(getCompilationId(method));
}
protected PhaseSuite<HighTierContext> getDebugGraphBuilderSuite() {
@@ -1234,6 +1234,7 @@
@SuppressWarnings("try")
protected StructuredGraph parse(StructuredGraph.Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
ResolvedJavaMethod javaMethod = builder.getMethod();
+ builder.speculationLog(getSpeculationLog());
if (builder.getCancellable() == null) {
builder.cancellable(getCancellable(javaMethod));
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalDebugHandlersFactoryTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalDebugHandlersFactoryTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -31,8 +31,12 @@
import java.nio.file.Paths;
import java.util.Comparator;
-import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
+import org.graalvm.compiler.debug.DebugOptions;
+import org.graalvm.compiler.debug.PathUtilities;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.test.AddExports;
+import org.junit.Assume;
import org.junit.Test;
@AddExports("jdk.internal.vm.compiler/org.graalvm.compiler.printer")
@@ -40,23 +44,28 @@
@Test
public void createUniqueTest() throws Exception {
- Field maxFileNameLengthField = GraalDebugHandlersFactory.class.getDeclaredField("MAX_FILE_NAME_LENGTH");
- maxFileNameLengthField.setAccessible(true);
+ Field maxFileNameLengthField = PathUtilities.class.getDeclaredField("MAX_FILE_NAME_LENGTH");
+ try {
+ maxFileNameLengthField.setAccessible(true);
+ } catch (RuntimeException ex) {
+ Assume.assumeFalse("If InaccessibleObjectException is thrown, skip the test, we are on JDK9", ex.getClass().getSimpleName().equals("InaccessibleObjectException"));
+ }
int maxFileNameLength = maxFileNameLengthField.getInt(null);
- Method createUniqueMethod = GraalDebugHandlersFactory.class.getDeclaredMethod("createUnique", Path.class, String.class, String.class, String.class, boolean.class);
+ Method createUniqueMethod = PathUtilities.class.getDeclaredMethod("createUnique", OptionValues.class, OptionKey.class, String.class, String.class, String.class, boolean.class);
createUniqueMethod.setAccessible(true);
Path tmpDir = Files.createTempDirectory(Paths.get("."), "createUniqueTest");
+ OptionValues options = new OptionValues(OptionValues.asMap(DebugOptions.DumpPath, tmpDir.toString()));
try {
for (boolean createDirectory : new boolean[]{true, false}) {
for (String ext : new String[]{"", ".bgv", ".graph-strings"}) {
for (int i = 0; i < maxFileNameLength + 5; i++) {
String id = new String(new char[i]).replace('\0', 'i');
String label = "";
- createUniqueMethod.invoke(null, tmpDir, id, label, ext, createDirectory);
+ createUniqueMethod.invoke(null, options, null, id, label, ext, createDirectory);
id = "";
label = new String(new char[i]).replace('\0', 'l');
- createUniqueMethod.invoke(null, tmpDir, id, label, ext, createDirectory);
+ createUniqueMethod.invoke(null, options, null, id, label, ext, createDirectory);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -144,6 +144,11 @@
public void test01() {
Super inheritsHC = new Super();
Person overridesHC = new Person(0);
+
+ // Ensure the profile for getSuperAge includes both receiver types
+ getSuperAge(inheritsHC);
+ getSuperAge(overridesHC);
+
test("getSuperAge", inheritsHC);
test("getSuperAge", overridesHC);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/HashCodeTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.core.test;
+import java.util.HashMap;
+
import org.graalvm.compiler.core.phases.HighTier;
import org.graalvm.compiler.core.phases.MidTier;
import org.graalvm.compiler.nodes.InvokeNode;
@@ -139,6 +141,10 @@
public void test08() {
initialize(Appendable.class);
checkForGuardedIntrinsicPattern("hashCodeInterface");
+
+ // Ensure the profile for the dispatch in hashCodeSnippet01
+ // has a receiver type that does not select Object.hashCode intrinsic
+ hashCodeSnippet01(new HashMap<>());
checkForGuardedIntrinsicPattern("hashCodeSnippet01");
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MarkUnsafeAccessTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -25,6 +25,7 @@
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;
+import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
@@ -33,22 +34,20 @@
import java.nio.file.Files;
import java.nio.file.Path;
-import jdk.vm.ci.code.InstalledCode;
-import jdk.vm.ci.code.InvalidInstalledCodeException;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Test;
-
-import sun.misc.Unsafe;
-
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.inlining.InliningPhase;
import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.InvalidInstalledCodeException;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import sun.misc.Unsafe;
public class MarkUnsafeAccessTest extends GraalCompilerTest {
@@ -170,7 +169,9 @@
try {
mbb.position(BLOCK_SIZE);
getter.get(mbb);
- System.currentTimeMillis(); // materialize async exception
+
+ // Make a call that goes into native code to materialize async exception
+ new File("").exists();
} catch (InternalError e) {
return;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/MergeCanonicalizerTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -26,12 +26,23 @@
import org.graalvm.compiler.nodes.ReturnNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Test;
public class MergeCanonicalizerTest extends GraalCompilerTest {
+ /**
+ * These tests assume all code paths are reachable so disable profile based dead code removal.
+ */
+ @Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
public static int staticField;
private int field;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ProfilingInfoTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -24,15 +24,17 @@
import java.io.Serializable;
+import org.graalvm.compiler.test.SubprocessUtil;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.TriState;
-import org.junit.Assert;
-import org.junit.Test;
-
/**
* Tests profiling information provided by the runtime.
* <p>
@@ -40,7 +42,7 @@
* information may be gathered for any given method. For example, HotSpot's advanced compilation
* policy can decide to only gather partial profiles in a first level compilation (see
* AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this,
- * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only set's
+ * occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only sets
* the null_seen bit when doing full profiling.
*/
public class ProfilingInfoTest extends GraalCompilerTest {
@@ -182,6 +184,14 @@
Assert.assertNull(typeProfile);
}
+ public ProfilingInfoTest() {
+ // These tests are explicitly testing the profiling behavior of the
+ // interpreter. C1-based profiling differs slightly and when -Xcomp
+ // is present, profiles will be created by C1 compiled code, not the
+ // interpreter.
+ Assume.assumeTrue(!SubprocessUtil.getVMCommandLine().contains("-Xcomp"));
+ }
+
@Test
public void testExceptionSeen() {
// NullPointerException
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SubWordReturnTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,143 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class SubWordReturnTest extends GraalCompilerTest {
+
+ private final JavaKind kind;
+ private final int value;
+
+ private final String generatedClassName;
+ private final String generatedClassNameInternal;
+
+ private final String testMethodName;
+
+ /**
+ * The {@link AsmLoader} generates a class looking like this for the types byte, short, int and
+ * char.
+ */
+ static class ByteGetter {
+
+ // private static int intField = 1000000;
+
+ private static byte get() {
+ // GETSTATIC intField
+ // IRETURN
+ return 0;
+ }
+
+ public static int testByteSnippet() {
+ return get();
+ }
+ }
+
+ @Parameters(name = "{0}, {1}")
+ public static List<Object[]> data() {
+ ArrayList<Object[]> ret = new ArrayList<>();
+ for (int i : new int[]{1000000, 1000001, -1000000, -1}) {
+ ret.add(new Object[]{JavaKind.Boolean, i});
+ ret.add(new Object[]{JavaKind.Byte, i});
+ ret.add(new Object[]{JavaKind.Short, i});
+ ret.add(new Object[]{JavaKind.Char, i});
+ }
+ return ret;
+ }
+
+ public SubWordReturnTest(JavaKind kind, int value) {
+ this.kind = kind;
+ this.value = value;
+
+ this.generatedClassName = SubWordReturnTest.class.getName() + "$" + kind.toString() + "Getter";
+ this.generatedClassNameInternal = generatedClassName.replace('.', '/');
+ this.testMethodName = "test" + kind.name() + "Snippet";
+ }
+
+ @Test
+ public void test() throws ClassNotFoundException {
+ Class<?> testClass = new AsmLoader(SubWordReturnTest.class.getClassLoader()).findClass(generatedClassName);
+ ResolvedJavaMethod method = getResolvedJavaMethod(testClass, testMethodName);
+ test(method, null);
+ }
+
+ class AsmLoader extends ClassLoader implements Opcodes {
+
+ Class<?> loaded;
+
+ AsmLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.equals(generatedClassName)) {
+ if (loaded == null) {
+ byte[] gen = generateClass();
+ loaded = defineClass(name, gen, 0, gen.length);
+ }
+ return loaded;
+ } else {
+ return super.findClass(name);
+ }
+ }
+
+ private byte[] generateClass() {
+ ClassWriter cw = new ClassWriter(0);
+ cw.visit(52, ACC_SUPER | ACC_PUBLIC, generatedClassNameInternal, null, "java/lang/Object", null);
+
+ FieldVisitor intField = cw.visitField(ACC_PRIVATE | ACC_STATIC, "intField", "I", null, value);
+ intField.visitEnd();
+
+ MethodVisitor get = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, "get", "()" + kind.getTypeChar(), null, null);
+ get.visitCode();
+ get.visitFieldInsn(GETSTATIC, generatedClassNameInternal, "intField", "I");
+ get.visitInsn(IRETURN);
+ get.visitMaxs(1, 0);
+ get.visitEnd();
+
+ MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, testMethodName, "()I", null, null);
+ snippet.visitCode();
+ snippet.visitMethodInsn(INVOKESTATIC, generatedClassNameInternal, "get", "()" + kind.getTypeChar(), false);
+ snippet.visitInsn(IRETURN);
+ snippet.visitMaxs(1, 0);
+ snippet.visitEnd();
+
+ cw.visitEnd();
+ return cw.toByteArray();
+ }
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnbalancedMonitorsTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -87,7 +87,7 @@
ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name);
try {
OptionValues options = getInitialOptions();
- StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build();
+ StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, method)).method(method).build();
Plugins plugins = new Plugins(new InvocationPlugins());
GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/UnsafeVirtualizationTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -32,9 +32,20 @@
import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
import org.junit.Test;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
public class UnsafeVirtualizationTest extends GraalCompilerTest {
- public static class A {
+ public static class Base {
+ /*
+ * This padding ensure that the size of the Base class ends up as a multiple of 8, which
+ * makes the first field of the subclass 8-byte aligned.
+ */
+ double padding;
+ }
+
+ public static class A extends Base {
int f1;
int f2;
}
@@ -56,39 +67,96 @@
AF2Offset = o2;
}
- public static int unsafeSnippet0(int i1, int i2) {
+ public static int unsafeSnippet1(double i1) {
A a = new A();
- UNSAFE.putDouble(a, AF1Offset, i1 + i2);
+ UNSAFE.putDouble(a, AF1Offset, i1);
return UNSAFE.getInt(a, AF1Offset) + UNSAFE.getInt(a, AF2Offset);
}
- public static int unsafeSnippet1(int i1, int i2) {
+ public static long unsafeSnippet2a(int i1) {
+ A a = new A();
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ a.f1 = i1;
+ return UNSAFE.getLong(a, AF1Offset);
+ }
+
+ public static long unsafeSnippet2b(int i1) {
+ A a = new A();
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ a.f2 = i1;
+ return UNSAFE.getLong(a, AF1Offset);
+ }
+
+ public static long unsafeSnippet3a(int i1) {
A a = new A();
- UNSAFE.putDouble(a, AF1Offset, i1 + i2);
- a.f2 = i1;
- return (int) UNSAFE.getDouble(a, AF1Offset);
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ UNSAFE.putInt(a, AF1Offset, i1);
+ return UNSAFE.getLong(a, AF1Offset);
+ }
+
+ public static long unsafeSnippet3b(int i1) {
+ A a = new A();
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ UNSAFE.putInt(a, AF2Offset, i1);
+ return UNSAFE.getLong(a, AF1Offset);
+ }
+
+ public static int unsafeSnippet4(double i1) {
+ A a = new A();
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ UNSAFE.putDouble(a, AF1Offset, i1);
+ return UNSAFE.getInt(a, AF1Offset) + UNSAFE.getInt(a, AF2Offset);
}
@Test
public void testUnsafePEA01() {
- testPartialEscapeReadElimination(parseEager("unsafeSnippet0", AllowAssumptions.NO), false);
- testPartialEscapeReadElimination(parseEager("unsafeSnippet0", AllowAssumptions.NO), true);
+ testPartialEscapeReadElimination("unsafeSnippet1", false, 1.0);
+ testPartialEscapeReadElimination("unsafeSnippet1", true, 1.0);
}
@Test
public void testUnsafePEA02() {
- testPartialEscapeReadElimination(parseEager("unsafeSnippet1", AllowAssumptions.NO), false);
- testPartialEscapeReadElimination(parseEager("unsafeSnippet1", AllowAssumptions.NO), true);
+ testPartialEscapeReadElimination("unsafeSnippet2a", false, 1);
+ testPartialEscapeReadElimination("unsafeSnippet2a", true, 1);
+
+ testPartialEscapeReadElimination("unsafeSnippet2b", false, 1);
+ testPartialEscapeReadElimination("unsafeSnippet2b", true, 1);
}
- public void testPartialEscapeReadElimination(StructuredGraph graph, boolean canonicalizeBefore) {
+ @Test
+ public void testUnsafePEA03() {
+ testPartialEscapeReadElimination("unsafeSnippet3a", false, 1);
+ testPartialEscapeReadElimination("unsafeSnippet3a", true, 1);
+
+ testPartialEscapeReadElimination("unsafeSnippet3b", false, 1);
+ testPartialEscapeReadElimination("unsafeSnippet3b", true, 1);
+ }
+
+ @Test
+ public void testUnsafePEA04() {
+ testPartialEscapeReadElimination("unsafeSnippet4", false, 1.0);
+ testPartialEscapeReadElimination("unsafeSnippet4", true, 1.0);
+ }
+
+ public void testPartialEscapeReadElimination(String snippet, boolean canonicalizeBefore, Object... args) {
+ assert AF1Offset % 8 == 0 : "First of the two int-fields must be 8-byte aligned";
+
+ ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
+ StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
OptionValues options = graph.getOptions();
PhaseContext context = getDefaultHighTierContext();
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
if (canonicalizeBefore) {
canonicalizer.apply(graph, context);
}
+ Result r = executeExpected(method, null, args);
new PartialEscapePhase(true, true, canonicalizer, null, options).apply(graph, context);
+ try {
+ InstalledCode code = getCode(method, graph);
+ Object result = code.executeVarargs(args);
+ assertEquals(r, new Result(result, null));
+ } catch (Throwable e) {
+ assertFalse(true, e.toString());
+ }
}
-
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java Mon Nov 06 20:29:49 2017 -0800
@@ -77,7 +77,7 @@
@Override
public String toString() {
- return "{" + x + "," + y + "}";
+ return "{" + x + "," + y + "," + z + "}";
}
@Override
@@ -158,11 +158,19 @@
context = getDefaultHighTierContext();
new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
new DeadCodeEliminationPhase().apply(graph);
- new CanonicalizerPhase().apply(graph, context);
+ canonicalizeGraph();
new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
+ postEACanonicalizeGraph();
returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
} catch (Throwable e) {
throw debug.handle(e);
}
}
+
+ protected void postEACanonicalizeGraph() {
+ }
+
+ protected void canonicalizeGraph() {
+ new CanonicalizerPhase().apply(graph, context);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -27,9 +27,20 @@
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.code.SourceStackTraceBailoutException;
import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
public class PEAAssertionsTest extends GraalCompilerTest {
+ /**
+ * These tests assume all code paths are reachable so disable profile based dead code removal.
+ */
+ @Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
public static Object field;
public static void snippet1(int i) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/TrufflePEATest.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.core.test.ea;
+import java.lang.reflect.Field;
+
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.StructuredGraph;
@@ -33,10 +35,9 @@
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
import org.junit.Test;
+
import sun.misc.Unsafe;
-import java.lang.reflect.Field;
-
public class TrufflePEATest extends GraalCompilerTest {
/**
@@ -56,6 +57,7 @@
static class DynamicObject {
int primitiveField0;
int primitiveField1;
+ int primitiveField2;
}
private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
@@ -66,7 +68,15 @@
static {
try {
Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0");
- primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0);
+ long offset = UNSAFE.objectFieldOffset(primitiveField0);
+ if (offset % 8 == 0) {
+ primitiveField0Offset = offset;
+ } else {
+ Field primitiveField1 = DynamicObject.class.getDeclaredField("primitiveField1");
+ offset = UNSAFE.objectFieldOffset(primitiveField1);
+ assert offset % 8 == 0;
+ primitiveField0Offset = offset;
+ }
} catch (NoSuchFieldException | SecurityException e) {
throw new AssertionError(e);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeEATest.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,14 +22,26 @@
*/
package org.graalvm.compiler.core.test.ea;
-import jdk.vm.ci.meta.JavaConstant;
+import java.nio.ByteBuffer;
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.PhiNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
+import org.graalvm.compiler.nodes.extended.RawLoadNode;
+import org.graalvm.compiler.nodes.extended.RawStoreNode;
+import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
+import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.junit.Assert;
import org.junit.Test;
-import org.graalvm.compiler.nodes.PhiNode;
-import org.graalvm.compiler.nodes.ValuePhiNode;
-import org.graalvm.compiler.nodes.java.LoadFieldNode;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
public class UnsafeEATest extends EATestBase {
@@ -56,6 +68,64 @@
}
}
+ @Override
+ protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) {
+ // Exercise both a graph containing UnsafeAccessNodes and one which has been possibly been
+ // canonicalized into AccessFieldNodes.
+ testingUnsafe = true;
+ super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis);
+ testingUnsafe = false;
+ super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis);
+ if (expectedConstantResult != null) {
+ // Check that a compiled version of this method returns the same value if we expect a
+ // constant result.
+ ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
+ JavaKind[] javaKinds = method.getSignature().toParameterKinds(false);
+ Object[] args = new Object[javaKinds.length];
+ int i = 0;
+ for (JavaKind k : javaKinds) {
+ args[i++] = JavaConstant.defaultForKind(k).asBoxedPrimitive();
+ }
+ Result result = executeExpected(method, null, args);
+ assertTrue(result.returnValue.equals(expectedConstantResult.asBoxedPrimitive()));
+ }
+ }
+
+ @Override
+ protected void canonicalizeGraph() {
+ if (testingUnsafe) {
+ // For testing purposes we'd like to ensure that our raw unsafe operations stay as
+ // unsafe nodes, so force them to appear to have LocationIdentity.any to disable
+ // transformation into field access nodes.
+ for (Node node : graph.getNodes().filter(x -> x instanceof UnsafeAccessNode).snapshot()) {
+ if (node instanceof RawStoreNode) {
+ RawStoreNode store = (RawStoreNode) node;
+ RawStoreNode newStore = graph.add(new RawStoreNode(store.object(), store.offset(), store.value(), store.accessKind(), NamedLocationIdentity.any(),
+ store.needsBarrier(), store.stateAfter(), true));
+ graph.replaceFixedWithFixed(store, newStore);
+ } else if (node instanceof RawLoadNode) {
+ RawLoadNode load = (RawLoadNode) node;
+ RawLoadNode newLoad = graph.add(new RawLoadNode(load.object(), load.offset(), load.accessKind(), NamedLocationIdentity.any(),
+ true));
+ graph.replaceFixedWithFixed(load, newLoad);
+ }
+ }
+ }
+ super.canonicalizeGraph();
+ }
+
+ @Override
+ protected void postEACanonicalizeGraph() {
+ // Simplify any UnpackEndianHalfNode so we end up with constants.
+ Graph.Mark mark = graph.getMark();
+ for (UnpackEndianHalfNode node : graph.getNodes().filter(UnpackEndianHalfNode.class)) {
+ node.lower(getTarget().arch.getByteOrder());
+ }
+ new CanonicalizerPhase().applyIncremental(graph, context, mark);
+ }
+
+ private boolean testingUnsafe;
+
@Test
public void testSimpleInt() {
testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false);
@@ -90,6 +160,82 @@
}
@Test
+ public void testSimpleDoubleOverwriteWithInt() {
+ testEscapeAnalysis("testSimpleDoubleOverwriteWithIntSnippet", JavaConstant.forInt(10), false);
+ }
+
+ public static int testSimpleDoubleOverwriteWithIntSnippet() {
+ TestClassInt x = new TestClassInt();
+ UNSAFE.putDouble(x, fieldOffset1, 10.1);
+ UNSAFE.putInt(x, fieldOffset1, 10);
+ return UNSAFE.getInt(x, fieldOffset1);
+ }
+
+ @Test
+ public void testSimpleDoubleOverwriteWithSecondInt() {
+ ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
+ bb.putDouble(10.1);
+ int value = bb.getInt(4);
+
+ testEscapeAnalysis("testSimpleDoubleOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false);
+ }
+
+ public static int testSimpleDoubleOverwriteWithSecondIntSnippet() {
+ TestClassInt x = new TestClassInt();
+ UNSAFE.putDouble(x, fieldOffset1, 10.1);
+ UNSAFE.putInt(x, fieldOffset1, 10);
+ return UNSAFE.getInt(x, fieldOffset2);
+ }
+
+ @Test
+ public void testSimpleDoubleOverwriteWithFirstInt() {
+ ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
+ bb.putDouble(10.1);
+ int value = bb.getInt(0);
+
+ testEscapeAnalysis("testSimpleDoubleOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false);
+ }
+
+ public static int testSimpleDoubleOverwriteWithFirstIntSnippet() {
+ TestClassInt x = new TestClassInt();
+ UNSAFE.putDouble(x, fieldOffset1, 10.1);
+ UNSAFE.putInt(x, fieldOffset2, 10);
+ return UNSAFE.getInt(x, fieldOffset1);
+ }
+
+ @Test
+ public void testSimpleLongOverwriteWithSecondInt() {
+ ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
+ bb.putLong(0, 0x1122334455667788L);
+ int value = bb.getInt(4);
+
+ testEscapeAnalysis("testSimpleLongOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false);
+ }
+
+ public static int testSimpleLongOverwriteWithSecondIntSnippet() {
+ TestClassInt x = new TestClassInt();
+ UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L);
+ UNSAFE.putInt(x, fieldOffset1, 10);
+ return UNSAFE.getInt(x, fieldOffset2);
+ }
+
+ @Test
+ public void testSimpleLongOverwriteWithFirstInt() {
+ ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
+ bb.putLong(0, 0x1122334455667788L);
+ int value = bb.getInt(0);
+
+ testEscapeAnalysis("testSimpleLongOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false);
+ }
+
+ public static int testSimpleLongOverwriteWithFirstIntSnippet() {
+ TestClassInt x = new TestClassInt();
+ UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L);
+ UNSAFE.putInt(x, fieldOffset2, 10);
+ return UNSAFE.getInt(x, fieldOffset1);
+ }
+
+ @Test
public void testMergedDouble() {
testEscapeAnalysis("testMergedDoubleSnippet", null, false);
Assert.assertEquals(1, returnNodes.size());
@@ -111,6 +257,32 @@
return UNSAFE.getDouble(x, fieldOffset1);
}
+ static class ExtendedTestClassInt extends TestClassInt {
+ public long l;
+ }
+
+ @Test
+ public void testMergedVirtualObjects() {
+ testEscapeAnalysis("testMergedVirtualObjectsSnippet", null, false);
+ }
+
+ public static TestClassInt testMergedVirtualObjectsSnippet(int value) {
+ TestClassInt x;
+ if (value == 1) {
+ x = new TestClassInt();
+ UNSAFE.putDouble(x, fieldOffset1, 10);
+ } else {
+ x = new TestClassInt();
+ UNSAFE.putInt(x, fieldOffset1, 0);
+ }
+ UNSAFE.putInt(x, fieldOffset1, 0);
+ if (value == 2) {
+ UNSAFE.putInt(x, fieldOffset2, 0);
+ }
+ GraalDirectives.deoptimizeAndInvalidate();
+ return x;
+ }
+
@Test
public void testMaterializedDouble() {
test("testMaterializedDoubleSnippet");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -146,7 +146,7 @@
private StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer) {
OptionValues options = getInitialOptions();
- StructuredGraph newGraph = new StructuredGraph.Builder(options, getDebugContext(options), AllowAssumptions.NO).method(method).build();
+ StructuredGraph newGraph = new StructuredGraph.Builder(options, getDebugContext(options, null, method), AllowAssumptions.NO).method(method).build();
context.getGraphBuilderSuite().apply(newGraph, context);
new DeadCodeEliminationPhase(Optional).apply(newGraph);
canonicalizer.apply(newGraph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompilerOptions.java Mon Nov 06 20:29:49 2017 -0800
@@ -47,7 +47,7 @@
public static final EnumOptionKey<ExceptionAction> CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose);
@Option(help = "The maximum number of compilation failures or bailouts to handle with the action specified " +
"by CompilationFailureAction or CompilationBailoutAction before changing to a less verbose action.", type = OptionType.User)
- public static final OptionKey<Integer> MaxCompilationProblemsPerAction = new OptionKey<>(5);
+ public static final OptionKey<Integer> MaxCompilationProblemsPerAction = new OptionKey<>(2);
@Option(help = "Alias for CompilationFailureAction=ExitVM.", type = OptionType.User)
public static final OptionKey<Boolean> ExitVMOnException = new OptionKey<>(false);
// @formatter:on
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -132,8 +132,17 @@
slotKinds[pos] = toSlotKind(value);
pos++;
} else {
- assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " +
- currentField.values().get(i - 1);
+ assert value.getStackKind() == JavaKind.Illegal;
+ ValueNode previousValue = currentField.values().get(i - 1);
+ assert (previousValue != null && previousValue.getStackKind().needsTwoSlots()) : vobjNode + " " + i +
+ " " + previousValue + " " + currentField.values().snapshot();
+ if (previousValue == null || !previousValue.getStackKind().needsTwoSlots()) {
+ // Don't allow the IllegalConstant to leak into the debug info
+ JavaKind entryKind = vobjNode.entryKind(i);
+ values[pos] = JavaConstant.defaultForKind(entryKind.getStackKind());
+ slotKinds[pos] = entryKind.getStackKind();
+ pos++;
+ }
}
}
if (pos != entryCount) {
@@ -164,19 +173,19 @@
if (!type.isArray()) {
ResolvedJavaField[] fields = type.getInstanceFields(true);
int fieldIndex = 0;
- for (int i = 0; i < values.length; i++) {
- ResolvedJavaField field = fields[fieldIndex++];
- JavaKind valKind = slotKinds[i].getStackKind();
+ for (int valueIndex = 0; valueIndex < values.length; valueIndex++, fieldIndex++) {
+ ResolvedJavaField field = fields[fieldIndex];
+ JavaKind valKind = slotKinds[valueIndex].getStackKind();
JavaKind fieldKind = storageKind(field.getType());
- if (fieldKind == JavaKind.Object) {
- assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind;
+ if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
+ assert fieldIndex + 1 < fields.length : String.format("Not enough fields for fieldIndex = %d valueIndex = %d %s %s", fieldIndex, valueIndex, Arrays.toString(fields),
+ Arrays.toString(values));
+ assert storageKind(fields[fieldIndex + 1].getType()) == JavaKind.Int : String.format("fieldIndex = %d valueIndex = %d %s %s %s", fieldIndex, valueIndex,
+ storageKind(fields[fieldIndex + 1].getType()), Arrays.toString(fields),
+ Arrays.toString(values));
+ fieldIndex++;
} else {
- if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
- assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int;
- fieldIndex++;
- } else {
- assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
- }
+ assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
}
}
assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -59,6 +59,7 @@
import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.debug.LIRGenerationDebugContext;
+import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
import org.graalvm.compiler.lir.gen.LIRGenerator;
import org.graalvm.compiler.lir.gen.LIRGenerator.Options;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
@@ -577,9 +578,9 @@
@Override
public void emitInvoke(Invoke x) {
LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
- CallingConvention invokeCc = gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()),
- callTarget.signature(), gen);
- gen.getResult().getFrameMapBuilder().callsMethod(invokeCc);
+ FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
+ CallingConvention invokeCc = frameMapBuilder.getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), callTarget.signature(), gen);
+ frameMapBuilder.callsMethod(invokeCc);
Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java Mon Nov 06 20:29:49 2017 -0800
@@ -195,9 +195,12 @@
public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult,
SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault, Object[] context) {
Object[] debugContext = context != null ? context : new Object[]{getProviders().getCodeCache(), method, compilationResult};
- CodeInstallationTask[] tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()];
- for (int i = 0; i < codeInstallationTaskFactories.size(); i++) {
- tasks[i] = codeInstallationTaskFactories.get(i).create();
+ CodeInstallationTask[] tasks;
+ synchronized (this) {
+ tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()];
+ for (int i = 0; i < codeInstallationTaskFactories.size(); i++) {
+ tasks[i] = codeInstallationTaskFactories.get(i).create();
+ }
}
try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
DebugContext.Activation a = debug.activate()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Mon Nov 06 20:29:49 2017 -0800
@@ -29,9 +29,11 @@
import static org.graalvm.compiler.debug.DebugOptions.Dump;
import static org.graalvm.compiler.debug.DebugOptions.DumpOnError;
import static org.graalvm.compiler.debug.DebugOptions.DumpOnPhaseChange;
+import static org.graalvm.compiler.debug.DebugOptions.DumpPath;
import static org.graalvm.compiler.debug.DebugOptions.ListMetrics;
import static org.graalvm.compiler.debug.DebugOptions.Log;
import static org.graalvm.compiler.debug.DebugOptions.MemUseTrackers;
+import static org.graalvm.compiler.debug.DebugOptions.ShowDumpFiles;
import static org.graalvm.compiler.debug.DebugOptions.Time;
import static org.graalvm.compiler.debug.DebugOptions.Timers;
import static org.graalvm.compiler.debug.DebugOptions.TrackMemUse;
@@ -56,6 +58,7 @@
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.graphio.GraphOutput;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet;
import org.graalvm.util.Pair;
@@ -98,6 +101,8 @@
CloseableCounter currentMemUseTracker;
Scope lastClosedScope;
Throwable lastExceptionThrown;
+ private IgvDumpChannel sharedChannel;
+ private GraphOutput<?, ?> parentOutput;
/**
* Stores the {@link MetricKey} values.
@@ -111,6 +116,19 @@
return immutable.scopesEnabled;
}
+ public <G, N, M> GraphOutput<G, M> buildOutput(GraphOutput.Builder<G, N, M> builder) throws IOException {
+ if (parentOutput != null) {
+ return builder.build(parentOutput);
+ } else {
+ if (sharedChannel == null) {
+ sharedChannel = new IgvDumpChannel(() -> getDumpPath(".bgv", false), immutable.options);
+ }
+ final GraphOutput<G, M> output = builder.build(sharedChannel);
+ parentOutput = output;
+ return output;
+ }
+ }
+
/**
* The immutable configuration that can be shared between {@link DebugContext} objects.
*/
@@ -323,6 +341,14 @@
String compilableName = compilable instanceof JavaMethod ? ((JavaMethod) compilable).format("%H.%n(%p)%R") : String.valueOf(compilable);
return identifier + ":" + compilableName;
}
+
+ final String getLabel() {
+ if (compilable instanceof JavaMethod) {
+ JavaMethod method = (JavaMethod) compilable;
+ return method.format("%h.%n(%p)%r");
+ }
+ return String.valueOf(compilable);
+ }
}
private final Description description;
@@ -394,6 +420,20 @@
}
}
+ public Path getDumpPath(String extension, boolean directory) {
+ try {
+ String id = description == null ? null : description.identifier;
+ String label = description == null ? null : description.getLabel();
+ Path result = PathUtilities.createUnique(immutable.options, DumpPath, id, label, extension, directory);
+ if (ShowDumpFiles.getValue(immutable.options)) {
+ TTY.println("Dumping debug output to %s", result.toAbsolutePath().toString());
+ }
+ return result;
+ } catch (IOException ex) {
+ throw rethrowSilently(RuntimeException.class, ex);
+ }
+ }
+
/**
* A special dump level that indicates the dumping machinery is enabled but no dumps will be
* produced except through other options.
@@ -2043,4 +2083,9 @@
}
out.println();
}
+
+ @SuppressWarnings({"unused", "unchecked"})
+ private static <E extends Exception> E rethrowSilently(Class<E> type, Throwable ex) throws E {
+ throw (E) ex;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHandlersFactory.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugHandlersFactory.java Mon Nov 06 20:29:49 2017 -0800
@@ -35,6 +35,9 @@
/**
* Creates {@link DebugHandler}s based on {@code options}.
+ *
+ * @param options options to control type and name of the channel
+ * @return list of debug handers that have been created
*/
List<DebugHandler> createHandlers(OptionValues options);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java Mon Nov 06 20:29:49 2017 -0800
@@ -128,8 +128,6 @@
public static final OptionKey<Boolean> PrintGraphProbabilities = new OptionKey<>(false);
@Option(help = "Enable dumping to the IdealGraphVisualizer.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintGraph = new OptionKey<>(true);
- @Option(help = "Dump graphs in binary format instead of XML format.", type = OptionType.Debug)
- public static final OptionKey<Boolean> PrintBinaryGraphs = new OptionKey<>(true);
@Option(help = "Print graphs to files instead of sending them over the network.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintGraphFile = new OptionKey<>(false);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/IgvDumpChannel.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,119 @@
+/*
+ * 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 java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.function.Supplier;
+import static org.graalvm.compiler.debug.DebugOptions.PrintBinaryGraphPort;
+import static org.graalvm.compiler.debug.DebugOptions.PrintGraphHost;
+import org.graalvm.compiler.options.OptionValues;
+
+final class IgvDumpChannel implements WritableByteChannel {
+ private final Supplier<Path> pathProvider;
+ private final OptionValues options;
+ private WritableByteChannel sharedChannel;
+ private boolean closed;
+
+ IgvDumpChannel(Supplier<Path> pathProvider, OptionValues options) {
+ this.pathProvider = pathProvider;
+ this.options = options;
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ return channel().write(src);
+ }
+
+ @Override
+ public boolean isOpen() {
+ return !closed;
+ }
+
+ @Override
+ public void close() throws IOException {
+ }
+
+ void realClose() throws IOException {
+ closed = true;
+ if (sharedChannel != null) {
+ sharedChannel.close();
+ sharedChannel = null;
+ }
+ }
+
+ WritableByteChannel channel() throws IOException {
+ if (closed) {
+ throw new IOException();
+ }
+ if (sharedChannel == null) {
+ if (DebugOptions.PrintGraphFile.getValue(options)) {
+ sharedChannel = createFileChannel(pathProvider);
+ } else {
+ sharedChannel = createNetworkChannel(pathProvider, options);
+ }
+ }
+ return sharedChannel;
+ }
+
+ private static WritableByteChannel createNetworkChannel(Supplier<Path> pathProvider, OptionValues options) throws IOException {
+ String host = PrintGraphHost.getValue(options);
+ int port = PrintBinaryGraphPort.getValue(options);
+ try {
+ WritableByteChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
+ TTY.println("Connected to the IGV on %s:%d", host, port);
+ return channel;
+ } catch (ClosedByInterruptException | InterruptedIOException e) {
+ /*
+ * Interrupts should not count as errors because they may be caused by a cancelled Graal
+ * compilation. ClosedByInterruptException occurs if the SocketChannel could not be
+ * opened. InterruptedIOException occurs if new Socket(..) was interrupted.
+ */
+ return null;
+ } catch (IOException e) {
+ if (!DebugOptions.PrintGraphFile.hasBeenSet(options)) {
+ return createFileChannel(pathProvider);
+ } else {
+ throw new IOException(String.format("Could not connect to the IGV on %s:%d", host, port), e);
+ }
+ }
+ }
+
+ private static WritableByteChannel createFileChannel(Supplier<Path> pathProvider) throws IOException {
+ Path path = pathProvider.get();
+ try {
+ return FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
+ } catch (IOException e) {
+ throw new IOException(String.format("Failed to open %s to dump IGV graphs", path), e);
+ }
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,12 +22,13 @@
*/
package org.graalvm.compiler.debug;
+import java.io.File;
import java.io.IOException;
+import java.nio.file.FileAlreadyExistsException;
+import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.graalvm.compiler.options.OptionKey;
@@ -39,54 +40,6 @@
public class PathUtilities {
private static final AtomicLong globalTimeStamp = new AtomicLong();
- /**
- * This generates a per thread persistent id to aid mapping related dump files with each other.
- */
- private static final ThreadLocal<PerThreadSequence> threadDumpId = new ThreadLocal<>();
- private static final AtomicInteger dumpId = new AtomicInteger();
-
- static class PerThreadSequence {
- final int threadID;
- HashMap<String, Integer> sequences = new HashMap<>(2);
-
- PerThreadSequence(int threadID) {
- this.threadID = threadID;
- }
-
- String generateID(String extension) {
- Integer box = sequences.get(extension);
- if (box == null) {
- sequences.put(extension, 1);
- return Integer.toString(threadID);
- } else {
- sequences.put(extension, box + 1);
- return Integer.toString(threadID) + '-' + box;
- }
- }
- }
-
- private static String getThreadDumpId(String extension) {
- PerThreadSequence id = threadDumpId.get();
- if (id == null) {
- id = new PerThreadSequence(dumpId.incrementAndGet());
- threadDumpId.set(id);
- }
- return id.generateID(extension);
- }
-
- /**
- * Prepends a period (i.e., {@code '.'}) to an non-null, non-empty string representation a file
- * extension if the string does not already start with a period.
- *
- * @return {@code ext} unmodified if it is null, empty or already starts with a period other
- * {@code "." + ext}
- */
- public static String formatExtension(String ext) {
- if (ext == null || ext.length() == 0) {
- return "";
- }
- return "." + ext;
- }
/**
* Gets a time stamp for the current process. This method will always return the same value for
@@ -100,43 +53,6 @@
}
/**
- * Generates a {@link Path} using the format "%s-%d_%d%s" with the {@code baseNameOption}, a
- * {@link #getGlobalTimeStamp() global timestamp} , {@link #getThreadDumpId a per thread unique
- * id} and an optional {@code extension}.
- *
- * @return the output file path or null if the flag is null
- */
- public static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException {
- return getPath(options, baseNameOption, extension, true);
- }
-
- /**
- * Generate a {@link Path} using the format "%s-%d_%s" with the {@code baseNameOption}, a
- * {@link #getGlobalTimeStamp() global timestamp} and an optional {@code extension} .
- *
- * @return the output file path or null if the flag is null
- */
- public static Path getPathGlobal(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException {
- return getPath(options, baseNameOption, extension, false);
- }
-
- private static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension, boolean includeThreadId) throws IOException {
- if (baseNameOption.getValue(options) == null) {
- return null;
- }
- String ext = formatExtension(extension);
- final String name = includeThreadId
- ? String.format("%s-%d_%s%s", baseNameOption.getValue(options), getGlobalTimeStamp(), getThreadDumpId(ext), ext)
- : String.format("%s-%d%s", baseNameOption.getValue(options), getGlobalTimeStamp(), ext);
- Path result = Paths.get(name);
- if (result.isAbsolute()) {
- return result;
- }
- Path dumpDir = DebugOptions.getDumpDirectory(options);
- return dumpDir.resolve(name).normalize();
- }
-
- /**
* Gets a value based on {@code name} that can be passed to {@link Paths#get(String, String...)}
* without causing an {@link InvalidPathException}.
*
@@ -145,21 +61,80 @@
*/
public static String sanitizeFileName(String name) {
try {
- Paths.get(name);
- return name;
+ Path path = Paths.get(name);
+ if (path.getNameCount() == 0) {
+ return name;
+ }
} catch (InvalidPathException e) {
// fall through
}
StringBuilder buf = new StringBuilder(name.length());
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
- try {
- Paths.get(String.valueOf(c));
- } catch (InvalidPathException e) {
- buf.append('_');
+ if (c != File.separatorChar && c != ' ' && !Character.isISOControl(c)) {
+ try {
+ Paths.get(String.valueOf(c));
+ buf.append(c);
+ continue;
+ } catch (InvalidPathException e) {
+ }
}
- buf.append(c);
+ buf.append('_');
}
return buf.toString();
}
+
+ /**
+ * A maximum file name length supported by most file systems. There is no platform independent
+ * way to get this in Java.
+ */
+ private static final int MAX_FILE_NAME_LENGTH = 255;
+
+ private static final String ELLIPSIS = "...";
+
+ static Path createUnique(OptionValues options, OptionKey<String> baseNameOption, String id, String label, String ext, boolean createDirectory) throws IOException {
+ String uniqueTag = "";
+ int dumpCounter = 1;
+ String prefix;
+ if (id == null) {
+ prefix = baseNameOption.getValue(options);
+ int slash = prefix.lastIndexOf(File.separatorChar);
+ prefix = prefix.substring(slash + 1);
+ } else {
+ prefix = id;
+ }
+ for (;;) {
+ int fileNameLengthWithoutLabel = uniqueTag.length() + ext.length() + prefix.length() + "[]".length();
+ int labelLengthLimit = MAX_FILE_NAME_LENGTH - fileNameLengthWithoutLabel;
+ String fileName;
+ if (labelLengthLimit < ELLIPSIS.length()) {
+ // This means `id` is very long
+ String suffix = uniqueTag + ext;
+ int idLengthLimit = Math.min(MAX_FILE_NAME_LENGTH - suffix.length(), prefix.length());
+ fileName = sanitizeFileName(prefix.substring(0, idLengthLimit) + suffix);
+ } else {
+ if (label == null) {
+ fileName = sanitizeFileName(prefix + uniqueTag + ext);
+ } else {
+ String adjustedLabel = label;
+ if (label.length() > labelLengthLimit) {
+ adjustedLabel = label.substring(0, labelLengthLimit - ELLIPSIS.length()) + ELLIPSIS;
+ }
+ fileName = sanitizeFileName(prefix + '[' + adjustedLabel + ']' + uniqueTag + ext);
+ }
+ }
+ Path dumpDir = DebugOptions.getDumpDirectory(options);
+ Path result = Paths.get(dumpDir.toString(), fileName);
+ try {
+ if (createDirectory) {
+ return Files.createDirectory(result);
+ } else {
+ return Files.createFile(result);
+ }
+ } catch (FileAlreadyExistsException e) {
+ uniqueTag = "_" + dumpCounter++;
+ }
+ }
+ }
+
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/GraphSnippetTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,51 @@
+/*
+ * 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.graph.test.graphio;
+
+import java.io.File;
+import java.lang.reflect.Method;
+import static org.junit.Assert.assertTrue;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class GraphSnippetTest {
+ @Test
+ public void dumpTheFile() throws Exception {
+ Class<?> snippets = null;
+ try {
+ snippets = Class.forName("org.graalvm.graphio.GraphSnippets");
+ } catch (ClassNotFoundException notFound) {
+ Assume.assumeNoException("The snippets class has to be around", notFound);
+ }
+ Method dump = null;
+ try {
+ dump = snippets.getDeclaredMethod("dump", File.class);
+ dump.setAccessible(true);
+ } catch (RuntimeException ex) {
+ Assume.assumeTrue("Only run the test, if the method is accessible", dump != null && dump.isAccessible());
+ }
+ File diamond = File.createTempFile("diamond", ".bgv");
+ dump.invoke(null, diamond);
+ assertTrue("File .bgv created: " + diamond, diamond.length() > 50);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/NodeEncodingTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,311 @@
+/*
+ * 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.graph.test.graphio;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.channels.Channels;
+import java.nio.channels.WritableByteChannel;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import org.graalvm.graphio.GraphOutput;
+import org.graalvm.graphio.GraphStructure;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import org.junit.Before;
+import org.junit.Test;
+
+public final class NodeEncodingTest {
+
+ private ByteArrayOutputStream out;
+
+ @Before
+ public void initOutput() {
+ out = new ByteArrayOutputStream();
+ }
+
+ @Test
+ public void version40TheNodeIsntDumpedWithItsID() throws Exception {
+ runTheNodeIsntDumpedWithItsID(true);
+ }
+
+ @Test
+ public void defaultVersionTheNodeIsntDumpedWithItsID() throws Exception {
+ runTheNodeIsntDumpedWithItsID(false);
+ }
+
+ private void runTheNodeIsntDumpedWithItsID(boolean explicitVersion) throws Exception {
+ WritableByteChannel w = Channels.newChannel(out);
+ MockGraph graph = new MockGraph();
+ MockNodeClass clazz = new MockNodeClass("clazz");
+ MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
+ try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
+ dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
+ dump.endGroup();
+ }
+
+ assertEquals("Node is always requested", 1, node.nodeRequested);
+ assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested);
+ assertByte(false, out.toByteArray(), 33);
+ assertEquals("Node class of the node has been requested", 1, node.nodeClassRequested);
+ assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried);
+ assertFalse("No to string ops", node.toStringRequested);
+ }
+
+ @Test
+ public void dumpingNodeInVersion10() throws Exception {
+ runTheNodeIsTreatedAsString(true);
+ }
+
+ private void runTheNodeIsTreatedAsString(boolean explicitVersion) throws Exception {
+ WritableByteChannel w = Channels.newChannel(out);
+ MockGraph graph = new MockGraph();
+ MockNodeClass clazz = new MockNodeClass("clazz");
+ MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
+ try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(1, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
+ dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
+ dump.endGroup();
+ }
+
+ assertEquals("Node is always requested", 1, node.nodeRequested);
+ assertEquals("Nobody asks for id of a node in version 1.0", 0, node.idTested);
+ assertByte(false, out.toByteArray(), 33);
+ assertEquals("Node class was needed to find out it is not a NodeClass instance", 1, node.nodeClassRequested);
+ assertEquals("Node class template name wasn't needed however", 0, clazz.nameTemplateQueried);
+ assertTrue("Node sent as a string version 1.0", node.toStringRequested);
+ }
+
+ @Test
+ public void dumpingNodeInVersion15() throws Exception {
+ runTheNodeIsTreatedPoolEntry(true);
+ }
+
+ private void runTheNodeIsTreatedPoolEntry(boolean explicitVersion) throws Exception {
+ WritableByteChannel w = Channels.newChannel(out);
+ MockGraph graph = new MockGraph();
+ MockNodeClass clazz = new MockNodeClass("clazz");
+ MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
+ try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(5, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
+ dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
+ dump.endGroup();
+ }
+
+ assertEquals("Node is always requested", 1, node.nodeRequested);
+ assertEquals("Id of our node is requested in version 5.0", 1, node.idTested);
+ assertByte(true, out.toByteArray(), 33);
+ assertTrue("Node class was needed at least once", 1 <= node.nodeClassRequested);
+ assertEquals("Node class template name sent to server", 1, clazz.nameTemplateQueried);
+ assertFalse("Node.toString() isn't needed", node.toStringRequested);
+ }
+
+ @Test
+ public void dumpingNodeTwiceInVersion4() throws Exception {
+ WritableByteChannel w = Channels.newChannel(out);
+ MockGraph graph = new MockGraph();
+ MockNodeClass clazz = new MockNodeClass("clazz");
+ MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
+ try (GraphOutput<MockGraph, ?> dump = GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w)) {
+ Map<String, Object> props = new LinkedHashMap<>();
+ props.put("node1", node);
+ props.put("node2", node);
+ props.put("node3", node);
+ dump.beginGroup(graph, "test1", "t1", null, 0, props);
+ dump.endGroup();
+ }
+
+ assertEquals("Node requested three times", 3, node.nodeRequested);
+ assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested);
+ // check there is no encoded string for object #3
+ assertByte(false, out.toByteArray(), 1, 0, 3);
+ assertEquals("Node class of the node has been requested three times", 3, node.nodeClassRequested);
+ assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried);
+ assertFalse("No to string ops", node.toStringRequested);
+ }
+
+ private static void assertByte(boolean shouldBeFound, byte[] arr, int... value) {
+ boolean found = false;
+ int at = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i] == value[at]) {
+ if (++at == value.length) {
+ found = true;
+ break;
+ }
+ } else {
+ at = 0;
+ }
+ }
+ if (shouldBeFound == found) {
+ return;
+ }
+ if (shouldBeFound) {
+ fail("Value " + value + " not found in\n" + Arrays.toString(arr));
+ } else {
+ fail("Value " + value + " surprisingly found in\n" + Arrays.toString(arr));
+ }
+ }
+
+ private static final class MockStructure implements GraphStructure<MockGraph, MockNode, MockNodeClass, MockNodeClass> {
+
+ @Override
+ public MockGraph graph(MockGraph currentGraph, Object obj) {
+ return obj instanceof MockGraph ? (MockGraph) obj : null;
+ }
+
+ @Override
+ public Iterable<? extends MockNode> nodes(MockGraph graph) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public int nodesCount(MockGraph graph) {
+ return 0;
+ }
+
+ @Override
+ public int nodeId(MockNode node) {
+ node.idTested++;
+ return node.id;
+ }
+
+ @Override
+ public boolean nodeHasPredecessor(MockNode node) {
+ return false;
+ }
+
+ @Override
+ public void nodeProperties(MockGraph graph, MockNode node, Map<String, ? super Object> properties) {
+ }
+
+ @Override
+ public MockNode node(Object obj) {
+ if (obj instanceof MockNode) {
+ ((MockNode) obj).nodeRequested++;
+ return (MockNode) obj;
+ }
+ return null;
+ }
+
+ @Override
+ public MockNodeClass nodeClass(Object obj) {
+ if (obj instanceof MockNode) {
+ ((MockNode) obj).nodeClassRequested++;
+ }
+ return obj instanceof MockNodeClass ? (MockNodeClass) obj : null;
+ }
+
+ @Override
+ public MockNodeClass classForNode(MockNode n) {
+ n.nodeClassRequested++;
+ return n.clazz;
+ }
+
+ @Override
+ public String nameTemplate(MockNodeClass nodeClass) {
+ nodeClass.nameTemplateQueried++;
+ return "";
+ }
+
+ @Override
+ public Object nodeClassType(MockNodeClass nodeClass) {
+ return nodeClass.getClass();
+ }
+
+ @Override
+ public MockNodeClass portInputs(MockNodeClass nodeClass) {
+ return nodeClass;
+ }
+
+ @Override
+ public MockNodeClass portOutputs(MockNodeClass nodeClass) {
+ return nodeClass;
+ }
+
+ @Override
+ public int portSize(MockNodeClass port) {
+ return 0;
+ }
+
+ @Override
+ public boolean edgeDirect(MockNodeClass port, int index) {
+ return false;
+ }
+
+ @Override
+ public String edgeName(MockNodeClass port, int index) {
+ return null;
+ }
+
+ @Override
+ public Object edgeType(MockNodeClass port, int index) {
+ return null;
+ }
+
+ @Override
+ public Collection<? extends MockNode> edgeNodes(MockGraph graph, MockNode node, MockNodeClass port, int index) {
+ return null;
+ }
+ }
+
+ private static final class MockGraph {
+
+ }
+
+ private static final class MockNode {
+ final MockNodeClass clazz;
+ final int id;
+ int idTested;
+ int nodeClassRequested;
+ int nodeRequested;
+ boolean toStringRequested;
+
+ MockNode(MockNodeClass clazz, int id) {
+ this.clazz = clazz;
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ this.toStringRequested = true;
+ return "MockNode{" + "id=" + id + ", class=" + clazz + '}';
+ }
+ }
+
+ private static final class MockNodeClass {
+ final String name;
+ int nameTemplateQueried;
+
+ MockNodeClass(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return "MockNodeClass{" + "name=" + name + '}';
+ }
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Mon Nov 06 20:29:49 2017 -0800
@@ -514,30 +514,61 @@
/**
* A node was added to a graph.
*/
- NODE_ADDED;
+ NODE_ADDED,
+
+ /**
+ * A node was removed from the graph.
+ */
+ NODE_REMOVED;
}
/**
* Client interested in one or more node related events.
*/
- public interface NodeEventListener {
+ public abstract static class NodeEventListener {
/**
- * Default handler for events.
+ * A method called when a change event occurs.
+ *
+ * This method dispatches the event to user-defined triggers. The methods that change the
+ * graph (typically in Graph and Node) must call this method to dispatch the event.
*
* @param e an event
* @param node the node related to {@code e}
*/
- default void event(NodeEvent e, Node node) {
+ final void event(NodeEvent e, Node node) {
+ switch (e) {
+ case INPUT_CHANGED:
+ inputChanged(node);
+ break;
+ case ZERO_USAGES:
+ usagesDroppedToZero(node);
+ break;
+ case NODE_ADDED:
+ nodeAdded(node);
+ break;
+ case NODE_REMOVED:
+ nodeRemoved(node);
+ break;
+ }
+ changed(e, node);
}
/**
- * Notifies this listener of a change in a node's inputs.
+ * Notifies this listener about any change event in the graph.
+ *
+ * @param e an event
+ * @param node the node related to {@code e}
+ */
+ public void changed(NodeEvent e, Node node) {
+ }
+
+ /**
+ * Notifies this listener about a change in a node's inputs.
*
* @param node a node who has had one of its inputs changed
*/
- default void inputChanged(Node node) {
- event(NodeEvent.INPUT_CHANGED, node);
+ public void inputChanged(Node node) {
}
/**
@@ -545,8 +576,7 @@
*
* @param node a node whose {@link Node#usages()} just became empty
*/
- default void usagesDroppedToZero(Node node) {
- event(NodeEvent.ZERO_USAGES, node);
+ public void usagesDroppedToZero(Node node) {
}
/**
@@ -554,8 +584,15 @@
*
* @param node a node that was just added to the graph
*/
- default void nodeAdded(Node node) {
- event(NodeEvent.NODE_ADDED, node);
+ public void nodeAdded(Node node) {
+ }
+
+ /**
+ * Notifies this listener of a removed node.
+ *
+ * @param node
+ */
+ public void nodeRemoved(Node node) {
}
}
@@ -583,7 +620,7 @@
}
}
- private static class ChainedNodeEventListener implements NodeEventListener {
+ private static class ChainedNodeEventListener extends NodeEventListener {
NodeEventListener head;
NodeEventListener next;
@@ -595,20 +632,32 @@
@Override
public void nodeAdded(Node node) {
- head.nodeAdded(node);
- next.nodeAdded(node);
+ head.event(NodeEvent.NODE_ADDED, node);
+ next.event(NodeEvent.NODE_ADDED, node);
}
@Override
public void inputChanged(Node node) {
- head.inputChanged(node);
- next.inputChanged(node);
+ head.event(NodeEvent.INPUT_CHANGED, node);
+ next.event(NodeEvent.INPUT_CHANGED, node);
}
@Override
public void usagesDroppedToZero(Node node) {
- head.usagesDroppedToZero(node);
- next.usagesDroppedToZero(node);
+ head.event(NodeEvent.ZERO_USAGES, node);
+ next.event(NodeEvent.ZERO_USAGES, node);
+ }
+
+ @Override
+ public void nodeRemoved(Node node) {
+ head.event(NodeEvent.NODE_REMOVED, node);
+ next.event(NodeEvent.NODE_REMOVED, node);
+ }
+
+ @Override
+ public void changed(NodeEvent e, Node node) {
+ head.event(e, node);
+ next.event(e, node);
}
}
@@ -1023,7 +1072,7 @@
updateNodeCaches(node);
if (nodeEventListener != null) {
- nodeEventListener.nodeAdded(node);
+ nodeEventListener.event(NodeEvent.NODE_ADDED, node);
}
afterRegister(node);
}
@@ -1085,6 +1134,10 @@
nodes[node.id] = null;
nodesDeletedSinceLastCompression++;
+ if (nodeEventListener != null) {
+ nodeEventListener.event(NodeEvent.NODE_ADDED, node);
+ }
+
// nodes aren't removed from the type cache here - they will be removed during iteration
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Mon Nov 06 20:29:49 2017 -0800
@@ -752,7 +752,7 @@
assert !graph.isFrozen();
NodeEventListener listener = graph.nodeEventListener;
if (listener != null) {
- listener.inputChanged(node);
+ listener.event(Graph.NodeEvent.INPUT_CHANGED, node);
}
}
}
@@ -762,7 +762,7 @@
assert !graph.isFrozen();
NodeEventListener listener = graph.nodeEventListener;
if (listener != null && node.isAlive()) {
- listener.usagesDroppedToZero(node);
+ listener.event(Graph.NodeEvent.ZERO_USAGES, node);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotNodeLIRBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -183,8 +183,7 @@
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
- Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
- node.arguments());
+ Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new AArch64BreakpointOp(parameters));
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java Mon Nov 06 20:29:49 2017 -0800
@@ -32,7 +32,6 @@
import org.graalvm.compiler.core.amd64.AMD64AddressNode;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.CounterKey;
@@ -44,6 +43,7 @@
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.CompressionNode;
import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
+import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
@@ -93,76 +93,76 @@
}
@Override
- protected boolean improve(DebugContext debug, AMD64AddressNode addr) {
-
- boolean result = false;
-
- while (super.improve(debug, addr)) {
- result = true;
+ protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) {
+ if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) {
+ return true;
}
if (addr.getScale() == Scale.Times1) {
if (addr.getIndex() instanceof CompressionNode) {
- if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase())) {
+ if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase(), isBaseNegated, isIndexNegated)) {
counterFoldedUncompressDuringAddressLowering.increment(debug);
return true;
}
}
if (addr.getBase() instanceof CompressionNode) {
- if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex())) {
+ if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex(), isBaseNegated, isIndexNegated)) {
counterFoldedUncompressDuringAddressLowering.increment(debug);
return true;
}
}
}
- return result;
+ return false;
+ }
+
+ @Override
+ protected boolean mightBeOptimized(ValueNode value) {
+ return super.mightBeOptimized(value) || value instanceof CompressionNode;
}
- private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other) {
- if (compression.getOp() == CompressionOp.Uncompress) {
- CompressEncoding encoding = compression.getEncoding();
- Scale scale = Scale.fromShift(encoding.getShift());
- if (scale == null) {
+ private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other, boolean isBaseNegated, boolean isIndexNegated) {
+ if (isBaseNegated || isIndexNegated || compression.getOp() != CompressionOp.Uncompress) {
+ return false;
+ }
+
+ CompressEncoding encoding = compression.getEncoding();
+ Scale scale = Scale.fromShift(encoding.getShift());
+ if (scale == null) {
+ return false;
+ }
+
+ if (heapBaseRegister != null && encoding.getBase() == heapBase) {
+ if ((!generatePIC || compression.stamp() instanceof ObjectStamp) && other == null) {
+ // With PIC it is only legal to do for oops since the base value may be
+ // different at runtime.
+ ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister));
+ addr.setBase(base);
+ } else {
return false;
}
-
- if (heapBaseRegister != null && encoding.getBase() == heapBase) {
- if ((!generatePIC || compression.stamp() instanceof ObjectStamp) && other == null) {
- // With PIC it is only legal to do for oops since the base value may be
- // different at runtime.
- ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister));
+ } else if (encoding.getBase() != 0 || (generatePIC && compression.stamp() instanceof KlassPointerStamp)) {
+ if (generatePIC) {
+ if (other == null) {
+ ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long));
addr.setBase(base);
} else {
return false;
}
- } else if (encoding.getBase() != 0 || (generatePIC && compression.stamp() instanceof KlassPointerStamp)) {
- if (generatePIC) {
- if (other == null) {
- ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long));
- addr.setBase(base);
- } else {
- return false;
- }
+ } else {
+ if (updateDisplacement(addr, encoding.getBase(), isBaseNegated)) {
+ addr.setBase(other);
} else {
- long disp = addr.getDisplacement() + encoding.getBase();
- if (NumUtil.isInt(disp)) {
- addr.setDisplacement((int) disp);
- addr.setBase(other);
- } else {
- return false;
- }
+ return false;
}
- } else {
- addr.setBase(other);
}
+ } else {
+ addr.setBase(other);
+ }
- addr.setScale(scale);
- addr.setIndex(compression.getValue());
- return true;
- } else {
- return false;
- }
+ addr.setScale(scale);
+ addr.setIndex(compression.getValue());
+ return true;
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java Mon Nov 06 20:29:49 2017 -0800
@@ -39,7 +39,6 @@
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
-import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
@@ -116,7 +115,7 @@
}
private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
- this(new AMD64LIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
+ this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
}
protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
@@ -363,7 +362,7 @@
Stub stub = getStub();
if (destroysRegisters) {
if (stub != null && stub.preservesRegisters()) {
- Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray();
+ Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
save = emitSaveAllRegisters(savedRegisters, true);
}
}
@@ -567,28 +566,29 @@
@Override
public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
LIRKind inputKind = pointer.getValueKind(LIRKind.class);
- assert inputKind.getPlatformKind() == AMD64Kind.QWORD;
+ LIRKindTool lirKindTool = getLIRKindTool();
+ assert inputKind.getPlatformKind() == lirKindTool.getObjectKind().getPlatformKind();
if (inputKind.isReference(0)) {
// oop
- Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD));
- append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+ Variable result = newVariable(lirKindTool.getNarrowOopKind());
+ append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool()));
return result;
} else {
// metaspace pointer
- Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
+ Variable result = newVariable(lirKindTool.getNarrowPointerKind());
AllocatableValue base = Value.ILLEGAL;
OptionValues options = getResult().getLIR().getOptions();
if (encoding.hasBase() || GeneratePIC.getValue(options)) {
if (GeneratePIC.getValue(options)) {
- Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
+ Variable baseAddress = newVariable(lirKindTool.getWordKind());
AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
append(move);
base = baseAddress;
} else {
- base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase()));
}
}
- append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+ append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool()));
return result;
}
}
@@ -596,35 +596,37 @@
@Override
public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
LIRKind inputKind = pointer.getValueKind(LIRKind.class);
- assert inputKind.getPlatformKind() == AMD64Kind.DWORD;
+ LIRKindTool lirKindTool = getLIRKindTool();
+ assert inputKind.getPlatformKind() == lirKindTool.getNarrowOopKind().getPlatformKind();
if (inputKind.isReference(0)) {
// oop
- Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD));
- append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
+ Variable result = newVariable(lirKindTool.getObjectKind());
+ append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool));
return result;
} else {
// metaspace pointer
- Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
+ LIRKind uncompressedKind = lirKindTool.getWordKind();
+ Variable result = newVariable(uncompressedKind);
AllocatableValue base = Value.ILLEGAL;
OptionValues options = getResult().getLIR().getOptions();
if (encoding.hasBase() || GeneratePIC.getValue(options)) {
if (GeneratePIC.getValue(options)) {
- Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
+ Variable baseAddress = newVariable(uncompressedKind);
AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
append(move);
base = baseAddress;
} else {
- base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase()));
}
}
- append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
+ append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool));
return result;
}
}
@Override
public void emitNullCheck(Value address, LIRFrameState state) {
- if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) {
+ if (address.getValueKind().getPlatformKind() == getLIRKindTool().getNarrowOopKind().getPlatformKind()) {
CompressEncoding encoding = config.getOopEncoding();
Value uncompressed;
if (encoding.getShift() <= 3) {
@@ -635,9 +637,9 @@
uncompressed = emitUncompress(address, encoding, false);
}
append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
- } else {
- super.emitNullCheck(address, state);
+ return;
}
+ super.emitNullCheck(address, state);
}
@Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRKindTool.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,39 @@
+/*
+ * 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.hotspot.amd64;
+
+import jdk.vm.ci.amd64.AMD64Kind;
+import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
+import org.graalvm.compiler.core.common.LIRKind;
+
+public class AMD64HotSpotLIRKindTool extends AMD64LIRKindTool {
+ @Override
+ public LIRKind getNarrowOopKind() {
+ return LIRKind.reference(AMD64Kind.DWORD);
+ }
+
+ @Override
+ public LIRKind getNarrowPointerKind() {
+ return LIRKind.value(AMD64Kind.DWORD);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotMove.java Mon Nov 06 20:29:49 2017 -0800
@@ -24,16 +24,13 @@
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
-import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;
-import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.amd64.AMD64Address;
-import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.debug.GraalError;
@@ -41,10 +38,8 @@
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
-import org.graalvm.compiler.lir.amd64.AMD64Move;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
-import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
@@ -180,91 +175,6 @@
}
}
- public static final class CompressPointer extends AMD64LIRInstruction {
- public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
-
- private final CompressEncoding encoding;
- private final boolean nonNull;
-
- @Def({REG, HINT}) protected AllocatableValue result;
- @Use({REG}) protected AllocatableValue input;
- @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
-
- public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
- super(TYPE);
- this.result = result;
- this.input = input;
- this.baseRegister = baseRegister;
- this.encoding = encoding;
- this.nonNull = nonNull;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
- AMD64Move.move(AMD64Kind.QWORD, crb, masm, result, input);
-
- Register resReg = asRegister(result);
- if (encoding.hasBase() || GeneratePIC.getValue(crb.getOptions())) {
- Register baseReg = asRegister(baseRegister);
- if (!nonNull) {
- masm.testq(resReg, resReg);
- masm.cmovq(ConditionFlag.Equal, resReg, baseReg);
- }
- masm.subq(resReg, baseReg);
- }
-
- if (encoding.hasShift()) {
- masm.shrq(resReg, encoding.getShift());
- }
- }
- }
-
- public static final class UncompressPointer extends AMD64LIRInstruction {
- public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
-
- private final CompressEncoding encoding;
- private final boolean nonNull;
-
- @Def({REG, HINT}) protected AllocatableValue result;
- @Use({REG}) protected AllocatableValue input;
- @Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
-
- public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
- super(TYPE);
- this.result = result;
- this.input = input;
- this.baseRegister = baseRegister;
- this.encoding = encoding;
- this.nonNull = nonNull;
- }
-
- @Override
- public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
- AMD64Move.move(AMD64Kind.DWORD, crb, masm, result, input);
-
- Register resReg = asRegister(result);
- if (encoding.getShift() != 0) {
- masm.shlq(resReg, encoding.getShift());
- }
-
- if (encoding.hasBase() || GeneratePIC.getValue(crb.getOptions())) {
- if (nonNull) {
- masm.addq(resReg, asRegister(baseRegister));
- } else {
- if (!encoding.hasShift()) {
- // if encoding.shift != 0, the flags are already set by the shlq
- masm.testq(resReg, resReg);
- }
-
- Label done = new Label();
- masm.jccb(ConditionFlag.Equal, done);
- masm.addq(resReg, asRegister(baseRegister));
- masm.bind(done);
- }
- }
- }
- }
-
public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) {
CompressEncoding encoding = config.getKlassEncoding();
masm.movl(register, address);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotNodeLIRBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -189,8 +189,7 @@
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
- Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
- node.arguments());
+ Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new AMD64BreakpointOp(parameters));
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotMove.java Mon Nov 06 20:29:49 2017 -0800
@@ -113,8 +113,7 @@
} else {
register = asRegister(result);
}
- int bytes = result.getPlatformKind().getSizeInBytes();
- loadFromConstantTable(crb, masm, bytes, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY);
+ int bytes = loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY);
if (isStack) {
masm.st(register, (SPARCAddress) crb.asAddress(result), bytes);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotNodeLIRBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -162,8 +162,7 @@
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
- Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
- node.arguments());
+ Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new SPARCBreakpointOp(parameters));
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotStrategySwitchOp.java Mon Nov 06 20:29:49 2017 -0800
@@ -77,8 +77,7 @@
boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && SPARCControlFlow.isShortBranch(masm, cbCondPosition, hint, target);
Register scratchRegister = asRegister(scratch);
- final int byteCount = constant.isCompressed() ? 4 : 8;
- loadFromConstantTable(crb, masm, byteCount, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY);
+ loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY);
if (canUseShortBranch) {
CBCOND.emit(masm, conditionFlag, conditionCode == CC.Xcc, keyRegister, scratchRegister, target);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayCopyIntrinsificationTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -160,7 +160,7 @@
}
/**
- * Tests {@link ArrayCopySnippets#checkcastArraycopyWork}.
+ * Tests {@link ArrayCopySnippets#arraycopyCheckcastSnippet}.
*/
@Test
public void testArrayStoreException() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -122,7 +122,7 @@
* Tests compilation requested by Truffle.
*/
@Test
- public void testTruffleCompilation() throws IOException, InterruptedException {
+ public void testTruffleCompilation1() throws IOException, InterruptedException {
testHelper(Collections.emptyList(),
Arrays.asList(
"-Dgraal.CompilationFailureAction=ExitVM",
@@ -130,6 +130,22 @@
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
}
+ /**
+ * Tests that TruffleCompilationExceptionsAreFatal works as expected.
+ */
+ @Test
+ public void testTruffleCompilation2() throws IOException, InterruptedException {
+ Probe[] probes = {
+ new Probe("Exiting VM due to TruffleCompilationExceptionsAreFatal=true", 1),
+ };
+ testHelper(Arrays.asList(probes),
+ Arrays.asList(
+ "-Dgraal.CompilationFailureAction=Silent",
+ "-Dgraal.TruffleCompilationExceptionsAreFatal=true",
+ "-Dgraal.CrashAt=root test1"),
+ "org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
+ }
+
private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose");
private static void testHelper(List<Probe> initialProbes, List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
@@ -149,14 +165,17 @@
}
List<Probe> probes = new ArrayList<>(initialProbes);
- Probe diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
- probes.add(diagnosticProbe);
- probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) {
- @Override
- String test() {
- return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
- }
- });
+ Probe diagnosticProbe = null;
+ if (!extraVmArgs.contains("-Dgraal.TruffleCompilationExceptionsAreFatal=true")) {
+ diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
+ probes.add(diagnosticProbe);
+ probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) {
+ @Override
+ String test() {
+ return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
+ }
+ });
+ }
for (String line : proc.output) {
for (Probe probe : probes) {
@@ -171,38 +190,42 @@
Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
}
}
+ if (diagnosticProbe != null) {
+ String line = diagnosticProbe.lastMatchingLine;
+ int substringStart = line.indexOf(diagnosticProbe.substring);
+ int substringLength = diagnosticProbe.substring.length();
+ String diagnosticOutputZip = line.substring(substringStart + substringLength).trim();
- String diagnosticOutputZip = diagnosticProbe.lastMatchingLine.substring(diagnosticProbe.substring.length()).trim();
-
- List<String> dumpPathEntries = Arrays.asList(dumpPath.list());
+ List<String> dumpPathEntries = Arrays.asList(dumpPath.list());
- File zip = new File(diagnosticOutputZip).getAbsoluteFile();
- Assert.assertTrue(zip.toString(), zip.exists());
- Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
- try {
- int bgv = 0;
- int cfg = 0;
- ZipFile dd = new ZipFile(diagnosticOutputZip);
- List<String> entries = new ArrayList<>();
- for (Enumeration<? extends ZipEntry> 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++;
+ File zip = new File(diagnosticOutputZip).getAbsoluteFile();
+ Assert.assertTrue(zip.toString(), zip.exists());
+ Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
+ try {
+ int bgv = 0;
+ int cfg = 0;
+ ZipFile dd = new ZipFile(diagnosticOutputZip);
+ List<String> entries = new ArrayList<>();
+ for (Enumeration<? extends ZipEntry> 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%n%s", diagnosticOutputZip, entries, proc));
+ if (bgv == 0) {
+ Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
+ }
+ if (cfg == 0) {
+ Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
+ }
+ } finally {
+ zip.delete();
+ dumpPath.delete();
}
- if (cfg == 0) {
- Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
- }
- } finally {
- zip.delete();
- dumpPath.delete();
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ExplicitExceptionTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,23 +22,44 @@
*/
package org.graalvm.compiler.hotspot.test;
-import org.junit.Test;
-
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assume;
+import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
public class ExplicitExceptionTest extends GraalCompilerTest {
private int expectedForeignCallCount;
+ /**
+ * Determines if profiling info for {@code method} indicates an exception was thrown somewhere
+ * in the method. In the case of the {@code -Xcomp} VM option, interpreter execution can be
+ * skipped altogether and other execution engines (e.g., C1) may not record seen exceptions in a
+ * method profile.
+ */
+ private static boolean exceptionWasSeen(ResolvedJavaMethod method) {
+ ProfilingInfo profilingInfo = method.getProfilingInfo();
+ if (profilingInfo != null) {
+ for (int i = 0; i < profilingInfo.getCodeSize(); i++) {
+ if (profilingInfo.getExceptionSeen(i) == TriState.TRUE) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
InstalledCode installedCode = super.getCode(method, graph, forceCompile, installAsDefault, options);
+ Assume.assumeTrue(exceptionWasSeen(method));
assertDeepEquals(expectedForeignCallCount, lastCompiledGraph.getNodes().filter(ForeignCallNode.class).count());
return installedCode;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -24,11 +24,13 @@
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
+import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.phases.HighTier;
@@ -44,6 +46,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
import org.junit.Assume;
+import org.junit.BeforeClass;
/**
* Test on-stack-replacement with locks.
@@ -51,13 +54,28 @@
public class GraalOSRLockTest extends GraalOSRTestBase {
private static boolean TestInSeparateThread = false;
+ private static final String COMPILE_ONLY_FLAG = "-Xcomp";
- public GraalOSRLockTest() {
+ @BeforeClass
+ public static void checkVMArguments() {
try {
Class.forName("java.lang.management.ManagementFactory");
} catch (ClassNotFoundException ex) {
Assume.assumeNoException("cannot check for monitors without java.management JDK9 module", ex);
}
+ /*
+ * Note: The -Xcomp execution mode of the VM will stop most of the OSR test cases from
+ * working as every method is compiled at level3 (followed by level4 on the second
+ * invocation). The tests in this class are written in a way that they expect a method to be
+ * executed at the invocation BCI with the interpreter and then perform an OSR to an
+ * installed nmethod at a given BCI.
+ *
+ */
+ RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
+ List<String> arguments = runtimeMxBean.getInputArguments();
+ for (String arg : arguments) {
+ Assume.assumeFalse(arg.equals(COMPILE_ONLY_FLAG));
+ }
}
// testing only
@@ -438,7 +456,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
return ret;
}
@@ -449,11 +467,11 @@
ReturnValue ret = ReturnValue.FAILURE;
synchronized (lock) {
synchronized (lock1) {
- for (int i = 1; i < limit; i++) {
+ for (int i = 1; i < 10 * limit; i++) {
GraalDirectives.blackhole(i);
- if (i % 1001 == 0) {
+ if (i % 33 == 0) {
ret = ReturnValue.SUCCESS;
- if (GraalDirectives.inCompiledCode() && i + 33 > (limit)) {
+ if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
GraalDirectives.blackhole(ret);
System.gc();
}
@@ -462,7 +480,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code already hereeeeee");
} else {
// lock 1 must be free
if (isMonitorLockHeld(lock1)) {
@@ -519,7 +537,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
return ret;
}
@@ -543,7 +561,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
return ret;
}
@@ -568,7 +586,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
return ret;
}
@@ -646,7 +664,7 @@
synchronized (monitor) {
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
}
return ret;
@@ -670,7 +688,7 @@
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
- throw new Error("Must part of compiled code");
+ throw new Error("Must be part of compiled code");
}
return ret;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRTestBase.java Mon Nov 06 20:29:49 2017 -0800
@@ -35,7 +35,9 @@
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.hotspot.CompilationTask;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.java.BciBlockMapping;
import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
import org.graalvm.compiler.nodes.StructuredGraph;
@@ -76,6 +78,13 @@
HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) method, bci, jvmciEnv);
HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler();
CompilationTask task = new CompilationTask(runtime, compiler, request, true, true, debug.getOptions());
+ if (method instanceof HotSpotResolvedJavaMethod) {
+ HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
+ GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
+ if (((HotSpotResolvedJavaMethod) method).hasCodeAtLevel(bci, config.compilationLevelFullOptimization)) {
+ return;
+ }
+ }
HotSpotCompilationRequestResult result = task.runCompilation(debug);
if (result.getFailure() != null) {
throw new GraalError(result.getFailureMessage());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,7 +37,6 @@
import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopyNode;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.FieldLocationIdentity;
@@ -629,12 +628,6 @@
System.arraycopy(a, 0, b, 0, a.length);
}
- @Test
- public void test61() {
- GraphPredicate checkForUnsafeArrayCopy = graph -> graph.getNodes().filter(UnsafeArrayCopyNode.class).count() > 0 ? 1 : 0;
- testPredicate("test13Snippet", checkForUnsafeArrayCopy, new int[]{});
- }
-
private interface GraphPredicate {
int apply(StructuredGraph graph);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -280,14 +280,19 @@
}
if (offset == -1) {
try {
- offset = getFieldOffset(name, Integer.class, "OopHandle");
+ offset = getFieldOffset(name, Integer.class, "jobject");
isHandle = true;
} catch (JVMCIError e) {
-
+ try {
+ // JDK-8186777
+ offset = getFieldOffset(name, Integer.class, "OopHandle");
+ isHandle = true;
+ } catch (JVMCIError e2) {
+ }
}
}
if (offset == -1) {
- throw new JVMCIError("cannot get offset of field " + name + " with type oop or OopHandle");
+ throw new JVMCIError("cannot get offset of field " + name + " with type oop, jobject or OopHandle");
}
classMirrorOffset = offset;
classMirrorIsHandle = isHandle;
@@ -648,6 +653,8 @@
public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**");
public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, isJDK8 ? "HeapWord**" : "HeapWord* volatile*");
+ public final boolean cmsIncrementalMode = getFlag("CMSIncrementalMode", Boolean.class, false);
+
public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address");
public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java Mon Nov 06 20:29:49 2017 -0800
@@ -266,6 +266,8 @@
unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
}
+ public static final ForeignCallDescriptor GENERIC_ARRAYCOPY = new ForeignCallDescriptor("generic_arraycopy", int.class, Word.class, int.class, Word.class, int.class, int.class);
+
@NodeIntrinsic(ForeignCallNode.class)
private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Mon Nov 06 20:29:49 2017 -0800
@@ -284,7 +284,7 @@
public Object mbean() {
if (graalRuntime instanceof HotSpotGraalRuntime) {
- return ((HotSpotGraalRuntime)graalRuntime).mbean();
+ return ((HotSpotGraalRuntime) graalRuntime).getMBean();
}
return null;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompilerFactory.java Mon Nov 06 20:29:49 2017 -0800
@@ -26,6 +26,8 @@
import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
import java.io.PrintStream;
+import java.util.Map;
+import java.util.Collections;
import org.graalvm.compiler.debug.MethodFilter;
import org.graalvm.compiler.options.Option;
@@ -190,4 +192,11 @@
}
return level;
}
+
+ public Map<String, Object> mbeans() {
+ HotSpotGraalCompiler compiler = createCompiler(HotSpotJVMCIRuntime.runtime());
+ String name = "org.graalvm.compiler.hotspot:type=Options";
+ Object bean = ((HotSpotGraalRuntime) compiler.getGraalRuntime()).getMBean();
+ return Collections.singletonMap(name, bean);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java Mon Nov 06 20:29:49 2017 -0800
@@ -283,10 +283,8 @@
@Override
public javax.management.MBeanInfo getMBeanInfo() {
List<javax.management.MBeanAttributeInfo> attrs = new ArrayList<>();
- if (registered != null) {
- for (OptionDescriptor descr : allOptionDescriptors()) {
- attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
- }
+ for (OptionDescriptor descr : allOptionDescriptors()) {
+ attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
}
javax.management.MBeanOperationInfo[] ops = {
new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Mon Nov 06 20:29:49 2017 -0800
@@ -317,7 +317,7 @@
return compilationProblemsPerAction;
}
- final Object mbean() {
+ Object getMBean() {
return mBean;
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Mon Nov 06 20:29:49 2017 -0800
@@ -28,8 +28,8 @@
import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
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_HANDLE_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;
@@ -41,6 +41,7 @@
import java.lang.ref.Reference;
import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
@@ -90,10 +91,8 @@
import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySlowPathNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyWithSlowPathNode;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyUnrollNode;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopySnippets;
import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -193,7 +192,7 @@
public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
- super(metaAccess, foreignCalls, target);
+ super(metaAccess, foreignCalls, target, runtime.getVMConfig().useCompressedOops);
this.runtime = runtime;
this.registers = registers;
this.constantReflection = constantReflection;
@@ -216,7 +215,6 @@
hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target);
resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
- providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target));
}
public MonitorSnippets.Templates getMonitorSnippets() {
@@ -315,10 +313,8 @@
}
} else if (n instanceof ArrayCopyNode) {
arraycopySnippets.lower((ArrayCopyNode) n, tool);
- } else if (n instanceof ArrayCopySlowPathNode) {
- arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool);
- } else if (n instanceof ArrayCopyUnrollNode) {
- arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool);
+ } else if (n instanceof ArrayCopyWithSlowPathNode) {
+ arraycopySnippets.lower((ArrayCopyWithSlowPathNode) n, tool);
} else if (n instanceof G1PreWriteBarrier) {
writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
} else if (n instanceof G1PostWriteBarrier) {
@@ -495,20 +491,18 @@
}
}
- @Override
- protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
- if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
- return HotSpotNarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding());
- }
- return super.loadStamp(stamp, kind, compressible);
+ private CompressEncoding getOopEncoding() {
+ return runtime.getVMConfig().getOopEncoding();
}
@Override
- protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
- if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
- return new HotSpotCompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding());
- }
- return super.implicitLoadConvert(kind, value, compressible);
+ protected Stamp loadCompressedStamp(ObjectStamp stamp) {
+ return HotSpotNarrowOopStamp.compressed(stamp, getOopEncoding());
+ }
+
+ @Override
+ protected ValueNode newCompressionNode(CompressionOp op, ValueNode value) {
+ return new HotSpotCompressionNode(op, value, getOopEncoding());
}
@Override
@@ -519,14 +513,6 @@
}
@Override
- protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
- if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
- return new HotSpotCompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding());
- }
- return super.implicitStoreConvert(kind, value, compressible);
- }
-
- @Override
protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) {
/*
* Anchor the read of the element klass to the cfg, because it is only valid when arrayClass
@@ -800,4 +786,9 @@
public int arrayLengthOffset() {
return runtime.getVMConfig().arrayOopDescLengthOffset();
}
+
+ @Override
+ protected final JavaKind getStorageKind(ResolvedJavaField field) {
+ return field.getJavaKind();
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java Mon Nov 06 20:29:49 2017 -0800
@@ -39,6 +39,7 @@
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
@@ -68,6 +69,7 @@
import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
@@ -316,8 +318,8 @@
private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
- ValueNode scaledIndex = b.add(new LeftShiftNode(index, b.add(ConstantNode.forInt(shift))));
- ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forInt(config.constantPoolSize))));
+ ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long)), b.add(ConstantNode.forInt(shift))));
+ ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
boolean notCompressible = false;
ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Mon Nov 06 20:29:49 2017 -0800
@@ -34,6 +34,7 @@
import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT;
import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.GENERIC_ARRAYCOPY;
import static org.graalvm.compiler.hotspot.HotSpotBackend.IC_MISS_HANDLER;
import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
import static org.graalvm.compiler.hotspot.HotSpotBackend.INVOCATION_EVENT;
@@ -85,7 +86,6 @@
import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.NEW_INSTANCE_C;
import static org.graalvm.compiler.hotspot.stubs.StubUtil.VM_MESSAGE_C;
import static org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub.EXCEPTION_HANDLER_FOR_RETURN_ADDRESS;
-import static org.graalvm.compiler.nodes.NamedLocationIdentity.any;
import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
import static org.graalvm.compiler.replacements.Log.LOG_OBJECT;
import static org.graalvm.compiler.replacements.Log.LOG_PRIMITIVE;
@@ -97,6 +97,7 @@
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
+import static org.graalvm.word.LocationIdentity.any;
import java.util.EnumMap;
@@ -213,7 +214,7 @@
// c_rarg4 - oop ckval (super_klass)
// return: 0 = success, n = number of copied elements xor'd with -1.
ForeignCallDescriptor desc = new ForeignCallDescriptor(name, int.class, Word.class, Word.class, Word.class, Word.class, Word.class);
- LocationIdentity killed = NamedLocationIdentity.getArrayLocation(JavaKind.Object);
+ LocationIdentity killed = NamedLocationIdentity.any();
registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc;
}
@@ -333,6 +334,7 @@
registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
+ registerForeignCall(GENERIC_ARRAYCOPY, c.genericArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
if (c.useMultiplyToLenIntrinsic()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/aot/ResolveDynamicConstantNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -28,6 +28,7 @@
import org.graalvm.word.LocationIdentity;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
@@ -35,7 +36,7 @@
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
-@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
+@NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {InputType.Memory})
public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
public static final NodeClass<ResolveDynamicConstantNode> TYPE = NodeClass.create(ResolveDynamicConstantNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileBranchNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -71,6 +71,15 @@
return branchCondition != null;
}
+ @Override
+ protected boolean canBeMergedWith(ProfileNode p) {
+ if (p instanceof ProfileBranchNode) {
+ ProfileBranchNode that = (ProfileBranchNode) p;
+ return this.method.equals(that.method) && this.bci == that.bci;
+ }
+ return false;
+ }
+
/**
* Gathers all the {@link ProfileBranchNode}s that are inputs to the
* {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileInvokeNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -37,6 +37,15 @@
super(TYPE, method, freqLog, probabilityLog);
}
+ @Override
+ protected boolean canBeMergedWith(ProfileNode p) {
+ if (p instanceof ProfileInvokeNode) {
+ ProfileInvokeNode that = (ProfileInvokeNode) p;
+ return this.method.equals(that.method);
+ }
+ return false;
+ }
+
/**
* Gathers all the {@link ProfileInvokeNode}s that are inputs to the
* {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -24,11 +24,17 @@
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
+import static org.graalvm.compiler.nodes.util.GraphUtil.removeFixedWithUnusedInputs;
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.iterators.NodeIterable;
+import org.graalvm.compiler.graph.spi.Simplifiable;
+import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.AbstractMergeNode;
+import org.graalvm.compiler.nodes.ControlSplitNode;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
@@ -41,7 +47,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
@NodeInfo(cycles = CYCLES_IGNORED, cyclesRationale = "profiling should be ignored", size = SIZE_IGNORED, sizeRationale = "profiling should be ignored")
-public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowerable {
+public abstract class ProfileNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
public static class Options {
@Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)//
public static final OptionKey<Boolean> ProbabilisticProfiling = new OptionKey<>(true);
@@ -54,19 +60,21 @@
// Only used if ProbabilisticProfiling == true and may be ignored by lowerer.
@OptionalInput protected ValueNode random;
- // logarithm base 2 of the profile probability
+ // Logarithm base 2 of the profile probability.
protected int probabilityLog;
+ // Step value to add to the profile counter.
+ protected int step;
+
protected ProfileNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, ResolvedJavaMethod method, int probabilityLog) {
super(c, StampFactory.forVoid());
this.method = method;
this.probabilityLog = probabilityLog;
+ this.step = 1;
}
public ProfileNode(ResolvedJavaMethod method, int probabilityLog) {
- super(TYPE, StampFactory.forVoid());
- this.method = method;
- this.probabilityLog = probabilityLog;
+ this(TYPE, method, probabilityLog);
}
@Override
@@ -92,6 +100,14 @@
this.random = r;
}
+ public int getStep() {
+ return step;
+ }
+
+ public void setStep(int s) {
+ step = s;
+ }
+
/**
* Get the logarithm base 2 of the profile probability.
*/
@@ -106,4 +122,25 @@
public static NodeIterable<ProfileNode> getProfileNodes(StructuredGraph graph) {
return graph.getNodes().filter(ProfileNode.class);
}
+
+ protected abstract boolean canBeMergedWith(ProfileNode p);
+
+ @Override
+ public void simplify(SimplifierTool tool) {
+ for (Node p = predecessor(); p != null; p = p.predecessor()) {
+ // Terminate search when we hit a control split or merge.
+ if (p instanceof ControlSplitNode || p instanceof AbstractMergeNode) {
+ break;
+ }
+ if (p instanceof ProfileNode) {
+ ProfileNode that = (ProfileNode) p;
+ if (this.canBeMergedWith(that)) {
+ that.setStep(this.getStep() + that.getStep());
+ removeFixedWithUnusedInputs(this);
+ tool.addToWorkList(that);
+ break;
+ }
+ }
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/profiling/ProfileWithNotificationNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -28,7 +28,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
@NodeInfo
-public class ProfileWithNotificationNode extends ProfileNode {
+public abstract class ProfileWithNotificationNode extends ProfileNode {
public static final NodeClass<ProfileWithNotificationNode> TYPE = NodeClass.create(ProfileWithNotificationNode.class);
protected int freqLog;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/OnStackReplacementPhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,10 +22,16 @@
*/
package org.graalvm.compiler.hotspot.phases;
+import static jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.cfg.Loop;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugContext;
@@ -37,13 +43,15 @@
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.AbstractBeginNode;
-import org.graalvm.compiler.nodes.AbstractLocalNode;
import org.graalvm.compiler.nodes.EntryMarkerNode;
import org.graalvm.compiler.nodes.EntryProxyNode;
+import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FrameState;
+import org.graalvm.compiler.nodes.LogicNode;
import org.graalvm.compiler.nodes.LoopBeginNode;
import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.StartNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
@@ -53,6 +61,7 @@
import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
import org.graalvm.compiler.nodes.extended.OSRStartNode;
import org.graalvm.compiler.nodes.java.AccessMonitorNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.java.MonitorEnterNode;
import org.graalvm.compiler.nodes.java.MonitorExitNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
@@ -172,15 +181,32 @@
if (value instanceof EntryProxyNode) {
EntryProxyNode proxy = (EntryProxyNode) value;
/*
- * we need to drop the stamp since the types we see during OSR may be too precise
- * (if a branch was not parsed for example).
+ * We need to drop the stamp since the types we see during OSR may be too precise
+ * (if a branch was not parsed for example). In cases when this is possible, we
+ * insert a guard and narrow the OSRLocal stamp at its usages.
*/
- Stamp s = proxy.stamp().unrestricted();
- AbstractLocalNode osrLocal = null;
+ Stamp narrowedStamp = proxy.value().stamp();
+ Stamp unrestrictedStamp = proxy.stamp().unrestricted();
+ ValueNode osrLocal;
if (i >= localsSize) {
- osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, s));
+ osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp));
} else {
- osrLocal = graph.addOrUnique(new OSRLocalNode(i, s));
+ osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp));
+ }
+ // Speculate on the OSRLocal stamps that could be more precise.
+ OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i);
+ if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) {
+ // Add guard.
+ LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null));
+ JavaConstant constant = graph.getSpeculationLog().speculate(reason);
+ FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false));
+ graph.addAfterFixed(osrStart, guard);
+
+ // Replace with a more specific type at usages.
+ // We know that we are at the root,
+ // so we need to replace the proxy in the state.
+ proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState);
+ osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard));
}
proxy.replaceAndDelete(osrLocal);
} else {
@@ -268,4 +294,30 @@
public float codeSizeIncrease() {
return 5.0f;
}
+
+ private static class OSRLocalSpeculationReason implements SpeculationReason {
+ private int bci;
+ private Stamp speculatedStamp;
+ private int localIndex;
+
+ OSRLocalSpeculationReason(int bci, Stamp speculatedStamp, int localIndex) {
+ this.bci = bci;
+ this.speculatedStamp = speculatedStamp;
+ this.localIndex = localIndex;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof OSRLocalSpeculationReason) {
+ OSRLocalSpeculationReason that = (OSRLocalSpeculationReason) obj;
+ return this.bci == that.bci && this.speculatedStamp.equals(that.speculatedStamp) && this.localIndex == that.localIndex;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return (bci << 16) ^ speculatedStamp.hashCode() ^ localIndex;
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java Mon Nov 06 20:29:49 2017 -0800
@@ -670,6 +670,11 @@
}
@Fold
+ public static boolean useCMSIncrementalMode(@InjectedParameter GraalHotSpotVMConfig config) {
+ return config.cmsIncrementalMode;
+ }
+
+ @Fold
public static boolean useCompressedOops(@InjectedParameter GraalHotSpotVMConfig config) {
return config.useCompressedOops;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HubGetClassNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -71,7 +71,7 @@
return null;
} else {
MetaAccessProvider metaAccess = tool.getMetaAccess();
- if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(graph().getOptions())) {
+ if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(tool.getOptions())) {
ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant());
if (exactType != null) {
return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/IdentityHashCodeNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -67,7 +67,7 @@
if (object.isConstant()) {
assert object.stamp() instanceof AbstractObjectStamp;
JavaConstant c = (JavaConstant) object.asConstant();
- if (ImmutableCode.getValue(getOptions())) {
+ if (ImmutableCode.getValue(tool.getOptions())) {
return this;
}
JavaConstant identityHashCode = null;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySlowPathNode.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2015, 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.replacements.arraycopy;
-
-import jdk.vm.ci.code.BytecodeFrame;
-import jdk.vm.ci.meta.JavaKind;
-
-import static org.graalvm.word.LocationIdentity.any;
-
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.hotspot.word.KlassPointer;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.NamedLocationIdentity;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.type.StampTool;
-import org.graalvm.compiler.replacements.SnippetTemplate;
-import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
-import org.graalvm.word.LocationIdentity;
-
-@NodeInfo(allowedUsageTypes = InputType.Memory)
-public final class ArrayCopySlowPathNode extends BasicArrayCopyNode {
-
- public static final NodeClass<ArrayCopySlowPathNode> TYPE = NodeClass.create(ArrayCopySlowPathNode.class);
-
- private final SnippetTemplate.SnippetInfo snippet;
-
- /**
- * Extra context for the slow path snippet.
- */
- private final Object argument;
-
- /**
- * AOT compilation requires klass constants to be exposed after the first lowering to be handled
- * automatically. Lowering for {@link ArrayCopySlowPathNode}, with snippet ==
- * {@link ArrayCopySnippets#arraycopyPredictedObjectWork}, requires a klass of Object[]. For
- * other snippets {@link #predictedKlass} is a null constant.
- */
- @Input protected ValueNode predictedKlass;
-
- public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode predictedKlass, JavaKind elementKind,
- SnippetTemplate.SnippetInfo snippet, Object argument) {
- super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
- assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
- this.snippet = snippet;
- this.argument = argument;
- this.predictedKlass = predictedKlass;
- }
-
- @NodeIntrinsic
- public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer predictedKlass,
- @ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet, @ConstantNodeParameter Object argument);
-
- public SnippetTemplate.SnippetInfo getSnippet() {
- return snippet;
- }
-
- public Object getArgument() {
- return argument;
- }
-
- @Override
- public LocationIdentity getLocationIdentity() {
- if (elementKind != null) {
- return NamedLocationIdentity.getArrayLocation(elementKind);
- }
- return any();
- }
-
- public void setBci(int bci) {
- this.bci = bci;
- }
-
- public ValueNode getPredictedKlass() {
- return predictedKlass;
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java Mon Nov 06 20:29:49 2017 -0800
@@ -28,11 +28,12 @@
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayClassElementOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypePrimitiveInPlace;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHub;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
+import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
@@ -47,10 +48,8 @@
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
-import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.CallTargetNode;
-import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.InvokeNode;
@@ -65,8 +64,10 @@
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.ReplacementsUtil;
import org.graalvm.compiler.replacements.SnippetCounter;
import org.graalvm.compiler.replacements.SnippetCounter.Group;
+import org.graalvm.compiler.replacements.SnippetIntegerHistogram;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
@@ -79,16 +80,208 @@
import org.graalvm.word.WordFactory;
import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
public class ArrayCopySnippets implements Snippets {
+ private enum ArrayCopyTypeCheck {
+ UNDEFINED_ARRAY_TYPE_CHECK,
+ // we know that both objects are arrays and have the same type
+ NO_ARRAY_TYPE_CHECK,
+ // can be used when we know that one of the objects is a primitive array
+ HUB_BASED_ARRAY_TYPE_CHECK,
+ // must be used when we don't have sufficient information to use one of the others
+ LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK
+ }
+
+ @Snippet
+ public static void arraycopyZeroLengthSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
+ @ConstantParameter Counters counters) {
+ Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+ Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+ checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
+ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
+ counters.zeroLengthStaticCounter.inc();
+ }
+
+ @Snippet
+ public static void arraycopyExactSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
+ @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter elementKindCounter, @ConstantParameter SnippetCounter elementKindCopiedCounter,
+ @ConstantParameter Counters counters) {
+ Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+ Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+ checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
+ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
+ incrementLengthCounter(length, counters);
+
+ elementKindCounter.inc();
+ elementKindCopiedCounter.add(length);
+ ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
+ }
+
+ @Snippet
+ public static void arraycopyUnrolledSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
+ @ConstantParameter JavaKind elementKind, @ConstantParameter int unrolledLength, @ConstantParameter Counters counters) {
+ Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+ Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+ checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
+ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
+ incrementLengthCounter(length, counters);
+
+ unrolledArraycopyWork(nonNullSrc, srcPos, nonNullDest, destPos, unrolledLength, elementKind);
+ }
+
+ @Snippet
+ public static void arraycopyCheckcastSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
+ @ConstantParameter Counters counters, @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) {
+ Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+ Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+ checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
+ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
+ incrementLengthCounter(length, counters);
+
+ ArrayCopyWithSlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind);
+ }
+
+ @Snippet
+ public static void arraycopyGenericSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, @ConstantParameter Counters counters,
+ @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) {
+ Object nonNullSrc = GraalDirectives.guardingNonNull(src);
+ Object nonNullDest = GraalDirectives.guardingNonNull(dest);
+ checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
+ checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
+ incrementLengthCounter(length, counters);
+
+ ArrayCopyWithSlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind);
+ }
+
+ @Snippet
+ public static void arraycopyNativeSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
+ // all checks are done in the native method, so no need to emit additional checks here
+ incrementLengthCounter(length, counters);
+ counters.systemArraycopyCounter.inc();
+ counters.systemArraycopyCopiedCounter.add(length);
+
+ System.arraycopy(src, srcPos, dest, destPos, length);
+ }
+
+ @Fold
+ static LocationIdentity getArrayLocation(JavaKind kind) {
+ return NamedLocationIdentity.getArrayLocation(kind);
+ }
+
+ private static void unrolledArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, JavaKind elementKind) {
+ int scale = arrayIndexScale(elementKind);
+ int arrayBaseOffset = arrayBaseOffset(elementKind);
+ LocationIdentity arrayLocation = getArrayLocation(elementKind);
+
+ long sourceOffset = arrayBaseOffset + (long) srcPos * scale;
+ long destOffset = arrayBaseOffset + (long) destPos * scale;
+ long position = 0;
+ long delta = scale;
+ if (probability(NOT_FREQUENT_PROBABILITY, nonNullSrc == nonNullDest && srcPos < destPos)) {
+ // bad aliased case so we need to copy the array from back to front
+ position = (long) (length - 1) * scale;
+ delta = -delta;
+ }
+
+ // the length was already checked before - we can emit unconditional instructions
+ ExplodeLoopNode.explodeLoop();
+ for (int iteration = 0; iteration < length; iteration++) {
+ Object value = RawLoadNode.load(nonNullSrc, sourceOffset + position, elementKind, arrayLocation);
+ RawStoreNode.storeObject(nonNullDest, destOffset + position, value, elementKind, arrayLocation, false);
+ position += delta;
+ }
+ }
+
+ @Snippet(allowPartialIntrinsicArgumentMismatch = true)
+ public static void checkcastArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
+ if (probability(FREQUENT_PROBABILITY, length > 0)) {
+ Object nonNullSrc = PiNode.asNonNullObject(src);
+ Object nonNullDest = PiNode.asNonNullObject(dest);
+ KlassPointer srcKlass = loadHub(nonNullSrc);
+ KlassPointer destKlass = loadHub(nonNullDest);
+ if (probability(LIKELY_PROBABILITY, srcKlass == destKlass)) {
+ // no storecheck required.
+ counters.objectCheckcastSameTypeCounter.inc();
+ counters.objectCheckcastSameTypeCopiedCounter.add(length);
+ ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
+ } else {
+ KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
+ Word superCheckOffset = WordFactory.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
+
+ counters.objectCheckcastDifferentTypeCounter.inc();
+ counters.objectCheckcastDifferentTypeCopiedCounter.add(length);
+
+ int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
+ if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) {
+ /*
+ * the stub doesn't throw the ArrayStoreException, but returns the number of
+ * copied elements (xor'd with -1).
+ */
+ copiedElements ^= -1;
+ System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
+ }
+ }
+ }
+ }
+
+ @Snippet(allowPartialIntrinsicArgumentMismatch = true)
+ public static void genericArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
+ if (probability(FREQUENT_PROBABILITY, length > 0)) {
+ counters.genericArraycopyDifferentTypeCounter.inc();
+ counters.genericArraycopyDifferentTypeCopiedCounter.add(length);
+ int copiedElements = GenericArrayCopyCallNode.genericArraycopy(src, srcPos, dest, destPos, length);
+ if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) {
+ /*
+ * the stub doesn't throw the ArrayStoreException, but returns the number of copied
+ * elements (xor'd with -1).
+ */
+ copiedElements ^= -1;
+ System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements);
+ }
+ }
+ }
+
+ private static void incrementLengthCounter(int length, Counters counters) {
+ counters.lengthHistogram.inc(length);
+ }
+
+ private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length, Counters counters) {
+ if (probability(SLOW_PATH_PROBABILITY, srcPos < 0) ||
+ probability(SLOW_PATH_PROBABILITY, destPos < 0) ||
+ probability(SLOW_PATH_PROBABILITY, length < 0) ||
+ probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length) ||
+ probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) {
+ counters.checkAIOOBECounter.inc();
+ DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+ }
+ counters.checkSuccessCounter.inc();
+ }
+
+ private static void checkArrayTypes(Object nonNullSrc, Object nonNullDest, ArrayCopyTypeCheck arrayTypeCheck) {
+ if (arrayTypeCheck == ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK) {
+ // nothing to do
+ } else if (arrayTypeCheck == ArrayCopyTypeCheck.HUB_BASED_ARRAY_TYPE_CHECK) {
+ KlassPointer srcHub = loadHub(nonNullSrc);
+ KlassPointer destHub = loadHub(nonNullDest);
+ if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
+ DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+ }
+ } else if (arrayTypeCheck == ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK) {
+ KlassPointer srcHub = loadHub(nonNullSrc);
+ KlassPointer destHub = loadHub(nonNullDest);
+ checkArrayType(srcHub);
+ checkArrayType(destHub);
+ } else {
+ ReplacementsUtil.staticAssert(false, "unknown array type check");
+ }
+ }
+
private static int checkArrayType(KlassPointer nonNullHub) {
int layoutHelper = readLayoutHelper(nonNullHub);
if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) {
@@ -97,528 +290,228 @@
return layoutHelper;
}
- private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length, Counters counters) {
- if (probability(SLOW_PATH_PROBABILITY, srcPos < 0)) {
- counters.checkAIOOBECounter.inc();
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- if (probability(SLOW_PATH_PROBABILITY, destPos < 0)) {
- counters.checkAIOOBECounter.inc();
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- if (probability(SLOW_PATH_PROBABILITY, length < 0)) {
- counters.checkAIOOBECounter.inc();
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- if (probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length)) {
- counters.checkAIOOBECounter.inc();
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- if (probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) {
- counters.checkAIOOBECounter.inc();
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- counters.checkSuccessCounter.inc();
- }
-
- @Snippet
- public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- KlassPointer srcHub = loadHub(nonNullSrc);
- KlassPointer destHub = loadHub(nonNullDest);
- checkArrayType(srcHub);
- checkArrayType(destHub);
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- counters.zeroLengthStaticCounter.inc();
- }
-
- @Snippet
- public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter counter,
- @ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- counter.inc();
- copiedCounter.add(length);
- ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
- if (length == 0) {
- counters.zeroLengthDynamicCounter.inc();
- } else {
- counters.nonZeroLengthDynamicCounter.inc();
- counters.nonZeroLengthDynamicCopiedCounter.add(length);
- }
- }
-
- /**
- * This intrinsic is useful for the case where we know something statically about one of the
- * inputs but not the other.
- */
- @Snippet
- public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind,
- @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- KlassPointer srcHub = loadHub(nonNullSrc);
- KlassPointer destHub = loadHub(nonNullDest);
- if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
- }
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- counter.inc();
- copiedCounter.add(length);
- ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
- if (length == 0) {
- counters.zeroLengthDynamicCounter.inc();
- } else {
- counters.nonZeroLengthDynamicCounter.inc();
- counters.nonZeroLengthDynamicCopiedCounter.add(length);
- }
- }
-
- @Snippet
- public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass,
- @ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
- if (length > 0) {
- KlassPointer srcHub = loadHub(PiNode.asNonNullObject(nonNullSrc));
- KlassPointer destHub = loadHub(PiNode.asNonNullObject(nonNullDest));
- if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) {
- counter.inc();
- copiedCounter.add(length);
- counters.predictedObjectArrayCopyFastPathCounter.inc();
- counters.predictedObjectArrayCopyFastPathCopiedCounter.add(length);
- ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
- } else {
- counters.predictedObjectArrayCopySlowPathCounter.inc();
- counters.predictedObjectArrayCopySlowPathCopiedCounter.add(length);
- System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
- }
- }
- }
-
- /**
- * This is the basic template for the full arraycopy checks, including a check that the
- * underlying type is really an array type.
- */
- @Snippet
- public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, KlassPointer predictedKlass, @ConstantParameter JavaKind elementKind,
- @ConstantParameter SnippetInfo slowPath, @ConstantParameter Object slowPathArgument, @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- KlassPointer srcHub = loadHub(nonNullSrc);
- KlassPointer destHub = loadHub(nonNullDest);
- checkArrayType(srcHub);
- checkArrayType(destHub);
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- if (length == 0) {
- counters.zeroLengthDynamicCounter.inc();
- } else {
- counters.nonZeroLengthDynamicCounter.inc();
- counters.nonZeroLengthDynamicCopiedCounter.add(length);
- }
- ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, predictedKlass, elementKind, slowPath, slowPathArgument);
- }
-
- /**
- * Snippet for unrolled arraycopy.
- */
- @Snippet
- public static void arraycopyUnrolledIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter int unrolledLength, @ConstantParameter JavaKind elementKind,
- @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- if (length == 0) {
- counters.zeroLengthDynamicCounter.inc();
- } else {
- counters.nonZeroLengthDynamicCounter.inc();
- counters.nonZeroLengthDynamicCopiedCounter.add(length);
- }
- ArrayCopyUnrollNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, unrolledLength, elementKind);
- }
-
- @Snippet
- public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantParameter Counters counters) {
- if (length > 0) {
- KlassPointer destKlass = loadHub(nonNullDest);
- KlassPointer srcKlass = loadHub(nonNullSrc);
- if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) {
- // no storecheck required.
- counters.objectCheckcastSameTypeCounter.inc();
- counters.objectCheckcastSameTypeCopiedCounter.add(length);
- ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
- } else {
- KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
- Word superCheckOffset = WordFactory.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
- counters.objectCheckcastCounter.inc();
- counters.objectCheckcastCopiedCounter.add(length);
- int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
- if (copiedElements != 0) {
- /*
- * the checkcast stub doesn't throw the ArrayStoreException, but returns the
- * number of copied elements (xor'd with -1).
- */
- copiedElements ^= -1;
- System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
- }
- }
- }
- }
-
- @Snippet
- public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
- Object nonNullSrc = GraalDirectives.guardingNonNull(src);
- Object nonNullDest = GraalDirectives.guardingNonNull(dest);
- KlassPointer srcHub = loadHub(nonNullSrc);
- KlassPointer destHub = loadHub(nonNullDest);
- if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) {
- int layoutHelper = checkArrayType(srcHub);
- final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace(INJECTED_VMCONFIG)) == 0);
- checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
- if (probability(FAST_PATH_PROBABILITY, isObjectArray)) {
- counters.genericObjectExactCallCounter.inc();
- counters.genericObjectExactCallCopiedCounter.add(length);
- ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, JavaKind.Object);
- } else {
- counters.genericPrimitiveCallCounter.inc();
- counters.genericPrimitiveCallCopiedCounter.add(length);
- UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper);
- }
- } else {
- counters.systemArraycopyCounter.inc();
- counters.systemArraycopyCopiedCounter.add(length);
- System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
- }
- }
-
- @Fold
- static LocationIdentity getArrayLocation(JavaKind kind) {
- return NamedLocationIdentity.getArrayLocation(kind);
- }
-
- @Snippet
- public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter JavaKind elementKind) {
- final int scale = arrayIndexScale(elementKind);
- int arrayBaseOffset = arrayBaseOffset(elementKind);
- LocationIdentity arrayLocation = getArrayLocation(elementKind);
- if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case
- long start = (long) (length - 1) * scale;
- long i = start;
- ExplodeLoopNode.explodeLoop();
- for (int iteration = 0; iteration < length; iteration++) {
- if (i >= 0) {
- Object a = RawLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
- RawStoreNode.storeObject(nonNullDest, arrayBaseOffset + i + (long) destPos * scale, a, elementKind, arrayLocation, false);
- i -= scale;
- }
- }
- } else {
- long end = (long) length * scale;
- long i = 0;
- ExplodeLoopNode.explodeLoop();
- for (int iteration = 0; iteration < length; iteration++) {
- if (i < end) {
- Object a = RawLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
- RawStoreNode.storeObject(nonNullDest, arrayBaseOffset + i + (long) destPos * scale, a, elementKind, arrayLocation, false);
- i += scale;
- }
- }
- }
- }
-
static class Counters {
final SnippetCounter checkSuccessCounter;
final SnippetCounter checkAIOOBECounter;
- final SnippetCounter objectCheckcastCounter;
- final SnippetCounter objectCheckcastSameTypeCounter;
- final SnippetCounter predictedObjectArrayCopySlowPathCounter;
- final SnippetCounter predictedObjectArrayCopyFastPathCounter;
+ final SnippetCounter zeroLengthStaticCounter;
+ final SnippetIntegerHistogram lengthHistogram;
- final SnippetCounter genericPrimitiveCallCounter;
- final SnippetCounter genericObjectExactCallCounter;
final SnippetCounter systemArraycopyCounter;
-
- final SnippetCounter zeroLengthStaticCounter;
- final SnippetCounter zeroLengthDynamicCounter;
- final SnippetCounter nonZeroLengthDynamicCounter;
-
- final SnippetCounter nonZeroLengthDynamicCopiedCounter;
- final SnippetCounter genericPrimitiveCallCopiedCounter;
- final SnippetCounter genericObjectExactCallCopiedCounter;
final SnippetCounter systemArraycopyCopiedCounter;
- final SnippetCounter objectCheckcastCopiedCounter;
+ final SnippetCounter genericArraycopyDifferentTypeCopiedCounter;
+ final SnippetCounter genericArraycopyDifferentTypeCounter;
+
final SnippetCounter objectCheckcastSameTypeCopiedCounter;
- final SnippetCounter predictedObjectArrayCopySlowPathCopiedCounter;
- final SnippetCounter predictedObjectArrayCopyFastPathCopiedCounter;
+ final SnippetCounter objectCheckcastSameTypeCounter;
+ final SnippetCounter objectCheckcastDifferentTypeCopiedCounter;
+ final SnippetCounter objectCheckcastDifferentTypeCounter;
final EnumMap<JavaKind, SnippetCounter> arraycopyCallCounters = new EnumMap<>(JavaKind.class);
- final EnumMap<JavaKind, SnippetCounter> arraycopyCounters = new EnumMap<>(JavaKind.class);
-
final EnumMap<JavaKind, SnippetCounter> arraycopyCallCopiedCounters = new EnumMap<>(JavaKind.class);
- final EnumMap<JavaKind, SnippetCounter> arraycopyCopiedCounters = new EnumMap<>(JavaKind.class);
Counters(SnippetCounter.Group.Factory factory) {
final Group checkCounters = factory.createSnippetCounterGroup("System.arraycopy checkInputs");
- final Group counters = factory.createSnippetCounterGroup("System.arraycopy");
- final Group copiedCounters = factory.createSnippetCounterGroup("System.arraycopy copied elements");
- final Group lengthCounters = factory.createSnippetCounterGroup("System.arraycopy 0-length checks");
+ final Group callCounters = factory.createSnippetCounterGroup("System.arraycopy calls");
+ final Group copiedElementsCounters = factory.createSnippetCounterGroup("System.arraycopy copied elements");
+ final Group lengthCounters = factory.createSnippetCounterGroup("System.arraycopy with 0-length");
checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess");
checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE");
- objectCheckcastCounter = new SnippetCounter(counters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
- objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
- predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]{slow-path}", "used System.arraycopy slow path for predicted Object[] arrays");
- predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
- genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
- genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
- systemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy");
+ zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-length copy static", "calls where the length is statically 0");
+ lengthHistogram = new SnippetIntegerHistogram(lengthCounters, 2, "length", "length");
- zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0");
- zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0");
- nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
+ systemArraycopyCounter = new SnippetCounter(callCounters, "native System.arraycopy", "JNI-based System.arraycopy call");
+ systemArraycopyCopiedCounter = new SnippetCounter(copiedElementsCounters, "native System.arraycopy", "JNI-based System.arraycopy call");
+
+ genericArraycopyDifferentTypeCounter = new SnippetCounter(callCounters, "generic[] stub", "generic arraycopy stub");
+ genericArraycopyDifferentTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "generic[] stub", "generic arraycopy stub");
- nonZeroLengthDynamicCopiedCounter = new SnippetCounter(copiedCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
- genericPrimitiveCallCopiedCounter = new SnippetCounter(copiedCounters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
- genericObjectExactCallCopiedCounter = new SnippetCounter(copiedCounters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
- systemArraycopyCopiedCounter = new SnippetCounter(copiedCounters, "genericObject", "call to System.arraycopy");
+ objectCheckcastSameTypeCounter = new SnippetCounter(callCounters, "checkcast object[] (same-type)", "checkcast object[] stub but src.klass == dest.klass Object[] arrays");
+ objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "checkcast object[] (same-type)", "checkcast object[] stub but src.klass == dest.klass Object[] arrays");
+ objectCheckcastDifferentTypeCounter = new SnippetCounter(callCounters, "checkcast object[] (store-check)", "checkcast object[] stub with store check");
+ objectCheckcastDifferentTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "checkcast object[] (store-check)", "checkcast object[] stub with store check");
- objectCheckcastCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
- objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
- predictedObjectArrayCopySlowPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{slow-path}",
- "used System.arraycopy slow path for predicted Object[] arrays");
- predictedObjectArrayCopyFastPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
- createArraycopyCounter(JavaKind.Byte, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Boolean, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Char, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Short, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Int, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Long, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Float, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Double, counters, copiedCounters);
- createArraycopyCounter(JavaKind.Object, counters, copiedCounters);
+ createArraycopyCounter(JavaKind.Byte, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Boolean, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Char, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Short, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Int, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Long, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Float, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Double, callCounters, copiedElementsCounters);
+ createArraycopyCounter(JavaKind.Object, callCounters, copiedElementsCounters);
}
void createArraycopyCounter(JavaKind kind, Group counters, Group copiedCounters) {
- arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
- arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
-
- arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
- arraycopyCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
+ arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[] stub", "arraycopy call for " + kind + "[] arrays"));
+ arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[] stub", "arraycopy call for " + kind + "[] arrays"));
}
}
public static class Templates extends SnippetTemplate.AbstractTemplates {
+ private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGenericSnippet");
+ private final SnippetInfo arraycopyUnrolledSnippet = snippet("arraycopyUnrolledSnippet");
+ private final SnippetInfo arraycopyExactSnippet = snippet("arraycopyExactSnippet");
+ private final SnippetInfo arraycopyZeroLengthSnippet = snippet("arraycopyZeroLengthSnippet");
+ private final SnippetInfo arraycopyCheckcastSnippet = snippet("arraycopyCheckcastSnippet");
+ private final SnippetInfo arraycopyNativeSnippet = snippet("arraycopyNativeSnippet");
+
+ private final SnippetInfo checkcastArraycopyWithSlowPathWork = snippet("checkcastArraycopyWithSlowPathWork");
+ private final SnippetInfo genericArraycopyWithSlowPathWork = snippet("genericArraycopyWithSlowPathWork");
+
+ private ResolvedJavaMethod originalArraycopy;
+ private final Counters counters;
public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, HotSpotProviders providers, TargetDescription target) {
super(options, factories, providers, providers.getSnippetReflection(), target);
this.counters = new Counters(factory);
}
- private ResolvedJavaMethod originalArraycopy() throws GraalError {
- if (originalArraycopy == null) {
- Method method;
- try {
- method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
- } catch (NoSuchMethodException | SecurityException e) {
- throw new GraalError(e);
- }
- originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
- }
- return originalArraycopy;
- }
-
- private ResolvedJavaMethod originalArraycopy;
-
- private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork");
- private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric");
-
- private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic");
- private final SnippetInfo arraycopyUnrolledIntrinsicSnippet = snippet("arraycopyUnrolledIntrinsic");
- private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic");
- private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic");
- private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic");
- private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork");
-
- private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork");
-
- private final Counters counters;
-
protected SnippetInfo snippet(String methodName) {
SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any());
info.setOriginalMethod(originalArraycopy());
return info;
}
- public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) {
- return selectComponentKind(arraycopy, true);
- }
+ public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
+ JavaKind elementKind = selectComponentKind(arraycopy);
+ SnippetInfo snippetInfo;
+ ArrayCopyTypeCheck arrayTypeCheck;
- public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) {
ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+ if (!canBeArray(srcType) || !canBeArray(destType)) {
+ // at least one of the objects is definitely not an array - use the native call
+ // right away as the copying will fail anyways
+ snippetInfo = arraycopyNativeSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
+ } else {
+ ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
+ ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
- if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
- if (!exact) {
- JavaKind component = getComponentKind(srcType);
- if (component != null) {
- return component;
+ if (arraycopy.isExact()) {
+ // there is a sufficient type match - we don't need any additional type checks
+ snippetInfo = arraycopyExactSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK;
+ } else if (srcComponentType == null && destComponentType == null) {
+ // we don't know anything about the types - use the generic copying
+ snippetInfo = arraycopyGenericSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK;
+ } else if (srcComponentType != null && destComponentType != null) {
+ if (!srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
+ // it depends on the array content if the copy succeeds - we need
+ // a type check for every store
+ snippetInfo = arraycopyCheckcastSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK;
+ } else {
+ // one object is an object array, the other one is a primitive array.
+ // this copy will always fail - use the native call right away
+ assert !srcComponentType.equals(destComponentType) : "must be handled by arraycopy.isExact()";
+ snippetInfo = arraycopyNativeSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
}
- return getComponentKind(destType);
- }
- return null;
- }
- if (exact) {
- if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
- return null;
- }
- if (!arraycopy.isExact()) {
- return null;
+ } else {
+ ResolvedJavaType nonNullComponentType = srcComponentType != null ? srcComponentType : destComponentType;
+ if (nonNullComponentType.isPrimitive()) {
+ // one involved object is a primitive array - we can safely assume that we
+ // are copying primitive arrays
+ snippetInfo = arraycopyExactSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.HUB_BASED_ARRAY_TYPE_CHECK;
+ elementKind = nonNullComponentType.getJavaKind();
+ } else {
+ // one involved object is an object array - we can safely assume that we are
+ // copying object arrays that might require a store check
+ snippetInfo = arraycopyCheckcastSnippet;
+ arrayTypeCheck = ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK;
+ }
}
}
- return srcType.getComponentType().getJavaKind();
- }
- private static JavaKind getComponentKind(ResolvedJavaType type) {
- if (type != null && type.isArray()) {
- return type.getComponentType().getJavaKind();
- }
- return null;
- }
-
- private static boolean shouldUnroll(ValueNode length) {
- return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
- }
-
- public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
- JavaKind componentKind = selectComponentKind(arraycopy);
- SnippetInfo snippetInfo = null;
- SnippetInfo slowPathSnippetInfo = null;
- Object slowPathArgument = null;
-
+ // a few special cases that are easier to handle when all other variables already have a
+ // value
if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
- snippetInfo = arraycopyZeroLengthIntrinsicSnippet;
- } else if (arraycopy.isExact()) {
- snippetInfo = arraycopyExactIntrinsicSnippet;
- if (shouldUnroll(arraycopy.getLength())) {
- snippetInfo = arraycopyUnrolledIntrinsicSnippet;
- }
- } else {
- if (componentKind == JavaKind.Object) {
- ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
- ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
- ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
- ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
- if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
- snippetInfo = arraycopySlowPathIntrinsicSnippet;
- slowPathSnippetInfo = checkcastArraycopyWorkSnippet;
- slowPathArgument = LocationIdentity.any();
- /*
- * Because this snippet has to use Sysytem.arraycopy as a slow path, we must
- * pretend to kill any() so clear the componentKind.
- */
- componentKind = null;
- }
- }
- if (componentKind == null && snippetInfo == null) {
- JavaKind predictedKind = selectComponentKind(arraycopy, false);
- if (predictedKind != null) {
- /*
- * At least one array is of a known type requiring no store checks, so
- * assume the other is of the same type. Generally this is working around
- * deficiencies in our propagation of type information.
- */
- componentKind = predictedKind;
- if (predictedKind == JavaKind.Object) {
- snippetInfo = arraycopySlowPathIntrinsicSnippet;
- slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet;
- slowPathArgument = predictedKind;
- componentKind = null;
- } else {
- snippetInfo = arraycopyPredictedExactIntrinsicSnippet;
- }
- }
- }
- if (snippetInfo == null) {
- snippetInfo = arraycopyGenericSnippet;
- }
+ snippetInfo = arraycopyZeroLengthSnippet;
+ } else if (snippetInfo == arraycopyExactSnippet && shouldUnroll(arraycopy.getLength())) {
+ snippetInfo = arraycopyUnrolledSnippet;
}
+
+ // create the snippet
Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage());
args.add("src", arraycopy.getSource());
args.add("srcPos", arraycopy.getSourcePosition());
args.add("dest", arraycopy.getDestination());
args.add("destPos", arraycopy.getDestinationPosition());
args.add("length", arraycopy.getLength());
- if (snippetInfo == arraycopyUnrolledIntrinsicSnippet) {
+ if (snippetInfo != arraycopyNativeSnippet) {
+ assert arrayTypeCheck != ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
+ args.addConst("arrayTypeCheck", arrayTypeCheck);
+ }
+ if (snippetInfo == arraycopyUnrolledSnippet) {
+ args.addConst("elementKind", elementKind != null ? elementKind : JavaKind.Illegal);
args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt());
- args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
- } else if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
- ValueNode predictedKlass = null;
- if (slowPathArgument == arraycopyPredictedObjectWorkSnippet) {
- HotSpotResolvedObjectType arrayClass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class);
- predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayClass.klass(), tool.getMetaAccess(), arraycopy.graph());
- } else {
- predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassAlwaysNull(), JavaConstant.NULL_POINTER, tool.getMetaAccess(), arraycopy.graph());
- }
- args.add("predictedKlass", predictedKlass);
- args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
- args.addConst("slowPath", slowPathSnippetInfo);
- assert slowPathArgument != null;
- args.addConst("slowPathArgument", slowPathArgument);
- } else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) {
- assert componentKind != null;
- args.addConst("elementKind", componentKind);
- args.addConst("counter", counters.arraycopyCallCounters.get(componentKind));
- args.addConst("copiedCounter", counters.arraycopyCallCopiedCounters.get(componentKind));
+ }
+ if (snippetInfo == arraycopyExactSnippet) {
+ assert elementKind != null;
+ args.addConst("elementKind", elementKind);
+ args.addConst("elementKindCounter", counters.arraycopyCallCounters.get(elementKind));
+ args.addConst("elementKindCopiedCounter", counters.arraycopyCallCopiedCounters.get(elementKind));
+ }
+ args.addConst("counters", counters);
+ if (snippetInfo == arraycopyCheckcastSnippet) {
+ args.addConst("workSnippet", checkcastArraycopyWithSlowPathWork);
+ args.addConst("elementKind", JavaKind.Illegal);
+ }
+ if (snippetInfo == arraycopyGenericSnippet) {
+ args.addConst("workSnippet", genericArraycopyWithSlowPathWork);
+ args.addConst("elementKind", JavaKind.Illegal);
}
+
+ instantiate(args, arraycopy);
+ }
+
+ public void lower(ArrayCopyWithSlowPathNode arraycopy, LoweringTool tool) {
+ StructuredGraph graph = arraycopy.graph();
+ if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ // if an arraycopy contains a slow path, we can't lower it right away
+ return;
+ }
+
+ SnippetInfo snippetInfo = arraycopy.getSnippet();
+ Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
+ args.add("src", arraycopy.getSource());
+ args.add("srcPos", arraycopy.getSourcePosition());
+ args.add("dest", arraycopy.getDestination());
+ args.add("destPos", arraycopy.getDestinationPosition());
+ args.add("length", arraycopy.getLength());
args.addConst("counters", counters);
instantiate(args, arraycopy);
}
- public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) {
- StructuredGraph graph = arraycopy.graph();
- if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
- // Can't be lowered yet
- return;
- }
- SnippetInfo snippetInfo = arraycopy.getSnippet();
- Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
- args.add("nonNullSrc", arraycopy.getSource());
- args.add("srcPos", arraycopy.getSourcePosition());
- args.add("nonNullDest", arraycopy.getDestination());
- args.add("destPos", arraycopy.getDestinationPosition());
- if (snippetInfo == arraycopyUnrolledWorkSnippet) {
- args.addConst("length", ((Integer) arraycopy.getArgument()).intValue());
- args.addConst("elementKind", arraycopy.getElementKind());
- } else {
- args.add("length", arraycopy.getLength());
- }
- if (snippetInfo == arraycopyPredictedObjectWorkSnippet) {
- args.add("objectArrayKlass", arraycopy.getPredictedKlass());
- args.addConst("counter", counters.arraycopyCallCounters.get(JavaKind.Object));
- args.addConst("copiedCounter", counters.arraycopyCallCopiedCounters.get(JavaKind.Object));
- args.addConst("counters", counters);
- }
- instantiate(args, arraycopy);
+ private static boolean canBeArray(ResolvedJavaType type) {
+ return type == null || type.isJavaLangObject() || type.isArray();
}
- public void lower(ArrayCopyUnrollNode arraycopy, LoweringTool tool) {
- StructuredGraph graph = arraycopy.graph();
- if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
- // Can't be lowered yet
- return;
+ public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) {
+ ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
+ ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
+
+ if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
+ return null;
}
- SnippetInfo snippetInfo = arraycopyUnrolledWorkSnippet;
- Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
- args.add("nonNullSrc", arraycopy.getSource());
- args.add("srcPos", arraycopy.getSourcePosition());
- args.add("nonNullDest", arraycopy.getDestination());
- args.add("destPos", arraycopy.getDestinationPosition());
- args.addConst("length", arraycopy.getUnrollLength());
- args.addConst("elementKind", arraycopy.getElementKind());
- template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
+ if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
+ return null;
+ }
+ if (!arraycopy.isExact()) {
+ return null;
+ }
+ return srcType.getComponentType().getJavaKind();
+ }
+
+ private static boolean shouldUnroll(ValueNode length) {
+ return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
}
/**
@@ -650,8 +543,8 @@
newInvoke.setStateAfter(arraycopy.stateAfter());
}
graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
- } else if (originalNode instanceof ArrayCopySlowPathNode) {
- ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode);
+ } else if (originalNode instanceof ArrayCopyWithSlowPathNode) {
+ ArrayCopyWithSlowPathNode slowPath = (ArrayCopyWithSlowPathNode) replacements.get(originalNode);
assert arraycopy.stateAfter() != null : arraycopy;
assert slowPath.stateAfter() == arraycopy.stateAfter();
slowPath.setBci(arraycopy.getBci());
@@ -659,5 +552,18 @@
}
GraphUtil.killCFG(arraycopy);
}
+
+ private ResolvedJavaMethod originalArraycopy() throws GraalError {
+ if (originalArraycopy == null) {
+ Method method;
+ try {
+ method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
+ } catch (NoSuchMethodException | SecurityException e) {
+ throw new GraalError(e);
+ }
+ originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
+ }
+ return originalArraycopy;
+ }
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyUnrollNode.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2015, 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.replacements.arraycopy;
-
-import jdk.vm.ci.meta.JavaKind;
-
-import static org.graalvm.word.LocationIdentity.any;
-
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.NamedLocationIdentity;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
-import org.graalvm.compiler.nodes.memory.MemoryAccess;
-import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
-import org.graalvm.compiler.nodes.memory.MemoryNode;
-import org.graalvm.compiler.nodes.spi.Lowerable;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.word.LocationIdentity;
-
-@NodeInfo(allowedUsageTypes = InputType.Memory)
-public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess {
-
- public static final NodeClass<ArrayCopyUnrollNode> TYPE = NodeClass.create(ArrayCopyUnrollNode.class);
-
- @Input protected ValueNode src;
- @Input protected ValueNode srcPos;
- @Input protected ValueNode dest;
- @Input protected ValueNode destPos;
- @Input protected ValueNode length;
-
- private JavaKind elementKind;
-
- private int unrolledLength;
-
- @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
-
- public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, JavaKind elementKind) {
- super(TYPE, StampFactory.forKind(JavaKind.Void));
- this.src = src;
- this.srcPos = srcPos;
- this.dest = dest;
- this.destPos = destPos;
- this.length = length;
- this.unrolledLength = unrolledLength;
- assert elementKind != null && elementKind != JavaKind.Illegal;
- this.elementKind = elementKind;
- }
-
- public ValueNode getSource() {
- return src;
- }
-
- public ValueNode getSourcePosition() {
- return srcPos;
- }
-
- public ValueNode getDestination() {
- return dest;
- }
-
- public ValueNode getDestinationPosition() {
- return destPos;
- }
-
- @Override
- public ValueNode getLength() {
- return length;
- }
-
- @Override
- public ValueNode getArray() {
- return dest;
- }
-
- @Override
- public ValueNode getIndex() {
- return destPos;
- }
-
- @Override
- public boolean isObjectArray() {
- return elementKind == JavaKind.Object;
- }
-
- @Override
- public boolean isInitialization() {
- return false;
- }
-
- @NodeIntrinsic
- public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength,
- @ConstantNodeParameter JavaKind elementKind);
-
- public int getUnrollLength() {
- return unrolledLength;
- }
-
- public JavaKind getElementKind() {
- return elementKind;
- }
-
- @Override
- public LocationIdentity getLocationIdentity() {
- if (elementKind != null) {
- return NamedLocationIdentity.getArrayLocation(elementKind);
- }
- return any();
- }
-
- @Override
- public void lower(LoweringTool tool) {
- tool.getLowerer().lower(this, tool);
- }
-
- @Override
- public MemoryNode getLastLocationAccess() {
- return lastLocationAccess;
- }
-
- @Override
- public void setLastLocationAccess(MemoryNode lla) {
- updateUsagesInterface(lastLocationAccess, lla);
- lastLocationAccess = lla;
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopyWithSlowPathNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2015, 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.replacements.arraycopy;
+
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.type.StampTool;
+import org.graalvm.compiler.replacements.SnippetTemplate;
+import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
+
+import jdk.vm.ci.code.BytecodeFrame;
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(allowedUsageTypes = InputType.Memory)
+public final class ArrayCopyWithSlowPathNode extends BasicArrayCopyNode {
+
+ public static final NodeClass<ArrayCopyWithSlowPathNode> TYPE = NodeClass.create(ArrayCopyWithSlowPathNode.class);
+
+ private final SnippetTemplate.SnippetInfo snippet;
+
+ public ArrayCopyWithSlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, SnippetTemplate.SnippetInfo snippet, JavaKind elementKind) {
+ super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
+ assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
+ this.snippet = snippet;
+ }
+
+ @NodeIntrinsic
+ public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet,
+ @ConstantNodeParameter JavaKind elementKind);
+
+ public SnippetTemplate.SnippetInfo getSnippet() {
+ return snippet;
+ }
+
+ public void setBci(int bci) {
+ this.bci = bci;
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/CheckcastArrayCopyCallNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -23,12 +23,13 @@
//JaCoCo Exclude
package org.graalvm.compiler.hotspot.replacements.arraycopy;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@@ -114,8 +115,9 @@
graph().addBeforeFixed(this, basePtr);
int shift = CodeUtil.log2(getArrayIndexScale(JavaKind.Object));
- ValueNode scaledIndex = graph().unique(new LeftShiftNode(pos, ConstantNode.forInt(shift, graph())));
- ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forInt(getArrayBaseOffset(JavaKind.Object), graph())));
+ ValueNode extendedPos = IntegerConvertNode.convert(pos, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph());
+ ValueNode scaledIndex = graph().unique(new LeftShiftNode(extendedPos, ConstantNode.forInt(shift, graph())));
+ ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerBits(PrimitiveStamp.getBits(scaledIndex.stamp()), getArrayBaseOffset(JavaKind.Object), graph())));
return graph().unique(new OffsetAddressNode(basePtr, offset));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/GenericArrayCopyCallNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+//JaCoCo Exclude
+package org.graalvm.compiler.hotspot.replacements.arraycopy;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
+
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
+import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
+import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
+import org.graalvm.compiler.nodes.extended.ForeignCallNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.word.LocationIdentity;
+
+import jdk.vm.ci.meta.JavaKind;
+
+@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
+public final class GenericArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+ public static final NodeClass<GenericArrayCopyCallNode> TYPE = NodeClass.create(GenericArrayCopyCallNode.class);
+ @Input ValueNode src;
+ @Input ValueNode srcPos;
+ @Input ValueNode dest;
+ @Input ValueNode destPos;
+ @Input ValueNode length;
+
+ protected final HotSpotGraalRuntimeProvider runtime;
+
+ protected GenericArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length) {
+ super(TYPE, StampFactory.forKind(JavaKind.Int));
+ this.src = src;
+ this.srcPos = srcPos;
+ this.dest = dest;
+ this.destPos = destPos;
+ this.length = length;
+ this.runtime = runtime;
+ }
+
+ public ValueNode getSource() {
+ return src;
+ }
+
+ public ValueNode getSourcePosition() {
+ return srcPos;
+ }
+
+ public ValueNode getDestination() {
+ return dest;
+ }
+
+ public ValueNode getDestinationPosition() {
+ return destPos;
+ }
+
+ public ValueNode getLength() {
+ return length;
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
+ StructuredGraph graph = graph();
+ ValueNode srcAddr = objectAddress(getSource());
+ ValueNode destAddr = objectAddress(getDestination());
+ ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), HotSpotBackend.GENERIC_ARRAYCOPY, srcAddr, srcPos, destAddr, destPos, length));
+ call.setStateAfter(stateAfter());
+ graph.replaceFixedWithFixed(this, call);
+ }
+ }
+
+ private ValueNode objectAddress(ValueNode obj) {
+ GetObjectAddressNode result = graph().add(new GetObjectAddressNode(obj));
+ graph().addBeforeFixed(this, result);
+ return result;
+ }
+
+ private ValueNode wordValue(ValueNode value) {
+ if (value.stamp().getStackKind() != runtime.getTarget().wordJavaKind) {
+ return IntegerConvertNode.convert(value, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph());
+ }
+ return value;
+ }
+
+ @Override
+ public LocationIdentity getLocationIdentity() {
+ return LocationIdentity.any();
+ }
+
+ @NodeIntrinsic
+ public static native int genericArraycopy(Object src, int srcPos, Object dest, int destPos, int length);
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopyNode.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-/*
- * 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.replacements.arraycopy;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
-import static org.graalvm.word.LocationIdentity.any;
-
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.NamedLocationIdentity;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
-import org.graalvm.compiler.nodes.memory.MemoryAccess;
-import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
-import org.graalvm.compiler.nodes.memory.MemoryNode;
-import org.graalvm.compiler.nodes.spi.Lowerable;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
-import org.graalvm.word.LocationIdentity;
-
-import jdk.vm.ci.meta.JavaKind;
-
-@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_256, size = SIZE_64)
-public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single, MemoryAccess {
-
- public static final NodeClass<UnsafeArrayCopyNode> TYPE = NodeClass.create(UnsafeArrayCopyNode.class);
- @Input ValueNode src;
- @Input ValueNode srcPos;
- @Input ValueNode dest;
- @Input ValueNode destPos;
- @Input ValueNode length;
- @OptionalInput ValueNode layoutHelper;
-
- @OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
-
- protected JavaKind elementKind;
-
- public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, JavaKind elementKind) {
- super(TYPE, StampFactory.forVoid());
- assert layoutHelper == null || elementKind == null;
- this.src = src;
- this.srcPos = srcPos;
- this.dest = dest;
- this.destPos = destPos;
- this.length = length;
- this.layoutHelper = layoutHelper;
- this.elementKind = elementKind;
- }
-
- public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
- this(src, srcPos, dest, destPos, length, null, elementKind);
- }
-
- public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) {
- this(src, srcPos, dest, destPos, length, layoutHelper, null);
- }
-
- @Override
- public ValueNode getArray() {
- return dest;
- }
-
- @Override
- public ValueNode getIndex() {
- return destPos;
- }
-
- @Override
- public ValueNode getLength() {
- return length;
- }
-
- @Override
- public boolean isObjectArray() {
- return elementKind == JavaKind.Object;
- }
-
- @Override
- public boolean isInitialization() {
- return false;
- }
-
- public JavaKind getElementKind() {
- return elementKind;
- }
-
- @Override
- public void lower(LoweringTool tool) {
- if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
- UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class);
- templates.lower(this, tool);
- }
- }
-
- public void addSnippetArguments(Arguments args) {
- args.add("src", src);
- args.add("srcPos", srcPos);
- args.add("dest", dest);
- args.add("destPos", destPos);
- args.add("length", length);
- if (layoutHelper != null) {
- args.add("layoutHelper", layoutHelper);
- }
- }
-
- @Override
- public LocationIdentity getLocationIdentity() {
- if (elementKind != null) {
- return NamedLocationIdentity.getArrayLocation(elementKind);
- }
- return any();
- }
-
- @Override
- public MemoryNode getLastLocationAccess() {
- return lastLocationAccess;
- }
-
- @Override
- public void setLastLocationAccess(MemoryNode lla) {
- updateUsagesInterface(lastLocationAccess, lla);
- lastLocationAccess = lla;
- }
-
- @NodeIntrinsic
- public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind);
-
- @NodeIntrinsic
- public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper);
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/UnsafeArrayCopySnippets.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,324 +0,0 @@
-/*
- * 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.replacements.arraycopy;
-
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.runtime;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
-import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
-import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
-import static org.graalvm.word.LocationIdentity.any;
-
-import org.graalvm.compiler.api.replacements.Fold;
-import org.graalvm.compiler.api.replacements.Snippet;
-import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
-import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
-import org.graalvm.compiler.nodes.NamedLocationIdentity;
-import org.graalvm.compiler.nodes.extended.RawLoadNode;
-import org.graalvm.compiler.nodes.extended.RawStoreNode;
-import org.graalvm.compiler.nodes.extended.UnsafeCopyNode;
-import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.replacements.SnippetTemplate;
-import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
-import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
-import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
-import org.graalvm.compiler.replacements.Snippets;
-import org.graalvm.compiler.word.ObjectAccess;
-import org.graalvm.word.LocationIdentity;
-import org.graalvm.word.UnsignedWord;
-import org.graalvm.word.WordFactory;
-
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.JavaKind;
-
-/**
- * As opposed to {@link ArrayCopySnippets}, these Snippets do <b>not</b> perform store checks.
- */
-public class UnsafeArrayCopySnippets implements Snippets {
-
- private static final boolean supportsUnalignedMemoryAccess = runtime().getHostJVMCIBackend().getTarget().arch.supportsUnalignedMemoryAccess();
-
- private static final JavaKind VECTOR_KIND = JavaKind.Long;
- private static final long VECTOR_SIZE = getArrayIndexScale(VECTOR_KIND);
-
- private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, JavaKind baseKind, LocationIdentity locationIdentity) {
- int arrayBaseOffset = arrayBaseOffset(baseKind);
- int elementSize = arrayIndexScale(baseKind);
- long byteLength = (long) length * elementSize;
- long srcOffset = (long) srcPos * elementSize;
- long destOffset = (long) destPos * elementSize;
-
- long preLoopBytes;
- long mainLoopBytes;
- long postLoopBytes;
-
- // We can easily vectorize the loop if both offsets have the same alignment.
- if (byteLength >= VECTOR_SIZE && (srcOffset % VECTOR_SIZE) == (destOffset % VECTOR_SIZE)) {
- preLoopBytes = NumUtil.roundUp(arrayBaseOffset + srcOffset, VECTOR_SIZE) - (arrayBaseOffset + srcOffset);
- postLoopBytes = (byteLength - preLoopBytes) % VECTOR_SIZE;
- mainLoopBytes = byteLength - preLoopBytes - postLoopBytes;
- } else {
- // Does the architecture support unaligned memory accesses?
- if (supportsUnalignedMemoryAccess) {
- preLoopBytes = byteLength % VECTOR_SIZE;
- mainLoopBytes = byteLength - preLoopBytes;
- postLoopBytes = 0;
- } else {
- // No. Let's do element-wise copying.
- preLoopBytes = byteLength;
- mainLoopBytes = 0;
- postLoopBytes = 0;
- }
- }
-
- if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) {
- // bad aliased case
- srcOffset += byteLength;
- destOffset += byteLength;
-
- // Post-loop
- for (long i = 0; i < postLoopBytes; i += elementSize) {
- srcOffset -= elementSize;
- destOffset -= elementSize;
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
- }
- // Main-loop
- for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
- srcOffset -= VECTOR_SIZE;
- destOffset -= VECTOR_SIZE;
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
- }
- // Pre-loop
- for (long i = 0; i < preLoopBytes; i += elementSize) {
- srcOffset -= elementSize;
- destOffset -= elementSize;
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
- }
- } else {
- // Pre-loop
- for (long i = 0; i < preLoopBytes; i += elementSize) {
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
- srcOffset += elementSize;
- destOffset += elementSize;
- }
- // Main-loop
- for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
- srcOffset += VECTOR_SIZE;
- destOffset += VECTOR_SIZE;
- }
- // Post-loop
- for (long i = 0; i < postLoopBytes; i += elementSize) {
- UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
- srcOffset += elementSize;
- destOffset += elementSize;
- }
- }
- }
-
- @Fold
- static LocationIdentity getArrayLocation(JavaKind kind) {
- return NamedLocationIdentity.getArrayLocation(kind);
- }
-
- @Snippet
- public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Byte;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Boolean;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Char;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Short;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Int;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Float;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Long;
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- @Snippet
- public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Double;
- /*
- * TODO atomicity problem on 32-bit architectures: The JVM spec requires double values to be
- * copied atomically, but not long values. For example, on Intel 32-bit this code is not
- * atomic as long as the vector kind remains Kind.Long.
- */
- vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
- }
-
- /**
- * For this kind, Object, we want to avoid write barriers between writes, but instead have them
- * at the end of the snippet. This is done by using {@link RawStoreNode}, and rely on
- * {@link WriteBarrierAdditionPhase} to put write barriers after the {@link UnsafeArrayCopyNode}
- * with kind Object.
- */
- @Snippet
- public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
- JavaKind kind = JavaKind.Object;
- final int scale = arrayIndexScale(kind);
- int arrayBaseOffset = arrayBaseOffset(kind);
- LocationIdentity arrayLocation = getArrayLocation(kind);
- if (src == dest && srcPos < destPos) { // bad aliased case
- long start = (long) (length - 1) * scale;
- for (long i = start; i >= 0; i -= scale) {
- Object a = RawLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
- RawStoreNode.storeObject(dest, arrayBaseOffset + i + (long) destPos * scale, a, kind, getArrayLocation(kind), false);
- }
- } else {
- long end = (long) length * scale;
- for (long i = 0; i < end; i += scale) {
- Object a = RawLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
- RawStoreNode.storeObject(dest, arrayBaseOffset + i + (long) destPos * scale, a, kind, getArrayLocation(kind), false);
- }
- }
- }
-
- @Snippet
- public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) {
- int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
- int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
-
- UnsignedWord vectorSize = WordFactory.unsigned(VECTOR_SIZE);
- UnsignedWord srcOffset = WordFactory.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
- UnsignedWord destOffset = WordFactory.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
- UnsignedWord destStart = destOffset;
- UnsignedWord destEnd = destOffset.add(WordFactory.unsigned(length).shiftLeft(log2ElementSize));
-
- UnsignedWord destVectorEnd = null;
- UnsignedWord nonVectorBytes = null;
- UnsignedWord sizeInBytes = WordFactory.unsigned(length).shiftLeft(log2ElementSize);
- if (supportsUnalignedMemoryAccess) {
- nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize);
- destVectorEnd = destEnd;
- } else {
- boolean inPhase = srcOffset.and((int) VECTOR_SIZE - 1).equal(destOffset.and((int) VECTOR_SIZE - 1));
- boolean hasAtLeastOneVector = sizeInBytes.aboveOrEqual(vectorSize);
- // We must have at least one full vector, otherwise we must copy each byte separately
- if (hasAtLeastOneVector && inPhase) { // If in phase, we can vectorize
- nonVectorBytes = vectorSize.subtract(destStart.unsignedRemainder(vectorSize));
- } else { // fallback is byte-wise
- nonVectorBytes = sizeInBytes;
- }
- destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(vectorSize));
- }
-
- UnsignedWord destNonVectorEnd = destStart.add(nonVectorBytes);
- while (destOffset.belowThan(destNonVectorEnd)) {
- ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
- destOffset = destOffset.add(1);
- srcOffset = srcOffset.add(1);
- }
- // Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8));
- while (destOffset.belowThan(destVectorEnd)) {
- ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any());
- destOffset = destOffset.add(wordSize());
- srcOffset = srcOffset.add(wordSize());
- }
- // Do the last bytes each when it is required to have absolute alignment.
- while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) {
- ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
- destOffset = destOffset.add(1);
- srcOffset = srcOffset.add(1);
- }
- }
-
- public static class Templates extends AbstractTemplates {
-
- private final SnippetInfo[] arraycopySnippets;
- private final SnippetInfo genericPrimitiveSnippet;
-
- public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, TargetDescription target) {
- super(options, factories, providers, providers.getSnippetReflection(), target);
-
- arraycopySnippets = new SnippetInfo[JavaKind.values().length];
- arraycopySnippets[JavaKind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean");
- arraycopySnippets[JavaKind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte");
- arraycopySnippets[JavaKind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort");
- arraycopySnippets[JavaKind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar");
- arraycopySnippets[JavaKind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt");
- arraycopySnippets[JavaKind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong");
- arraycopySnippets[JavaKind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat");
- arraycopySnippets[JavaKind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble");
- arraycopySnippets[JavaKind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject");
-
- genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive");
- }
-
- public void lower(UnsafeArrayCopyNode node, LoweringTool tool) {
- JavaKind elementKind = node.getElementKind();
- SnippetInfo snippet;
- if (elementKind == null) {
- // primitive array of unknown kind
- snippet = genericPrimitiveSnippet;
- } else {
- snippet = arraycopySnippets[elementKind.ordinal()];
- assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found";
- }
-
- Arguments args = new Arguments(snippet, node.graph().getGuardsStage(), tool.getLoweringStage());
- node.addSnippetArguments(args);
-
- SnippetTemplate template = template(node.getDebug(), args);
- template.instantiate(providers.getMetaAccess(), node, DEFAULT_REPLACER, args);
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProbabilisticProfileSnippets.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -54,6 +54,7 @@
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
+import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.TargetDescription;
public class ProbabilisticProfileSnippets implements Snippets {
@@ -64,22 +65,22 @@
}
@Snippet
- public static int notificationMask(int freqLog, int probLog) {
- int probabilityMask = (1 << probLog) - 1;
+ public static int notificationMask(int freqLog, int probLog, int stepLog) {
int frequencyMask = (1 << freqLog) - 1;
- return frequencyMask & ~probabilityMask;
+ int stepMask = (1 << (stepLog + probLog)) - 1;
+ return frequencyMask & ~stepMask;
}
@NodeIntrinsic(ForeignCallNode.class)
public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
@Snippet
- public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog) {
+ public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog) {
if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
- int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
+ int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + ((config(INJECTED_VMCONFIG).invocationCounterIncrement * step) << probLog);
counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
if (freqLog >= 0) {
- int mask = notificationMask(freqLog, probLog);
+ int mask = notificationMask(freqLog, probLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
}
@@ -91,11 +92,12 @@
public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
@Snippet
- public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci, int targetBci) {
+ public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci,
+ int targetBci) {
if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
- int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
+ int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + ((config(INJECTED_VMCONFIG).invocationCounterIncrement * step) << probLog);
counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
- int mask = notificationMask(freqLog, probLog);
+ int mask = notificationMask(freqLog, probLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
}
@@ -103,10 +105,11 @@
}
@Snippet
- public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, boolean branchCondition,
+ public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog,
+ @ConstantParameter int probLog, boolean branchCondition,
int bci, int targetBci) {
if (branchCondition) {
- profileBackedgeWithProbability(counters, random, freqLog, probLog, bci, targetBci);
+ profileBackedgeWithProbability(counters, random, step, stepLog, freqLog, probLog, bci, targetBci);
}
}
@@ -124,6 +127,8 @@
StructuredGraph graph = profileNode.graph();
LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
+ ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph);
+ ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph);
if (profileNode instanceof ProfileBranchNode) {
// Backedge event
@@ -132,8 +137,11 @@
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
+
args.add("counters", counters);
args.add("random", profileBranchNode.getRandom());
+ args.add("step", step);
+ args.add("stepLog", stepLog);
args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
args.addConst("probLog", profileBranchNode.getProbabilityLog());
if (profileBranchNode.hasCondition()) {
@@ -148,8 +156,11 @@
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
// Method invocation event
Arguments args = new Arguments(profileMethodEntryWithProbability, graph.getGuardsStage(), tool.getLoweringStage());
+
args.add("counters", counters);
args.add("random", profileInvokeNode.getRandom());
+ args.add("step", step);
+ args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
args.addConst("probLog", profileInvokeNode.getProbabilityLog());
SnippetTemplate template = template(graph.getDebug(), args);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/profiling/ProfileSnippets.java Mon Nov 06 20:29:49 2017 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 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
@@ -54,6 +54,7 @@
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
+import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.TargetDescription;
public class ProfileSnippets implements Snippets {
@@ -61,12 +62,19 @@
public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
@Snippet
- public static void profileMethodEntry(MethodCountersPointer counters, @ConstantParameter int freqLog) {
- int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
+ protected static int notificationMask(int freqLog, int stepLog) {
+ int stepMask = (1 << stepLog) - 1;
+ int frequencyMask = (1 << freqLog) - 1;
+ return frequencyMask & ~stepMask;
+ }
+
+ @Snippet
+ public static void profileMethodEntry(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog) {
+ int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement * step;
counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
if (freqLog >= 0) {
- final int frequencyMask = (1 << freqLog) - 1;
- if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+ final int mask = notificationMask(freqLog, stepLog);
+ if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
}
}
@@ -76,19 +84,19 @@
public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
@Snippet
- public static void profileBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, int bci, int targetBci) {
- int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
+ public static void profileBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, int bci, int targetBci) {
+ int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement * step;
counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
- final int frequencyMask = (1 << freqLog) - 1;
- if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
+ final int mask = notificationMask(freqLog, stepLog);
+ if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
}
}
@Snippet
- public static void profileConditionalBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) {
+ public static void profileConditionalBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) {
if (branchCondition) {
- profileBackedge(counters, freqLog, bci, targetBci);
+ profileBackedge(counters, step, stepLog, freqLog, bci, targetBci);
}
}
@@ -104,6 +112,8 @@
public void lower(ProfileNode profileNode, LoweringTool tool) {
StructuredGraph graph = profileNode.graph();
LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
+ ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph);
+ ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph);
if (profileNode instanceof ProfileBranchNode) {
// Backedge event
@@ -113,6 +123,8 @@
ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
args.add("counters", counters);
+ args.add("step", step);
+ args.add("stepLog", stepLog);
args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
if (profileBranchNode.hasCondition()) {
args.add("branchCondition", profileBranchNode.branchCondition());
@@ -127,6 +139,8 @@
// Method invocation event
Arguments args = new Arguments(profileMethodEntry, graph.getGuardsStage(), tool.getLoweringStage());
args.add("counters", counters);
+ args.add("step", step);
+ args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
SnippetTemplate template = template(graph.getDebug(), args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewArrayStub.java Mon Nov 06 20:29:49 2017 -0800
@@ -33,6 +33,7 @@
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useCMSIncrementalMode;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH;
import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.formatArray;
@@ -122,7 +123,7 @@
// check that array length is small enough for fast path.
Word thread = registerAsWord(threadRegister);
boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
- if (inlineContiguousAllocationSupported && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
+ if (inlineContiguousAllocationSupported && !useCMSIncrementalMode(INJECTED_VMCONFIG) && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging(options));
if (memory.notEqual(0)) {
if (logging(options)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/NewInstanceStub.java Mon Nov 06 20:29:49 2017 -0800
@@ -53,6 +53,7 @@
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteLimitOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabSlowAllocationsOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabStats;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useCMSIncrementalMode;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useG1GC;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
@@ -147,7 +148,7 @@
*/
Word thread = registerAsWord(threadRegister);
boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
- if (!forceSlowPath(options) && inlineContiguousAllocationSupported) {
+ if (!forceSlowPath(options) && inlineContiguousAllocationSupported && !useCMSIncrementalMode(INJECTED_VMCONFIG)) {
if (isInstanceKlassFullyInitialized(hub)) {
int sizeInBytes = readLayoutHelper(hub);
Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging(options));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Mon Nov 06 20:29:49 2017 -0800
@@ -342,7 +342,7 @@
import org.graalvm.compiler.nodes.calc.AndNode;
import org.graalvm.compiler.nodes.calc.CompareNode;
import org.graalvm.compiler.nodes.calc.ConditionalNode;
-import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.FloatDivNode;
import org.graalvm.compiler.nodes.calc.FloatConvertNode;
import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
@@ -374,7 +374,6 @@
import org.graalvm.compiler.nodes.extended.StateSplitProxyNode;
import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
-import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -383,6 +382,7 @@
import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin;
import org.graalvm.compiler.nodes.java.ArrayLengthNode;
@@ -435,6 +435,7 @@
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
import jdk.vm.ci.meta.TriState;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
/**
* The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
@@ -1036,7 +1037,7 @@
deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
- private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) {
+ private AbstractBeginNode handleException(ValueNode exceptionObject, int bci, boolean deoptimizeOnly) {
assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));
@@ -1058,8 +1059,12 @@
this.controlFlowSplit = true;
FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
- createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
-
+ if (deoptimizeOnly) {
+ DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
+ dispatchBegin.setNext(BeginNode.begin(deoptimizeNode));
+ } else {
+ createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
+ }
return dispatchBegin;
}
@@ -1111,7 +1116,7 @@
}
protected ValueNode genFloatDiv(ValueNode x, ValueNode y) {
- return DivNode.create(x, y);
+ return FloatDivNode.create(x, y);
}
protected ValueNode genFloatRem(ValueNode x, ValueNode y) {
@@ -1215,7 +1220,7 @@
ValueNode exception = frameState.pop(JavaKind.Object);
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()));
+ lastInstr.setNext(handleException(nonNullException, bci(), false));
}
protected LogicNode createInstanceOf(TypeReference type, ValueNode object) {
@@ -1275,12 +1280,12 @@
}
BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
AbstractBeginNode falseSucc = graph.add(new BeginNode());
- ValueNode nonNullReceiver = graph.addOrUnique(PiNode.create(receiver, objectNonNull(), falseSucc));
+ ValueNode nonNullReceiver = graph.addOrUniqueWithInputs(PiNode.create(receiver, objectNonNull(), falseSucc));
append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, SLOW_PATH_PROBABILITY));
lastInstr = falseSucc;
exception.setStateAfter(createFrameState(bci(), exception));
- exception.setNext(handleException(exception, bci()));
+ exception.setNext(handleException(exception, bci(), false));
EXPLICIT_EXCEPTIONS.increment(debug);
return nonNullReceiver;
}
@@ -1292,7 +1297,7 @@
lastInstr = trueSucc;
exception.setStateAfter(createFrameState(bci(), exception));
- exception.setNext(handleException(exception, bci()));
+ exception.setNext(handleException(exception, bci(), false));
}
protected ValueNode genArrayLength(ValueNode x) {
@@ -1532,8 +1537,8 @@
@Override
public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
BytecodeParser intrinsicCallSiteParser = getNonIntrinsicAncestor();
- boolean withExceptionEdge = intrinsicCallSiteParser == null ? !omitInvokeExceptionEdge(null) : !intrinsicCallSiteParser.omitInvokeExceptionEdge(null);
- createNonInlinedInvoke(withExceptionEdge, bci(), callTarget, resultType);
+ ExceptionEdgeAction exceptionEdgeAction = intrinsicCallSiteParser == null ? getActionForInvokeExceptionEdge(null) : intrinsicCallSiteParser.getActionForInvokeExceptionEdge(null);
+ createNonInlinedInvoke(exceptionEdgeAction, bci(), callTarget, resultType);
}
protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
@@ -1603,7 +1608,7 @@
int invokeBci = bci();
JavaTypeProfile profile = getProfileForInvoke(invokeKind);
- boolean withExceptionEdge = !omitInvokeExceptionEdge(inlineInfo);
+ ExceptionEdgeAction edgeAction = getActionForInvokeExceptionEdge(inlineInfo);
boolean partialIntrinsicExit = false;
if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
partialIntrinsicExit = true;
@@ -1614,7 +1619,7 @@
// must use the same context as the call to the intrinsic.
invokeBci = intrinsicCallSiteParser.bci();
profile = intrinsicCallSiteParser.getProfileForInvoke(invokeKind);
- withExceptionEdge = !intrinsicCallSiteParser.omitInvokeExceptionEdge(inlineInfo);
+ edgeAction = intrinsicCallSiteParser.getActionForInvokeExceptionEdge(inlineInfo);
} else {
// We are parsing the intrinsic for the root compilation or for inlining,
// This call is a partial intrinsic exit, and we do not have profile information
@@ -1624,7 +1629,7 @@
assert intrinsicContext.isPostParseInlined();
invokeBci = BytecodeFrame.UNKNOWN_BCI;
profile = null;
- withExceptionEdge = graph.method().getAnnotation(Snippet.class) == null;
+ edgeAction = graph.method().getAnnotation(Snippet.class) == null ? ExceptionEdgeAction.INCLUDE_AND_HANDLE : ExceptionEdgeAction.OMIT;
}
if (originalMethod.isStatic()) {
@@ -1637,10 +1642,10 @@
Signature sig = originalMethod.getSignature();
returnType = sig.getReturnType(method.getDeclaringClass());
resultType = sig.getReturnKind();
- assert checkPartialIntrinsicExit(intrinsicCallSiteParser == null ? null : intrinsicCallSiteParser.currentInvoke.args, args);
+ assert intrinsicContext.allowPartialIntrinsicArgumentMismatch() || checkPartialIntrinsicExit(intrinsicCallSiteParser == null ? null : intrinsicCallSiteParser.currentInvoke.args, args);
targetMethod = originalMethod;
}
- Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile);
+ Invoke invoke = createNonInlinedInvoke(edgeAction, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile);
if (partialIntrinsicExit) {
// This invoke must never be later inlined as it might select the intrinsic graph.
// Until there is a mechanism to guarantee that any late inlining will not select
@@ -1698,14 +1703,14 @@
} else {
for (int i = 0; i < recursiveArgs.length; i++) {
ValueNode arg = GraphUtil.unproxify(recursiveArgs[i]);
- assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s", i,
- ParameterNode.class.getSimpleName(), i, arg);
+ assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s",
+ i, ParameterNode.class.getSimpleName(), i, arg);
}
}
return true;
}
- protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
+ protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
InvokeKind invokeKind, JavaKind resultType, JavaType returnType, JavaTypeProfile profile) {
StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
@@ -1714,7 +1719,7 @@
}
MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
- Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, callTarget, resultType);
+ Invoke invoke = createNonInlinedInvoke(exceptionEdge, invokeBci, callTarget, resultType);
for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
plugin.notifyNotInlined(this, targetMethod, invoke);
@@ -1723,11 +1728,11 @@
return invoke;
}
- protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
- if (!withExceptionEdge) {
+ protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+ if (exceptionEdge == ExceptionEdgeAction.OMIT) {
return createInvoke(invokeBci, callTarget, resultType);
} else {
- Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType);
+ Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge);
AbstractBeginNode beginNode = graph.add(KillingBeginNode.create(LocationIdentity.any()));
invoke.setNext(beginNode);
lastInstr = beginNode;
@@ -1736,20 +1741,29 @@
}
/**
- * If the method returns true, the invocation of the given {@link MethodCallTargetNode call
- * target} does not need an exception edge.
+ * Describes what should be done with the exception edge of an invocation. The edge can be
+ * omitted or included. An included edge can handle the exception or transfer execution to the
+ * interpreter for handling (deoptimize).
*/
- protected boolean omitInvokeExceptionEdge(InlineInfo lastInlineInfo) {
+ protected enum ExceptionEdgeAction {
+ OMIT,
+ INCLUDE_AND_HANDLE,
+ INCLUDE_AND_DEOPTIMIZE
+ }
+
+ protected ExceptionEdgeAction getActionForInvokeExceptionEdge(InlineInfo lastInlineInfo) {
if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) {
- return false;
+ return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) {
- return true;
+ return ExceptionEdgeAction.OMIT;
+ } else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION) {
+ return ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.CheckAll) {
- return false;
+ return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.ExplicitOnly) {
- return false;
+ return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) {
- return true;
+ return ExceptionEdgeAction.OMIT;
} else {
assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile;
// be conservative if information was not recorded (could result in endless
@@ -1759,12 +1773,12 @@
if (profilingInfo != null) {
TriState exceptionSeen = profilingInfo.getExceptionSeen(bci());
if (exceptionSeen == TriState.FALSE) {
- return true;
+ return ExceptionEdgeAction.OMIT;
}
}
}
}
- return false;
+ return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
}
}
@@ -1887,7 +1901,7 @@
if (newProfile != profile) {
if (newProfile.getTypes().length == 0) {
// All profiled types select the intrinsic so
- // emit a fixed guard instead of a if-then-else.
+ // emit a fixed guard instead of an if-then-else.
lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false));
return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null);
}
@@ -1966,7 +1980,7 @@
}
lastInstr = intrinsicGuard.nonIntrinsicBranch;
- createNonInlinedInvoke(omitInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
+ createNonInlinedInvoke(getActionForInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
EndNode nonIntrinsicEnd = append(new EndNode());
AbstractMergeNode mergeNode = graph.add(new MergeNode());
@@ -2303,7 +2317,7 @@
if (calleeBeforeUnwindNode != null) {
ValueNode calleeUnwindValue = parser.getUnwindValue();
assert calleeUnwindValue != null;
- calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
+ calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false));
}
}
}
@@ -2319,7 +2333,7 @@
return invoke;
}
- protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
+ protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType, ExceptionEdgeAction exceptionEdgeAction) {
if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
/*
* Clear non-live locals early so that the exception handler entry gets the cleared
@@ -2328,7 +2342,7 @@
frameState.clearNonLiveLocals(currentBlock, liveness, false);
}
- AbstractBeginNode exceptionEdge = handleException(null, bci());
+ AbstractBeginNode exceptionEdge = handleException(null, bci(), exceptionEdgeAction == ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE);
InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci));
frameState.pushReturn(resultType, invoke);
invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
@@ -2359,20 +2373,43 @@
}
}
+ ValueNode realReturnVal = processReturnValue(returnVal, returnKind);
+
frameState.setRethrowException(false);
frameState.clearStack();
- beforeReturn(returnVal, returnKind);
+ beforeReturn(realReturnVal, returnKind);
if (parent == null) {
- append(new ReturnNode(returnVal));
+ append(new ReturnNode(realReturnVal));
} else {
if (returnDataList == null) {
returnDataList = new ArrayList<>();
}
- returnDataList.add(new ReturnToCallerData(returnVal, lastInstr));
+ returnDataList.add(new ReturnToCallerData(realReturnVal, lastInstr));
lastInstr = null;
}
}
+ private ValueNode processReturnValue(ValueNode value, JavaKind kind) {
+ JavaKind returnKind = method.getSignature().getReturnKind();
+ if (kind != returnKind) {
+ // sub-word integer
+ assert returnKind.isNumericInteger() && returnKind.getStackKind() == JavaKind.Int;
+ IntegerStamp stamp = (IntegerStamp) value.stamp();
+
+ // the bytecode verifier doesn't check that the value is in the correct range
+ if (stamp.lowerBound() < returnKind.getMinValue() || returnKind.getMaxValue() < stamp.upperBound()) {
+ ValueNode narrow = append(genNarrow(value, returnKind.getBitCount()));
+ if (returnKind.isUnsigned()) {
+ return append(genZeroExtend(narrow, 32));
+ } else {
+ return append(genSignExtend(narrow, 32));
+ }
+ }
+ }
+
+ return value;
+ }
+
private void beforeReturn(ValueNode x, JavaKind kind) {
if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
/*
@@ -2794,6 +2831,8 @@
}
private void createExceptionDispatch(ExceptionDispatchBlock block) {
+ lastInstr = finishInstruction(lastInstr, frameState);
+
assert frameState.stackSize() == 1 : frameState;
if (block.handler.isCatchAll()) {
assert block.getSuccessorCount() == 1;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -207,7 +207,7 @@
receiver = new ParameterNode(javaIndex, receiverStamp);
}
- locals[javaIndex] = graph.addOrUnique(receiver);
+ locals[javaIndex] = graph.addOrUniqueWithInputs(receiver);
javaIndex = 1;
index = 1;
}
@@ -241,7 +241,7 @@
param = new ParameterNode(index, stamp);
}
- locals[javaIndex] = graph.addOrUnique(param);
+ locals[javaIndex] = graph.addOrUniqueWithInputs(param);
javaIndex++;
if (kind.needsTwoSlots()) {
locals[javaIndex] = TWO_SLOT_MARKER;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/ConditionalElimination02.java Mon Nov 06 20:29:49 2017 -0800
@@ -29,6 +29,9 @@
import org.junit.Test;
import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
public class ConditionalElimination02 extends JTTTest {
@@ -59,6 +62,14 @@
return -1;
}
+ /**
+ * These tests assume all code paths are reachable so disable profile based dead code removal.
+ */
+ @Override
+ protected HighTierContext getDefaultHighTierContext() {
+ return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
+ }
+
@Test
public void run0() throws Throwable {
runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new A(5), false, false);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Double04.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, 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.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of double operations.
+ */
+public class Fold_Double04 extends JTTTest {
+
+ // Contrived check whether both arguments are the same kind of zero
+ public static boolean test(double x, double y) {
+ if (x == 0) {
+ if (1 / x == Double.NEGATIVE_INFINITY) {
+ return 1 / y == Double.NEGATIVE_INFINITY;
+ } else {
+ return 1 / y == Double.POSITIVE_INFINITY;
+ }
+ }
+ return false;
+ }
+
+ @Test
+ public void run0() throws Throwable {
+ runTest("test", -0d, -0d);
+ }
+
+ @Test
+ public void run1() throws Throwable {
+ runTest("test", -0d, 0d);
+ }
+
+ @Test
+ public void run2() throws Throwable {
+ runTest("test", 0d, -0d);
+ }
+
+ @Test
+ public void run3() throws Throwable {
+ runTest("test", 0d, 0d);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/Fold_Float03.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, 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.jtt.optimize;
+
+import org.junit.Test;
+
+import org.graalvm.compiler.jtt.JTTTest;
+
+/*
+ * Tests constant folding of float operations.
+ */
+public class Fold_Float03 extends JTTTest {
+
+ // Contrived check whether both arguments are the same kind of zero
+ public static boolean test(float x, float y) {
+ if (x == 0) {
+ if (1 / x == Float.NEGATIVE_INFINITY) {
+ return 1 / y == Float.NEGATIVE_INFINITY;
+ } else {
+ return 1 / y == Float.POSITIVE_INFINITY;
+ }
+ }
+ return false;
+ }
+
+ @Test
+ public void run0() throws Throwable {
+ runTest("test", -0f, -0f);
+ }
+
+ @Test
+ public void run1() throws Throwable {
+ runTest("test", -0f, 0f);
+ }
+
+ @Test
+ public void run2() throws Throwable {
+ runTest("test", 0f, -0f);
+ }
+
+ @Test
+ public void run3() throws Throwable {
+ runTest("test", 0f, 0f);
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,6 +37,7 @@
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
@@ -132,12 +133,19 @@
masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset));
// Get array length in bytes.
- masm.imull(length, asRegister(lengthValue), arrayIndexScale);
+ masm.movl(length, asRegister(lengthValue));
+
+ if (arrayIndexScale > 1) {
+ masm.shll(length, NumUtil.log2Ceil(arrayIndexScale)); // scale length
+ }
+
masm.movl(result, length); // copy
if (supportsAVX2(crb.target)) {
emitAVXCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
} else if (supportsSSE41(crb.target)) {
+ // this code is used for AVX as well because our backend correctly ensures that
+ // VEX-prefixed instructions are emitted if AVX is supported
emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ControlFlow.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,21 +22,21 @@
*/
package org.graalvm.compiler.lir.amd64;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
import org.graalvm.compiler.asm.Label;
-import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.code.CompilationResult.JumpTable;
+import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIRInstructionClass;
@@ -312,6 +312,42 @@
}
}
+ @Opcode("SETcc")
+ public static final class CondSetOp extends AMD64LIRInstruction {
+ public static final LIRInstructionClass<CondSetOp> TYPE = LIRInstructionClass.create(CondSetOp.class);
+ @Def({REG, HINT}) protected Value result;
+ private final ConditionFlag condition;
+
+ public CondSetOp(Variable result, Condition condition) {
+ super(TYPE);
+ this.result = result;
+ this.condition = intCond(condition);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ setcc(masm, result, condition);
+ }
+ }
+
+ @Opcode("SETcc")
+ public static final class FloatCondSetOp extends AMD64LIRInstruction {
+ public static final LIRInstructionClass<FloatCondSetOp> TYPE = LIRInstructionClass.create(FloatCondSetOp.class);
+ @Def({REG, HINT}) protected Value result;
+ private final ConditionFlag condition;
+
+ public FloatCondSetOp(Variable result, Condition condition) {
+ super(TYPE);
+ this.result = result;
+ this.condition = floatCond(condition);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ setcc(masm, result, condition);
+ }
+ }
+
@Opcode("CMOVE")
public static final class CondMoveOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<CondMoveOp> TYPE = LIRInstructionClass.create(CondMoveOp.class);
@@ -418,6 +454,21 @@
}
}
+ private static void setcc(AMD64MacroAssembler masm, Value result, ConditionFlag cond) {
+ switch ((AMD64Kind) result.getPlatformKind()) {
+ case BYTE:
+ case WORD:
+ case DWORD:
+ masm.setl(cond, asRegister(result));
+ break;
+ case QWORD:
+ masm.setq(cond, asRegister(result));
+ break;
+ default:
+ throw GraalError.shouldNotReachHere();
+ }
+ }
+
private static ConditionFlag intCond(Condition cond) {
switch (cond) {
case EQ:
@@ -464,6 +515,10 @@
}
}
+ public static boolean trueOnUnordered(Condition condition) {
+ return trueOnUnordered(floatCond(condition));
+ }
+
private static boolean trueOnUnordered(ConditionFlag condition) {
switch (condition) {
case AboveEqual:
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,8 +22,11 @@
*/
package org.graalvm.compiler.lir.amd64;
+import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
@@ -35,12 +38,16 @@
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.LIRKindTool;
import org.graalvm.compiler.core.common.type.DataPointerConstant;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIRFrameState;
@@ -740,4 +747,110 @@
throw GraalError.shouldNotReachHere("Unknown result Kind: " + result.getPlatformKind());
}
}
+
+ public abstract static class Pointer extends AMD64LIRInstruction {
+ protected final LIRKindTool lirKindTool;
+ protected final CompressEncoding encoding;
+ protected final boolean nonNull;
+
+ @Def({REG, HINT}) private AllocatableValue result;
+ @Use({REG}) private AllocatableValue input;
+ @Alive({REG, ILLEGAL}) private AllocatableValue baseRegister;
+
+ protected Pointer(LIRInstructionClass<? extends Pointer> type, AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull,
+ LIRKindTool lirKindTool) {
+ super(type);
+ this.result = result;
+ this.input = input;
+ this.baseRegister = baseRegister;
+ this.encoding = encoding;
+ this.nonNull = nonNull;
+ this.lirKindTool = lirKindTool;
+ }
+
+ protected boolean hasBase(CompilationResultBuilder crb) {
+ return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase();
+ }
+
+ protected final Register getResultRegister() {
+ return asRegister(result);
+ }
+
+ protected final Register getBaseRegister() {
+ return asRegister(baseRegister);
+ }
+
+ protected final int getShift() {
+ return encoding.getShift();
+ }
+
+ protected final void move(LIRKind kind, CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ AMD64Move.move((AMD64Kind) kind.getPlatformKind(), crb, masm, result, input);
+ }
+ }
+
+ public static final class CompressPointer extends Pointer {
+ public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+
+ public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+ super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ move(lirKindTool.getObjectKind(), crb, masm);
+
+ Register resReg = getResultRegister();
+ if (hasBase(crb)) {
+ Register baseReg = getBaseRegister();
+ if (!nonNull) {
+ masm.testq(resReg, resReg);
+ masm.cmovq(Equal, resReg, baseReg);
+ }
+ masm.subq(resReg, baseReg);
+ }
+
+ int shift = getShift();
+ if (shift != 0) {
+ masm.shrq(resReg, shift);
+ }
+ }
+ }
+
+ public static final class UncompressPointer extends Pointer {
+ public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+
+ public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+ super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+ move(lirKindTool.getNarrowOopKind(), crb, masm);
+
+ Register resReg = getResultRegister();
+ int shift = getShift();
+ if (shift != 0) {
+ masm.shlq(resReg, shift);
+ }
+
+ if (hasBase(crb)) {
+ Register baseReg = getBaseRegister();
+ if (nonNull) {
+ masm.addq(resReg, baseReg);
+ return;
+ }
+
+ if (shift == 0) {
+ // if encoding.shift != 0, the flags are already set by the shlq
+ masm.testq(resReg, resReg);
+ }
+
+ Label done = new Label();
+ masm.jccb(Equal, done);
+ masm.addq(resReg, baseReg);
+ masm.bind(done);
+ }
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLoadConstantTableBaseOp.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCLoadConstantTableBaseOp.java Mon Nov 06 20:29:49 2017 -0800
@@ -55,8 +55,8 @@
* this case absolute addressing (without using the base pointer is used). See also:
* CodeInstaller::pd_patch_DataSectionReference
*
- * @see SPARCMove#loadFromConstantTable(CompilationResultBuilder, SPARCMacroAssembler, int,
- * Register, jdk.vm.ci.meta.Constant, Register, SPARCDelayedControlTransfer)
+ * @see SPARCMove#loadFromConstantTable(CompilationResultBuilder, SPARCMacroAssembler, Register,
+ * jdk.vm.ci.meta.Constant, Register, SPARCDelayedControlTransfer)
*/
public class SPARCLoadConstantTableBaseOp extends SPARCLIRInstruction {
public static final LIRInstructionClass<SPARCLoadConstantTableBaseOp> TYPE = LIRInstructionClass.create(SPARCLoadConstantTableBaseOp.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCMove.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCMove.java Mon Nov 06 20:29:49 2017 -0800
@@ -53,6 +53,7 @@
import org.graalvm.compiler.asm.sparc.SPARCAssembler;
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler.ScratchRegister;
+import org.graalvm.compiler.code.DataSection.Data;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.DataPointerConstant;
import org.graalvm.compiler.debug.GraalError;
@@ -116,11 +117,11 @@
public static final LIRInstructionClass<LoadConstantFromTable> TYPE = LIRInstructionClass.create(LoadConstantFromTable.class);
public static final SizeEstimate SIZE = SizeEstimate.create(1, 8);
- private Constant constant;
+ private JavaConstant constant;
@Def({REG, STACK}) AllocatableValue result;
@Use({REG}) private AllocatableValue constantTableBase;
- public LoadConstantFromTable(Constant constant, AllocatableValue constantTableBase, AllocatableValue result) {
+ public LoadConstantFromTable(JavaConstant constant, AllocatableValue constantTableBase, AllocatableValue result) {
super(TYPE, SIZE);
this.constant = constant;
this.result = result;
@@ -134,11 +135,11 @@
Register baseRegister = asRegister(constantTableBase);
if (isRegister(result)) {
Register resultRegister = asRegister(result);
- loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, resultRegister, getDelayedControlTransfer());
+ loadFromConstantTable(crb, masm, baseRegister, constant, resultRegister, getDelayedControlTransfer());
} else if (isStackSlot(result)) {
try (ScratchRegister scratch = masm.getScratchRegister()) {
Register scratchRegister = scratch.getRegister();
- loadFromConstantTable(crb, masm, byteCount, baseRegister, constant, scratchRegister, getDelayedControlTransfer());
+ loadFromConstantTable(crb, masm, baseRegister, constant, scratchRegister, getDelayedControlTransfer());
StackSlot slot = asStackSlot(result);
reg2stack(crb, masm, slot, scratchRegister.asValue(), getDelayedControlTransfer());
}
@@ -642,7 +643,6 @@
boolean hasVIS1 = cpuFeatures.contains(CPUFeature.VIS1);
boolean hasVIS3 = cpuFeatures.contains(CPUFeature.VIS3);
Register resultRegister = asRegister(result);
- int byteCount = result.getPlatformKind().getSizeInBytes();
switch (input.getJavaKind().getStackKind()) {
case Int:
if (input.isDefaultForKind()) {
@@ -655,7 +655,7 @@
if (constantTableBase.equals(g0)) {
throw GraalError.shouldNotReachHere();
} else {
- loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+ loadFromConstantTable(crb, masm, constantTableBase, input, resultRegister, delaySlotLir);
}
}
break;
@@ -667,7 +667,7 @@
delaySlotLir.emitControlTransfer(crb, masm);
masm.or(g0, (int) input.asLong(), resultRegister);
} else {
- loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+ loadFromConstantTable(crb, masm, constantTableBase, input, resultRegister, delaySlotLir);
}
break;
case Float: {
@@ -683,7 +683,7 @@
masm.movwtos(scratch, resultRegister);
} else {
// First load the address into the scratch register
- loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+ loadFromConstantTable(crb, masm, constantTableBase, input, resultRegister, delaySlotLir);
}
}
break;
@@ -700,7 +700,7 @@
delaySlotLir.emitControlTransfer(crb, masm);
masm.movxtod(scratch, resultRegister);
} else {
- loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+ loadFromConstantTable(crb, masm, constantTableBase, input, resultRegister, delaySlotLir);
}
}
break;
@@ -710,7 +710,7 @@
delaySlotLir.emitControlTransfer(crb, masm);
masm.clr(resultRegister);
} else {
- loadFromConstantTable(crb, masm, byteCount, constantTableBase, input, resultRegister, delaySlotLir);
+ loadFromConstantTable(crb, masm, constantTableBase, input, resultRegister, delaySlotLir);
}
break;
default:
@@ -768,25 +768,30 @@
* patterns used for small constant sections (<8k) and large constant sections (>=8k). The
* generated patterns by this method must be understood by
* CodeInstaller::pd_patch_DataSectionReference (jvmciCodeInstaller_sparc.cpp).
+ *
+ * @return the number of bytes loaded from the constant table
*/
- public static void loadFromConstantTable(CompilationResultBuilder crb, SPARCMacroAssembler masm, int byteCount, Register constantTableBase, Constant input, Register dest,
+ public static int loadFromConstantTable(CompilationResultBuilder crb, SPARCMacroAssembler masm, Register constantTableBase, Constant input, Register dest,
SPARCDelayedControlTransfer delaySlotInstruction) {
SPARCAddress address;
ScratchRegister scratch = null;
try {
+ Data data = crb.createDataItem(input);
+ int size = data.getSize();
if (masm.isImmediateConstantLoad()) {
address = new SPARCAddress(constantTableBase, 0);
// Make delayed only, when using immediate constant load.
delaySlotInstruction.emitControlTransfer(crb, masm);
- crb.recordDataReferenceInCode(input, byteCount);
+ crb.recordDataReferenceInCode(data, size);
} else {
scratch = masm.getScratchRegister();
Register sr = scratch.getRegister();
- crb.recordDataReferenceInCode(input, byteCount);
+ crb.recordDataReferenceInCode(data, size);
masm.sethix(0, sr, true);
address = new SPARCAddress(sr, 0);
}
- masm.ld(address, dest, byteCount, false);
+ masm.ld(address, dest, size, false);
+ return size;
} finally {
if (scratch != null) {
scratch.close();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRValueUtil.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRValueUtil.java Mon Nov 06 20:29:49 2017 -0800
@@ -69,6 +69,16 @@
return asConstantValue(value).getJavaConstant();
}
+ public static boolean isIntConstant(Value value, long expected) {
+ if (isJavaConstant(value)) {
+ JavaConstant javaConstant = asJavaConstant(value);
+ if (javaConstant != null && javaConstant.getJavaKind().isNumericInteger()) {
+ return javaConstant.asLong() == expected;
+ }
+ }
+ return false;
+ }
+
public static boolean isStackSlotValue(Value value) {
assert value != null;
return value instanceof StackSlot || value instanceof VirtualStackSlot;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java Mon Nov 06 20:29:49 2017 -0800
@@ -30,6 +30,7 @@
import java.util.Collections;
import java.util.EnumSet;
+import jdk.vm.ci.code.RegisterConfig;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.debug.CounterKey;
@@ -138,8 +139,8 @@
private void doOptimize(LIR lir) {
DebugContext debug = lir.getDebug();
try (Indent indent = debug.logAndIndent("eliminate redundant moves")) {
-
- callerSaveRegs = frameMap.getRegisterConfig().getCallerSaveRegisters();
+ RegisterConfig registerConfig = frameMap.getRegisterConfig();
+ callerSaveRegs = registerConfig.getCallerSaveRegisters();
initBlockData(lir);
@@ -147,7 +148,7 @@
// Unallocatable registers should never be optimized.
eligibleRegs = new int[numRegs];
Arrays.fill(eligibleRegs, -1);
- for (Register reg : frameMap.getRegisterConfig().getAllocatableRegisters()) {
+ for (Register reg : registerConfig.getAllocatableRegisters()) {
if (reg.number < numRegs) {
eligibleRegs[reg.number] = reg.number;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/SaveCalleeSaveRegisters.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/SaveCalleeSaveRegisters.java Mon Nov 06 20:29:49 2017 -0800
@@ -31,7 +31,6 @@
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.StandardOp;
import org.graalvm.compiler.lir.Variable;
-import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase;
@@ -48,8 +47,7 @@
@Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
- FrameMapBuilder frameMapBuilder = lirGenRes.getFrameMapBuilder();
- RegisterArray calleeSaveRegisters = frameMapBuilder.getCodeCache().getRegisterConfig().getCalleeSaveRegisters();
+ RegisterArray calleeSaveRegisters = lirGenRes.getRegisterConfig().getCalleeSaveRegisters();
if (calleeSaveRegisters == null || calleeSaveRegisters.size() == 0) {
return;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java Mon Nov 06 20:29:49 2017 -0800
@@ -80,10 +80,10 @@
*/
public class CompilationResultBuilder {
- // @formatter:off
- @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug)
- public static final OptionKey<Boolean> PrintLIRWithAssembly = new OptionKey<>(false);
- // @formatter:on
+ public static class Options {
+ @Option(help = "Include the LIR as comments with the final assembly.", type = OptionType.Debug) //
+ public static final OptionKey<Boolean> PrintLIRWithAssembly = new OptionKey<>(false);
+ }
private static class ExceptionInfo {
@@ -295,13 +295,24 @@
public AbstractAddress recordDataReferenceInCode(Constant constant, int alignment) {
assert constant != null;
debug.log("Constant reference in code: pos = %d, data = %s", asm.position(), constant);
+ Data data = createDataItem(constant);
+ data.updateAlignment(alignment);
+ return recordDataSectionReference(data);
+ }
+
+ public AbstractAddress recordDataReferenceInCode(Data data, int alignment) {
+ assert data != null;
+ data.updateAlignment(alignment);
+ return recordDataSectionReference(data);
+ }
+
+ public Data createDataItem(Constant constant) {
Data data = dataCache.get(constant);
if (data == null) {
data = dataBuilder.createDataItem(constant);
dataCache.put(constant, data);
}
- data.updateAlignment(alignment);
- return recordDataSectionReference(data);
+ return data;
}
public AbstractAddress recordDataReferenceInCode(byte[] data, int alignment) {
@@ -472,7 +483,7 @@
if (block == null) {
return;
}
- boolean emitComment = debug.isDumpEnabled(DebugContext.BASIC_LEVEL) || PrintLIRWithAssembly.getValue(getOptions());
+ boolean emitComment = debug.isDumpEnabled(DebugContext.BASIC_LEVEL) || Options.PrintLIRWithAssembly.getValue(getOptions());
if (emitComment) {
blockComment(String.format("block B%d %s", block.getId(), block.getLoop()));
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/ArithmeticLIRGenerator.java Mon Nov 06 20:29:49 2017 -0800
@@ -50,8 +50,19 @@
protected abstract Variable emitAdd(LIRKind resultKind, Value a, Value b, boolean setFlags);
+ protected abstract Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags);
+
@Override
public final Variable emitAdd(Value aVal, Value bVal, boolean setFlags) {
+ return emitAddOrSub(aVal, bVal, setFlags, true);
+ }
+
+ @Override
+ public final Variable emitSub(Value aVal, Value bVal, boolean setFlags) {
+ return emitAddOrSub(aVal, bVal, setFlags, false);
+ }
+
+ private Variable emitAddOrSub(Value aVal, Value bVal, boolean setFlags, boolean isAdd) {
LIRKind resultKind;
Value a = aVal;
Value b = bVal;
@@ -90,47 +101,7 @@
resultKind = LIRKind.combine(a, b);
}
- return emitAdd(resultKind, a, b, setFlags);
+ return isAdd ? emitAdd(resultKind, a, b, setFlags) : emitSub(resultKind, a, b, setFlags);
}
- protected abstract Variable emitSub(LIRKind resultKind, Value a, Value b, boolean setFlags);
-
- @Override
- public final Variable emitSub(Value aVal, Value bVal, boolean setFlags) {
- LIRKind resultKind;
- Value a = aVal;
- Value b = bVal;
-
- if (isNumericInteger(a.getPlatformKind())) {
- LIRKind aKind = a.getValueKind(LIRKind.class);
- LIRKind bKind = b.getValueKind(LIRKind.class);
- assert a.getPlatformKind() == b.getPlatformKind();
-
- if (aKind.isUnknownReference()) {
- resultKind = aKind;
- } else if (bKind.isUnknownReference()) {
- resultKind = bKind;
- }
-
- if (aKind.isValue() && bKind.isValue()) {
- resultKind = aKind;
- } else if (bKind.isValue()) {
- if (aKind.isDerivedReference()) {
- resultKind = aKind;
- } else {
- AllocatableValue allocatable = getLIRGen().asAllocatable(a);
- resultKind = aKind.makeDerivedReference(allocatable);
- a = allocatable;
- }
- } else if (aKind.isDerivedReference() && bKind.isDerivedReference() && aKind.getDerivedReferenceBase().equals(bKind.getDerivedReferenceBase())) {
- resultKind = LIRKind.value(a.getPlatformKind());
- } else {
- resultKind = aKind.makeUnknownReference();
- }
- } else {
- resultKind = LIRKind.combine(a, b);
- }
-
- return emitSub(resultKind, a, b, setFlags);
- }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.lir.gen;
+import jdk.vm.ci.code.RegisterConfig;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
import org.graalvm.compiler.debug.DebugContext;
@@ -123,6 +124,10 @@
return frameMap;
}
+ public final RegisterConfig getRegisterConfig() {
+ return frameMapBuilder.getRegisterConfig();
+ }
+
public LIR getLIR() {
return lir;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerator.java Mon Nov 06 20:29:49 2017 -0800
@@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.List;
+import jdk.vm.ci.code.RegisterConfig;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
@@ -201,8 +202,13 @@
}
@Override
+ public RegisterConfig getRegisterConfig() {
+ return res.getRegisterConfig();
+ }
+
+ @Override
public RegisterAttributes attributes(Register register) {
- return res.getFrameMapBuilder().getRegisterConfig().getAttributesMap()[register.number];
+ return getRegisterConfig().getAttributesMap()[register.number];
}
@Override
@@ -228,7 +234,7 @@
if (moveFactory.canInlineConstant(constant)) {
return new ConstantValue(toRegisterKind(kind), constant);
} else {
- return emitLoadConstant(kind, constant);
+ return emitLoadConstant(toRegisterKind(kind), constant);
}
}
@@ -289,7 +295,7 @@
*/
@Override
public AllocatableValue resultOperandFor(JavaKind javaKind, ValueKind<?> valueKind) {
- Register reg = res.getFrameMapBuilder().getRegisterConfig().getReturnRegister(javaKind);
+ Register reg = getRegisterConfig().getReturnRegister(javaKind);
assert target().arch.canStoreValue(reg.getRegisterCategory(), valueKind.getPlatformKind()) : reg.getRegisterCategory() + " " + valueKind.getPlatformKind();
return reg.asValue(valueKind);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.lir.gen;
+import jdk.vm.ci.code.RegisterConfig;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
@@ -109,6 +110,8 @@
LIRGenerationResult getResult();
+ RegisterConfig getRegisterConfig();
+
boolean hasBlockEnd(AbstractBlockBase<?> block);
MoveFactory getMoveFactory();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -214,7 +214,7 @@
}
};
ResolvedJavaMethod method = getResolvedJavaMethod(name);
- OptionValues options = new OptionValues(getInitialOptions(), DefaultLoopPolicies.UnrollMaxIterations, 2);
+ OptionValues options = new OptionValues(getInitialOptions(), DefaultLoopPolicies.Options.UnrollMaxIterations, 2);
StructuredGraph graph = parse(builder(method, StructuredGraph.AllowAssumptions.YES, id, options), getEagerGraphBuilderSuite());
try (DebugContext.Scope buildScope = graph.getDebug().scope(name, method, graph)) {
MidTierContext context = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, null);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Mon Nov 06 20:29:49 2017 -0800
@@ -83,7 +83,11 @@
range = add(graph, range, oneDirection);
}
// round-away-from-zero divison: (range + stride -/+ 1) / stride
- ValueNode denominator = add(graph, sub(graph, range, oneDirection), iv.strideNode());
+ ValueNode denominator = range;
+ if (!oneDirection.stamp().equals(iv.strideNode().stamp())) {
+ ValueNode subedRanged = sub(graph, range, oneDirection);
+ denominator = add(graph, subedRanged, iv.strideNode());
+ }
ValueNode div = divBefore(graph, loop.entryPoint(), denominator, iv.strideNode());
if (assumePositive) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java Mon Nov 06 20:29:49 2017 -0800
@@ -55,16 +55,19 @@
import jdk.vm.ci.meta.MetaAccessProvider;
public class DefaultLoopPolicies implements LoopPolicies {
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> LoopUnswitchMaxIncrease = new OptionKey<>(500);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> LoopUnswitchTrivial = new OptionKey<>(10);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Double> LoopUnswitchFrequencyBoost = new OptionKey<>(10.0);
+
+ public static class Options {
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> LoopUnswitchMaxIncrease = new OptionKey<>(500);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> LoopUnswitchTrivial = new OptionKey<>(10);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Double> LoopUnswitchFrequencyBoost = new OptionKey<>(10.0);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> FullUnrollMaxNodes = new OptionKey<>(300);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> FullUnrollMaxIterations = new OptionKey<>(600);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> ExactFullUnrollMaxNodes = new OptionKey<>(1200);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> ExactPartialUnrollMaxNodes = new OptionKey<>(200);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> FullUnrollMaxNodes = new OptionKey<>(300);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> FullUnrollMaxIterations = new OptionKey<>(600);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> ExactFullUnrollMaxNodes = new OptionKey<>(1200);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> ExactPartialUnrollMaxNodes = new OptionKey<>(200);
- @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> UnrollMaxIterations = new OptionKey<>(16);
+ @Option(help = "", type = OptionType.Expert) public static final OptionKey<Integer> UnrollMaxIterations = new OptionKey<>(16);
+ }
@Override
public boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess) {
@@ -87,10 +90,10 @@
OptionValues options = loop.entryPoint().getOptions();
CountedLoopInfo counted = loop.counted();
long maxTrips = counted.constantMaxTripCount();
- int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? ExactFullUnrollMaxNodes.getValue(options) : FullUnrollMaxNodes.getValue(options);
+ int maxNodes = (counted.isExactTripCount() && counted.isConstantExactTripCount()) ? Options.ExactFullUnrollMaxNodes.getValue(options) : Options.FullUnrollMaxNodes.getValue(options);
maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount()));
int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
- if (maxTrips <= FullUnrollMaxIterations.getValue(options) && size * (maxTrips - 1) <= maxNodes) {
+ if (maxTrips <= Options.FullUnrollMaxIterations.getValue(options) && size * (maxTrips - 1) <= maxNodes) {
// check whether we're allowed to unroll this loop
return loop.canDuplicateLoop();
} else {
@@ -106,7 +109,7 @@
return false;
}
OptionValues options = loop.entryPoint().getOptions();
- int maxNodes = ExactPartialUnrollMaxNodes.getValue(options);
+ int maxNodes = Options.ExactPartialUnrollMaxNodes.getValue(options);
maxNodes = Math.min(maxNodes, Math.max(0, MaximumDesiredSize.getValue(options) - loop.loopBegin().graph().getNodeCount()));
int size = Math.max(1, loop.size() - 1 - loop.loopBegin().phis().count());
int unrollFactor = loopBegin.getUnrollFactor();
@@ -118,7 +121,7 @@
}
loopBegin.setLoopOrigFrequency(loopFrequency);
}
- int maxUnroll = UnrollMaxIterations.getValue(options);
+ int maxUnroll = Options.UnrollMaxIterations.getValue(options);
// Now correct size for the next unroll. UnrollMaxIterations == 1 means perform the
// pre/main/post transformation but don't actually unroll the main loop.
size += size;
@@ -190,9 +193,9 @@
CountingClosure stateNodesCount = new CountingClosure();
double loopFrequency = loop.loopBegin().loopFrequency();
OptionValues options = loop.loopBegin().getOptions();
- int maxDiff = LoopUnswitchTrivial.getValue(options) + (int) (LoopUnswitchFrequencyBoost.getValue(options) * (loopFrequency - 1.0 + phis));
+ int maxDiff = Options.LoopUnswitchTrivial.getValue(options) + (int) (Options.LoopUnswitchFrequencyBoost.getValue(options) * (loopFrequency - 1.0 + phis));
- maxDiff = Math.min(maxDiff, LoopUnswitchMaxIncrease.getValue(options));
+ maxDiff = Math.min(maxDiff, Options.LoopUnswitchMaxIncrease.getValue(options));
int remainingGraphSpace = MaximumDesiredSize.getValue(options) - graph.getNodeCount();
maxDiff = Math.min(maxDiff, remainingGraphSpace);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo/src/org/graalvm/compiler/nodeinfo/NodeCycles.java Mon Nov 06 20:29:49 2017 -0800
@@ -68,6 +68,10 @@
this.value = value;
}
+ public boolean isValueKnown() {
+ return this != NodeCycles.CYCLES_UNKNOWN && this != NodeCycles.CYCLES_UNSET;
+ }
+
public static final int IGNORE_CYCLES_CONTRACT_FACTOR = 0xFFFF;
public static NodeCycles compute(NodeCycles base, int opCount) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -552,4 +552,21 @@
return result.longValue();
}
}
+
+ @Test
+ public void testDiv() {
+ testDiv(32, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ testDiv(64, Long.MIN_VALUE, Long.MAX_VALUE);
+ }
+
+ private static void testDiv(int bits, long min, long max) {
+ BinaryOp<?> div = IntegerStamp.OPS.getDiv();
+ assertEquals(IntegerStamp.create(bits, -50, 50), div.foldStamp(IntegerStamp.create(bits, -100, 100), IntegerStamp.create(bits, 2, 5)));
+ assertEquals(IntegerStamp.create(bits, 20, 500), div.foldStamp(IntegerStamp.create(bits, 100, 1000), IntegerStamp.create(bits, 2, 5)));
+ assertEquals(IntegerStamp.create(bits, -500, -20), div.foldStamp(IntegerStamp.create(bits, -1000, -100), IntegerStamp.create(bits, 2, 5)));
+ assertEquals(IntegerStamp.create(bits, min, max), div.foldStamp(IntegerStamp.create(bits, min, max), IntegerStamp.create(bits, 1, max)));
+ assertEquals(IntegerStamp.create(bits, -100, 100), div.foldStamp(IntegerStamp.create(bits, -100, 100), IntegerStamp.create(bits, 1, max)));
+ assertEquals(IntegerStamp.create(bits, 0, 1000), div.foldStamp(IntegerStamp.create(bits, 100, 1000), IntegerStamp.create(bits, 1, max)));
+ assertEquals(IntegerStamp.create(bits, -1000, 0), div.foldStamp(IntegerStamp.create(bits, -1000, -100), IntegerStamp.create(bits, 1, max)));
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/PrimitiveStampBoundaryTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.test;
+
+import java.util.EnumSet;
+import java.util.HashSet;
+
+import org.graalvm.compiler.core.common.calc.FloatConvert;
+import org.graalvm.compiler.core.common.calc.FloatConvertCategory;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.core.common.type.PrimitiveStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.test.GraalTest;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Exercise the various stamp folding operations by generating ranges from a set of boundary values
+ * and then ensuring that the values that produced those ranges are in the resulting stamp.
+ */
+public class PrimitiveStampBoundaryTest extends GraalTest {
+
+ static long[] longBoundaryValues = {Long.MIN_VALUE, Long.MIN_VALUE + 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1, 0, 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE, Long.MAX_VALUE - 1,
+ Long.MAX_VALUE};
+
+ static int[] shiftBoundaryValues = {-128, -1, 0, 1, 4, 8, 16, 31, 63, 128};
+
+ static HashSet<IntegerStamp> shiftStamps;
+ static HashSet<PrimitiveStamp> integerTestStamps;
+ static HashSet<PrimitiveStamp> floatTestStamps;
+
+ static {
+ shiftStamps = new HashSet<>();
+ for (long v1 : shiftBoundaryValues) {
+ for (long v2 : shiftBoundaryValues) {
+ shiftStamps.add(IntegerStamp.create(32, Math.min(v1, v2), Math.max(v1, v2)));
+ }
+ }
+
+ integerTestStamps = new HashSet<>();
+ for (long v1 : longBoundaryValues) {
+ for (long v2 : longBoundaryValues) {
+ if (v2 == (int) v2 && v1 == (int) v1) {
+ integerTestStamps.add(IntegerStamp.create(32, Math.min(v1, v2), Math.max(v1, v2)));
+ }
+ integerTestStamps.add(IntegerStamp.create(64, Math.min(v1, v2), Math.max(v1, v2)));
+ }
+ }
+ }
+
+ static double[] doubleBoundaryValues = {Double.NEGATIVE_INFINITY, Double.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.MIN_VALUE,
+ Long.MIN_VALUE, Long.MIN_VALUE + 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1, 0, 1,
+ Integer.MAX_VALUE - 1, Integer.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE,
+ Float.MAX_VALUE, Float.POSITIVE_INFINITY, Double.MAX_VALUE, Double.POSITIVE_INFINITY};
+
+ static double[] doubleSpecialValues = {Double.NaN, -0.0, -0.0F, Float.NaN};
+
+ static {
+ floatTestStamps = new HashSet<>();
+
+ for (double d1 : doubleBoundaryValues) {
+ for (double d2 : doubleBoundaryValues) {
+ float f1 = (float) d2;
+ float f2 = (float) d1;
+ if (d2 == f1 && d1 == f2) {
+ generateFloatingStamps(new FloatStamp(32, Math.min(f2, f1), Math.max(f2, f1), true));
+ generateFloatingStamps(new FloatStamp(32, Math.min(f2, f1), Math.max(f2, f1), false));
+ }
+ generateFloatingStamps(new FloatStamp(64, Math.min(d1, d2), Math.max(d1, d2), true));
+ generateFloatingStamps(new FloatStamp(64, Math.min(d1, d2), Math.max(d1, d2), false));
+ }
+ }
+ }
+
+ private static void generateFloatingStamps(FloatStamp floatStamp) {
+ floatTestStamps.add(floatStamp);
+ for (double d : doubleSpecialValues) {
+ FloatStamp newStamp = (FloatStamp) floatStamp.meet(floatStampForConstant(d, floatStamp.getBits()));
+ if (!newStamp.isUnrestricted()) {
+ floatTestStamps.add(newStamp);
+ }
+ }
+ }
+
+ @Test
+ public void testConvertBoundaryValues() {
+ testConvertBoundaryValues(IntegerStamp.OPS.getSignExtend(), 32, 64, integerTestStamps);
+ testConvertBoundaryValues(IntegerStamp.OPS.getZeroExtend(), 32, 64, integerTestStamps);
+ testConvertBoundaryValues(IntegerStamp.OPS.getNarrow(), 64, 32, integerTestStamps);
+ }
+
+ private static void testConvertBoundaryValues(IntegerConvertOp<?> op, int inputBits, int resultBits, HashSet<PrimitiveStamp> stamps) {
+ for (PrimitiveStamp stamp : stamps) {
+ if (inputBits == stamp.getBits()) {
+ Stamp lower = boundaryStamp(stamp, false);
+ Stamp upper = boundaryStamp(stamp, true);
+ checkConvertOperation(op, inputBits, resultBits, op.foldStamp(inputBits, resultBits, stamp), lower);
+ checkConvertOperation(op, inputBits, resultBits, op.foldStamp(inputBits, resultBits, stamp), upper);
+ }
+ }
+ }
+
+ private static void checkConvertOperation(IntegerConvertOp<?> op, int inputBits, int resultBits, Stamp result, Stamp v1stamp) {
+ Stamp folded = op.foldStamp(inputBits, resultBits, v1stamp);
+ assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
+ assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
+ }
+
+ @Test
+ public void testFloatConvertBoundaryValues() {
+ for (FloatConvert op : EnumSet.allOf(FloatConvert.class)) {
+ ArithmeticOpTable.FloatConvertOp floatConvert = IntegerStamp.OPS.getFloatConvert(op);
+ if (floatConvert == null) {
+ continue;
+ }
+ assert op.getCategory() == FloatConvertCategory.IntegerToFloatingPoint : op;
+ testConvertBoundaryValues(floatConvert, op.getInputBits(), integerTestStamps);
+ }
+ for (FloatConvert op : EnumSet.allOf(FloatConvert.class)) {
+ ArithmeticOpTable.FloatConvertOp floatConvert = FloatStamp.OPS.getFloatConvert(op);
+ if (floatConvert == null) {
+ continue;
+ }
+ assert op.getCategory() == FloatConvertCategory.FloatingPointToInteger || op.getCategory() == FloatConvertCategory.FloatingPointToFloatingPoint : op;
+ testConvertBoundaryValues(floatConvert, op.getInputBits(), floatTestStamps);
+ }
+ }
+
+ private static void testConvertBoundaryValues(ArithmeticOpTable.FloatConvertOp op, int bits, HashSet<PrimitiveStamp> stamps) {
+ for (PrimitiveStamp stamp : stamps) {
+ if (bits == stamp.getBits()) {
+ Stamp lower = boundaryStamp(stamp, false);
+ Stamp upper = boundaryStamp(stamp, true);
+ checkConvertOperation(op, op.foldStamp(stamp), lower);
+ checkConvertOperation(op, op.foldStamp(stamp), upper);
+ }
+ }
+ }
+
+ private static void checkConvertOperation(ArithmeticOpTable.FloatConvertOp op, Stamp result, Stamp v1stamp) {
+ Stamp folded = op.foldStamp(v1stamp);
+ assertTrue(folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
+ assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
+ }
+
+ @Test
+ public void testShiftBoundaryValues() {
+ for (ShiftOp<?> op : IntegerStamp.OPS.getShiftOps()) {
+ testShiftBoundaryValues(op, integerTestStamps, shiftStamps);
+ }
+ }
+
+ private static void testShiftBoundaryValues(ShiftOp<?> shiftOp, HashSet<PrimitiveStamp> stamps, HashSet<IntegerStamp> shifts) {
+ for (PrimitiveStamp testStamp : stamps) {
+ if (testStamp instanceof IntegerStamp) {
+ IntegerStamp stamp = (IntegerStamp) testStamp;
+ for (IntegerStamp shiftStamp : shifts) {
+ IntegerStamp foldedStamp = (IntegerStamp) shiftOp.foldStamp(stamp, shiftStamp);
+ checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.lowerBound());
+ checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.lowerBound(), shiftStamp.upperBound());
+ checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.upperBound(), shiftStamp.lowerBound());
+ checkShiftOperation(stamp.getBits(), shiftOp, foldedStamp, stamp.upperBound(), shiftStamp.upperBound());
+ }
+ }
+ }
+ }
+
+ private static void checkShiftOperation(int bits, ShiftOp<?> op, IntegerStamp result, long v1, long v2) {
+ IntegerStamp v1stamp = IntegerStamp.create(bits, v1, v1);
+ IntegerStamp v2stamp = IntegerStamp.create(32, v2, v2);
+ IntegerStamp folded = (IntegerStamp) op.foldStamp(v1stamp, v2stamp);
+ Constant constant = op.foldConstant(JavaConstant.forPrimitiveInt(bits, v1), (int) v2);
+ assertTrue(constant != null);
+ assertTrue(folded.asConstant() != null, "should constant fold %s %s %s %s", op, v1stamp, v2stamp, folded);
+ assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s %s", op, v1stamp, v2stamp, folded, result, result.meet(folded));
+ }
+
+ private static void checkBinaryOperation(ArithmeticOpTable.BinaryOp<?> op, Stamp result, Stamp v1stamp, Stamp v2stamp) {
+ Stamp folded = op.foldStamp(v1stamp, v2stamp);
+ Constant constant = op.foldConstant(v1stamp.asConstant(), v2stamp.asConstant());
+ if (constant != null) {
+ Constant constant2 = folded.asConstant();
+ if (constant2 == null && v1stamp instanceof FloatStamp) {
+ JavaConstant c = (JavaConstant) constant;
+ assertTrue((c.getJavaKind() == JavaKind.Double && Double.isNaN(c.asDouble())) ||
+ (c.getJavaKind() == JavaKind.Float && Float.isNaN(c.asFloat())));
+ } else {
+ assertTrue(constant2 != null, "should constant fold %s %s %s %s", op, v1stamp, v2stamp, folded);
+ if (!constant.equals(constant2)) {
+ op.foldConstant(v1stamp.asConstant(), v2stamp.asConstant());
+ op.foldStamp(v1stamp, v2stamp);
+ }
+ assertTrue(constant.equals(constant2), "should produce same constant %s %s %s %s %s", op, v1stamp, v2stamp, constant, constant2);
+ }
+ assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s %s", op, v1stamp, v2stamp, folded, result, result.meet(folded));
+ }
+ }
+
+ @Test
+ public void testBinaryBoundaryValues() {
+ for (BinaryOp<?> op : IntegerStamp.OPS.getBinaryOps()) {
+ if (op != null) {
+ testBinaryBoundaryValues(op, integerTestStamps);
+ }
+ }
+ for (BinaryOp<?> op : FloatStamp.OPS.getBinaryOps()) {
+ if (op != null) {
+ testBinaryBoundaryValues(op, floatTestStamps);
+ }
+ }
+ }
+
+ private static Stamp boundaryStamp(Stamp v1, boolean upper) {
+ if (v1 instanceof IntegerStamp) {
+ IntegerStamp istamp = (IntegerStamp) v1;
+ long bound = upper ? istamp.upperBound() : istamp.lowerBound();
+ return IntegerStamp.create(istamp.getBits(), bound, bound);
+ } else if (v1 instanceof FloatStamp) {
+ FloatStamp floatStamp = (FloatStamp) v1;
+ double bound = upper ? floatStamp.upperBound() : floatStamp.lowerBound();
+ int bits = floatStamp.getBits();
+ return floatStampForConstant(bound, bits);
+ } else {
+ throw new InternalError("unexpected stamp type " + v1);
+ }
+ }
+
+ private static FloatStamp floatStampForConstant(double bound, int bits) {
+ if (bits == 32) {
+ float fbound = (float) bound;
+ return new FloatStamp(bits, fbound, fbound, !Float.isNaN(fbound));
+ } else {
+ return new FloatStamp(bits, bound, bound, !Double.isNaN(bound));
+ }
+ }
+
+ private static void testBinaryBoundaryValues(ArithmeticOpTable.BinaryOp<?> op, HashSet<PrimitiveStamp> stamps) {
+ for (PrimitiveStamp v1 : stamps) {
+ for (PrimitiveStamp v2 : stamps) {
+ if (v1.getBits() == v2.getBits() && v1.getClass() == v2.getClass()) {
+ Stamp result = op.foldStamp(v1, v2);
+ Stamp v1lower = boundaryStamp(v1, false);
+ Stamp v1upper = boundaryStamp(v1, true);
+ Stamp v2lower = boundaryStamp(v2, false);
+ Stamp v2upper = boundaryStamp(v2, true);
+ checkBinaryOperation(op, result, v1lower, v2lower);
+ checkBinaryOperation(op, result, v1lower, v2upper);
+ checkBinaryOperation(op, result, v1upper, v2lower);
+ checkBinaryOperation(op, result, v1upper, v2upper);
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testUnaryBoundaryValues() {
+ for (ArithmeticOpTable.UnaryOp<?> op : IntegerStamp.OPS.getUnaryOps()) {
+ if (op != null) {
+ testUnaryBoundaryValues(op, integerTestStamps);
+ }
+ }
+ for (ArithmeticOpTable.UnaryOp<?> op : FloatStamp.OPS.getUnaryOps()) {
+ if (op != null) {
+ testUnaryBoundaryValues(op, floatTestStamps);
+ }
+ }
+ }
+
+ private static void testUnaryBoundaryValues(ArithmeticOpTable.UnaryOp<?> op, HashSet<PrimitiveStamp> stamps) {
+ for (PrimitiveStamp v1 : stamps) {
+ Stamp result = op.foldStamp(v1);
+ checkUnaryOperation(op, result, boundaryStamp(v1, false));
+ checkUnaryOperation(op, result, boundaryStamp(v1, true));
+ }
+ }
+
+ private static void checkUnaryOperation(ArithmeticOpTable.UnaryOp<?> op, Stamp result, Stamp v1stamp) {
+ Stamp folded = op.foldStamp(v1stamp);
+ Constant v1constant = v1stamp.asConstant();
+ if (v1constant != null) {
+ Constant constant = op.foldConstant(v1constant);
+ if (constant != null) {
+ Constant constant2 = folded.asConstant();
+ if (constant2 == null && v1stamp instanceof FloatStamp) {
+ JavaConstant c = (JavaConstant) constant;
+ assertTrue((c.getJavaKind() == JavaKind.Double && Double.isNaN(c.asDouble())) ||
+ (c.getJavaKind() == JavaKind.Float && Float.isNaN(c.asFloat())));
+ } else {
+ assertTrue(constant2 != null, "should constant fold %s %s %s", op, v1stamp, folded);
+ assertTrue(constant.equals(constant2), "should produce same constant %s %s %s %s", op, v1stamp, constant, constant2);
+ }
+ }
+ } else {
+ assert v1stamp instanceof FloatStamp;
+ }
+ assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/CompressionNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -122,9 +122,9 @@
// We always want uncompressed constants
return this;
}
- int stableDimension = ((ConstantNode) forValue).getStableDimension();
- boolean isDefaultStable = ((ConstantNode) forValue).isDefaultStable();
- return ConstantNode.forConstant(stamp(), convert(forValue.asConstant(), tool.getConstantReflection()), stableDimension, isDefaultStable, tool.getMetaAccess());
+
+ ConstantNode constant = (ConstantNode) forValue;
+ return ConstantNode.forConstant(stamp(), convert(constant.getValue(), tool.getConstantReflection()), constant.getStableDimension(), constant.isDefaultStable(), tool.getMetaAccess());
} else if (forValue instanceof CompressionNode) {
CompressionNode other = (CompressionNode) forValue;
if (op != other.op && encoding.equals(other.encoding)) {
@@ -136,22 +136,22 @@
@Override
public void generate(NodeLIRBuilderTool gen) {
- LIRGeneratorTool hsGen = gen.getLIRGeneratorTool();
boolean nonNull;
- if (getValue().stamp() instanceof AbstractObjectStamp) {
- nonNull = StampTool.isPointerNonNull(getValue().stamp());
+ if (value.stamp() instanceof AbstractObjectStamp) {
+ nonNull = StampTool.isPointerNonNull(value.stamp());
} else {
// metaspace pointers are never null
nonNull = true;
}
+ LIRGeneratorTool tool = gen.getLIRGeneratorTool();
Value result;
switch (op) {
case Compress:
- result = hsGen.emitCompress(gen.operand(getValue()), encoding, nonNull);
+ result = tool.emitCompress(gen.operand(value), encoding, nonNull);
break;
case Uncompress:
- result = hsGen.emitUncompress(gen.operand(getValue()), encoding, nonNull);
+ result = tool.emitUncompress(gen.operand(value), encoding, nonNull);
break;
default:
throw GraalError.shouldNotReachHere();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConstantNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ConstantNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -54,7 +54,7 @@
/**
* The {@code ConstantNode} represents a {@link Constant constant}.
*/
-@NodeInfo(nameTemplate = "C({p#rawvalue})", cycles = CYCLES_0, size = SIZE_1)
+@NodeInfo(nameTemplate = "C({p#rawvalue}) {p#stampKind}", cycles = CYCLES_0, size = SIZE_1)
public final class ConstantNode extends FloatingNode implements LIRLowerable {
public static final NodeClass<ConstantNode> TYPE = NodeClass.create(ConstantNode.class);
@@ -518,13 +518,14 @@
public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
Map<Object, Object> properties = super.getDebugProperties(map);
properties.put("rawvalue", value.toValueString());
+ properties.put("stampKind", stamp.unrestricted().toString());
return properties;
}
@Override
public String toString(Verbosity verbosity) {
if (verbosity == Verbosity.Name) {
- return super.toString(Verbosity.Name) + "(" + value.toValueString() + ")";
+ return super.toString(Verbosity.Name) + "(" + value.toValueString() + ", " + stamp().unrestricted().toString() + ")";
} else {
return super.toString(verbosity);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,7 +22,7 @@
*/
package org.graalvm.compiler.nodes;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
import java.util.ArrayList;
@@ -74,7 +74,7 @@
* The {@code IfNode} represents a branch that can go one of two directions depending on the outcome
* of a comparison.
*/
-@NodeInfo(cycles = CYCLES_2, size = SIZE_2, sizeRationale = "2 jmps")
+@NodeInfo(cycles = CYCLES_1, size = SIZE_2, sizeRationale = "2 jmps")
public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
@@ -375,7 +375,7 @@
}
// Falsify the reference check.
- setCondition(graph().addOrUnique(LogicConstantNode.contradiction()));
+ setCondition(graph().addOrUniqueWithInputs(LogicConstantNode.contradiction()));
return true;
}
@@ -726,10 +726,11 @@
protected void removeThroughFalseBranch(SimplifierTool tool, AbstractMergeNode merge) {
AbstractBeginNode trueBegin = trueSuccessor();
+ LogicNode conditionNode = condition();
graph().removeSplitPropagate(this, trueBegin);
tool.addToWorkList(trueBegin);
- if (condition() != null) {
- GraphUtil.tryKillUnused(condition());
+ if (conditionNode != null) {
+ GraphUtil.tryKillUnused(conditionNode);
}
if (merge.isAlive() && merge.forwardEndCount() > 1) {
for (FixedNode end : merge.forwardEnds()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PhiNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PhiNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -132,12 +132,24 @@
}
str.append(valueAt(i) == null ? "-" : valueAt(i).toString(Verbosity.Id));
}
+ String description = valueDescription();
+ if (description.length() > 0) {
+ str.append(", ").append(description);
+ }
return super.toString(Verbosity.Name) + "(" + str + ")";
} else {
return super.toString(verbosity);
}
}
+ /**
+ * String describing the kind of value this Phi merges. Used by {@link #toString(Verbosity)} and
+ * dumping.
+ */
+ protected String valueDescription() {
+ return "";
+ }
+
public void addInput(ValueNode x) {
assert !(x instanceof ValuePhiNode) || ((ValuePhiNode) x).merge() instanceof LoopBeginNode || ((ValuePhiNode) x).merge() != this.merge();
assert !(this instanceof ValuePhiNode) || x.stamp().isCompatible(stamp());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -59,14 +59,14 @@
*
* In contrast to a {@link GuardedValueNode}, a {@link PiNode} is useless as soon as the type of its
* input is as narrow or narrower than the {@link PiNode}'s type. The {@link PiNode}, and therefore
- * also the scheduling restriction enforced by the anchor, will go away.
+ * also the scheduling restriction enforced by the guard, will go away.
*/
@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
public class PiNode extends FloatingGuardedNode implements LIRLowerable, Virtualizable, IterableNodeType, Canonicalizable, ValueProxy {
public static final NodeClass<PiNode> TYPE = NodeClass.create(PiNode.class);
@Input ValueNode object;
- protected final Stamp piStamp;
+ protected Stamp piStamp;
public ValueNode object() {
return object;
@@ -84,12 +84,12 @@
this(object, stamp, null);
}
- public PiNode(ValueNode object, Stamp stamp, ValueNode anchor) {
- this(TYPE, object, stamp, (GuardingNode) anchor);
+ public PiNode(ValueNode object, Stamp stamp, ValueNode guard) {
+ this(TYPE, object, stamp, (GuardingNode) guard);
}
- public PiNode(ValueNode object, ValueNode anchor) {
- this(object, AbstractPointerStamp.pointerNonNull(object.stamp()), anchor);
+ public PiNode(ValueNode object, ValueNode guard) {
+ this(object, AbstractPointerStamp.pointerNonNull(object.stamp()), guard);
}
public PiNode(ValueNode object, ResolvedJavaType toType, boolean exactType, boolean nonNull) {
@@ -104,29 +104,29 @@
return new PiNode(object, stamp);
}
- public static ValueNode create(ValueNode object, Stamp stamp, ValueNode anchor) {
- ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+ public static ValueNode create(ValueNode object, Stamp stamp, ValueNode guard) {
+ ValueNode value = canonical(object, stamp, (GuardingNode) guard);
if (value != null) {
return value;
}
- return new PiNode(object, stamp, anchor);
+ return new PiNode(object, stamp, guard);
}
- public static ValueNode create(ValueNode object, ValueNode anchor) {
+ public static ValueNode create(ValueNode object, ValueNode guard) {
Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp());
- ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+ ValueNode value = canonical(object, stamp, (GuardingNode) guard);
if (value != null) {
return value;
}
- return new PiNode(object, stamp, anchor);
+ return new PiNode(object, stamp, guard);
}
@SuppressWarnings("unused")
- public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ValueNode anchor) {
+ public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode object, ValueNode guard) {
Stamp stamp = AbstractPointerStamp.pointerNonNull(object.stamp());
- ValueNode value = canonical(object, stamp, (GuardingNode) anchor);
+ ValueNode value = canonical(object, stamp, (GuardingNode) guard);
if (value == null) {
- value = new PiNode(object, stamp, anchor);
+ value = new PiNode(object, stamp, guard);
}
b.push(JavaKind.Object, b.append(value));
return true;
@@ -147,6 +147,11 @@
return piStamp;
}
+ public void strengthenPiStamp(Stamp newPiStamp) {
+ assert this.piStamp.join(newPiStamp).equals(newPiStamp) : "stamp can only improve";
+ this.piStamp = newPiStamp;
+ }
+
@Override
public void generate(NodeLIRBuilderTool generator) {
if (generator.hasOperand(object)) {
@@ -256,17 +261,17 @@
/**
* Changes the stamp of an object and ensures the newly stamped value is non-null and does not
- * float above a given anchor.
+ * float above a given guard.
*/
@NodeIntrinsic
- public static native Object piCastNonNull(Object object, GuardingNode anchor);
+ public static native Object piCastNonNull(Object object, GuardingNode guard);
/**
* Changes the stamp of an object and ensures the newly stamped value is non-null and does not
- * float above a given anchor.
+ * float above a given guard.
*/
@NodeIntrinsic
- public static native Class<?> piCastNonNullClass(Class<?> type, GuardingNode anchor);
+ public static native Class<?> piCastNonNullClass(Class<?> type, GuardingNode guard);
/**
* Changes the stamp of an object to represent a given type and to indicate that the object is
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.nodes;
+import java.util.Map;
+
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
@@ -35,7 +37,7 @@
/**
* Value {@link PhiNode}s merge data flow values at control flow merges.
*/
-@NodeInfo(nameTemplate = "Phi({i#values})")
+@NodeInfo(nameTemplate = "Phi({i#values}, {p#valueDescription})")
public class ValuePhiNode extends PhiNode implements ArrayLengthProvider {
public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
@@ -113,4 +115,16 @@
}
return super.verify();
}
+
+ @Override
+ protected String valueDescription() {
+ return stamp().unrestricted().toString();
+ }
+
+ @Override
+ public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
+ Map<Object, Object> properties = super.getDebugProperties(map);
+ properties.put("valueDescription", valueDescription());
+ return properties;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -91,7 +91,9 @@
public static <OP> ConstantNode tryConstantFold(BinaryOp<OP> op, ValueNode forX, ValueNode forY, Stamp stamp) {
if (forX.isConstant() && forY.isConstant()) {
Constant ret = op.foldConstant(forX.asConstant(), forY.asConstant());
- return ConstantNode.forPrimitive(stamp, ret);
+ if (ret != null) {
+ return ConstantNode.forPrimitive(stamp, ret);
+ }
}
return null;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,7 +22,7 @@
*/
package org.graalvm.compiler.nodes.calc;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode;
@@ -47,10 +47,10 @@
import jdk.vm.ci.meta.JavaConstant;
/**
- * The {@code ConditionalNode} class represents a comparison that yields one of two values. Note
- * that these nodes are not built directly from the bytecode but are introduced by canonicalization.
+ * The {@code ConditionalNode} class represents a comparison that yields one of two (eagerly
+ * evaluated) values.
*/
-@NodeInfo(cycles = CYCLES_0, size = SIZE_2)
+@NodeInfo(cycles = CYCLES_1, size = SIZE_2)
public final class ConditionalNode extends FloatingNode implements Canonicalizable, LIRLowerable {
public static final NodeClass<ConditionalNode> TYPE = NodeClass.create(ConditionalNode.class);
@@ -116,7 +116,6 @@
valueStamp = valueStamp.join(bounds);
}
}
-
}
return updateStamp(valueStamp);
}
@@ -145,49 +144,10 @@
}
public static ValueNode canonicalizeConditional(LogicNode condition, ValueNode trueValue, ValueNode falseValue, Stamp stamp) {
- // this optimizes the case where a value from the range 0 - 1 is mapped to the range 0 - 1
- if (trueValue.isConstant() && falseValue.isConstant() && trueValue.stamp() instanceof IntegerStamp && falseValue.stamp() instanceof IntegerStamp) {
- long constTrueValue = trueValue.asJavaConstant().asLong();
- long constFalseValue = falseValue.asJavaConstant().asLong();
- if (condition instanceof IntegerEqualsNode) {
- IntegerEqualsNode equals = (IntegerEqualsNode) condition;
- if (equals.getY().isConstant() && equals.getX().stamp() instanceof IntegerStamp) {
- IntegerStamp equalsXStamp = (IntegerStamp) equals.getX().stamp();
- if (equalsXStamp.upMask() == 1) {
- long equalsY = equals.getY().asJavaConstant().asLong();
- if (equalsY == 0) {
- if (constTrueValue == 0 && constFalseValue == 1) {
- // return x when: x == 0 ? 0 : 1;
- return IntegerConvertNode.convertUnsigned(equals.getX(), stamp);
- } else if (constTrueValue == 1 && constFalseValue == 0) {
- // negate a boolean value via xor
- return IntegerConvertNode.convertUnsigned(XorNode.create(equals.getX(), ConstantNode.forIntegerStamp(equals.getX().stamp(), 1)), stamp);
- }
- } else if (equalsY == 1) {
- if (constTrueValue == 1 && constFalseValue == 0) {
- // return x when: x == 1 ? 1 : 0;
- return IntegerConvertNode.convertUnsigned(equals.getX(), stamp);
- } else if (constTrueValue == 0 && constFalseValue == 1) {
- // negate a boolean value via xor
- return IntegerConvertNode.convertUnsigned(XorNode.create(equals.getX(), ConstantNode.forIntegerStamp(equals.getX().stamp(), 1)), stamp);
- }
- }
- }
- }
- } else if (condition instanceof IntegerTestNode) {
- // replace IntegerTestNode with AndNode for the following patterns:
- // (value & 1) == 0 ? 0 : 1
- // (value & 1) == 1 ? 1 : 0
- IntegerTestNode integerTestNode = (IntegerTestNode) condition;
- if (integerTestNode.getY().isConstant()) {
- assert integerTestNode.getX().stamp() instanceof IntegerStamp;
- long testY = integerTestNode.getY().asJavaConstant().asLong();
- if (testY == 1 && constTrueValue == 0 && constFalseValue == 1) {
- return IntegerConvertNode.convertUnsigned(AndNode.create(integerTestNode.getX(), integerTestNode.getY()), stamp);
- }
- }
- }
+ if (trueValue == falseValue) {
+ return trueValue;
}
+
if (condition instanceof CompareNode && ((CompareNode) condition).isIdentityComparison()) {
// optimize the pattern (x == y) ? x : y
CompareNode compare = (CompareNode) condition;
@@ -195,25 +155,87 @@
return falseValue;
}
}
- if (trueValue == falseValue) {
- return trueValue;
- }
+
+ if (trueValue.stamp() instanceof IntegerStamp) {
+ // check if the conditional is redundant
+ if (condition instanceof IntegerLessThanNode) {
+ IntegerLessThanNode lessThan = (IntegerLessThanNode) condition;
+ IntegerStamp falseValueStamp = (IntegerStamp) falseValue.stamp();
+ IntegerStamp trueValueStamp = (IntegerStamp) trueValue.stamp();
+ if (lessThan.getX() == trueValue && lessThan.getY() == falseValue) {
+ // return "x" for "x < y ? x : y" in case that we know "x <= y"
+ if (trueValueStamp.upperBound() <= falseValueStamp.lowerBound()) {
+ return trueValue;
+ }
+ } else if (lessThan.getX() == falseValue && lessThan.getY() == trueValue) {
+ // return "x" for "x < y ? y : x" in case that we know "x <= y"
+ if (falseValueStamp.upperBound() <= trueValueStamp.lowerBound()) {
+ return falseValue;
+ }
+ }
+ }
- if (condition instanceof IntegerLessThanNode && trueValue.stamp() instanceof IntegerStamp) {
- /*
- * Convert a conditional add ((x < 0) ? (x + y) : x) into (x + (y & (x >> (bits - 1))))
- * to avoid the test.
- */
- IntegerLessThanNode lt = (IntegerLessThanNode) condition;
- if (lt.getY().isConstant() && lt.getY().asConstant().isDefaultForKind()) {
- if (falseValue == lt.getX()) {
- if (trueValue instanceof AddNode) {
- AddNode add = (AddNode) trueValue;
- if (add.getX() == falseValue) {
- int bits = ((IntegerStamp) trueValue.stamp()).getBits();
- ValueNode shift = new RightShiftNode(lt.getX(), ConstantNode.forIntegerBits(32, bits - 1));
- ValueNode and = new AndNode(shift, add.getY());
- return new AddNode(add.getX(), and);
+ // this optimizes the case where a value from the range 0 - 1 is mapped to the
+ // range 0 - 1
+ if (trueValue.isConstant() && falseValue.isConstant()) {
+ long constTrueValue = trueValue.asJavaConstant().asLong();
+ long constFalseValue = falseValue.asJavaConstant().asLong();
+ if (condition instanceof IntegerEqualsNode) {
+ IntegerEqualsNode equals = (IntegerEqualsNode) condition;
+ if (equals.getY().isConstant() && equals.getX().stamp() instanceof IntegerStamp) {
+ IntegerStamp equalsXStamp = (IntegerStamp) equals.getX().stamp();
+ if (equalsXStamp.upMask() == 1) {
+ long equalsY = equals.getY().asJavaConstant().asLong();
+ if (equalsY == 0) {
+ if (constTrueValue == 0 && constFalseValue == 1) {
+ // return x when: x == 0 ? 0 : 1;
+ return IntegerConvertNode.convertUnsigned(equals.getX(), stamp);
+ } else if (constTrueValue == 1 && constFalseValue == 0) {
+ // negate a boolean value via xor
+ return IntegerConvertNode.convertUnsigned(XorNode.create(equals.getX(), ConstantNode.forIntegerStamp(equals.getX().stamp(), 1)), stamp);
+ }
+ } else if (equalsY == 1) {
+ if (constTrueValue == 1 && constFalseValue == 0) {
+ // return x when: x == 1 ? 1 : 0;
+ return IntegerConvertNode.convertUnsigned(equals.getX(), stamp);
+ } else if (constTrueValue == 0 && constFalseValue == 1) {
+ // negate a boolean value via xor
+ return IntegerConvertNode.convertUnsigned(XorNode.create(equals.getX(), ConstantNode.forIntegerStamp(equals.getX().stamp(), 1)), stamp);
+ }
+ }
+ }
+ }
+ } else if (condition instanceof IntegerTestNode) {
+ // replace IntegerTestNode with AndNode for the following patterns:
+ // (value & 1) == 0 ? 0 : 1
+ // (value & 1) == 1 ? 1 : 0
+ IntegerTestNode integerTestNode = (IntegerTestNode) condition;
+ if (integerTestNode.getY().isConstant()) {
+ assert integerTestNode.getX().stamp() instanceof IntegerStamp;
+ long testY = integerTestNode.getY().asJavaConstant().asLong();
+ if (testY == 1 && constTrueValue == 0 && constFalseValue == 1) {
+ return IntegerConvertNode.convertUnsigned(AndNode.create(integerTestNode.getX(), integerTestNode.getY()), stamp);
+ }
+ }
+ }
+ }
+
+ if (condition instanceof IntegerLessThanNode) {
+ /*
+ * Convert a conditional add ((x < 0) ? (x + y) : x) into (x + (y & (x >> (bits -
+ * 1)))) to avoid the test.
+ */
+ IntegerLessThanNode lt = (IntegerLessThanNode) condition;
+ if (lt.getY().isConstant() && lt.getY().asConstant().isDefaultForKind()) {
+ if (falseValue == lt.getX()) {
+ if (trueValue instanceof AddNode) {
+ AddNode add = (AddNode) trueValue;
+ if (add.getX() == falseValue) {
+ int bits = ((IntegerStamp) trueValue.stamp()).getBits();
+ ValueNode shift = new RightShiftNode(lt.getX(), ConstantNode.forIntegerBits(32, bits - 1));
+ ValueNode and = new AndNode(shift, add.getY());
+ return new AddNode(add.getX(), and);
+ }
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/DivNode.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.nodes.calc;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
-
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
-import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
-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;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-
-import jdk.vm.ci.code.CodeUtil;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.PrimitiveConstant;
-
-@NodeInfo(shortName = "/", cycles = CYCLES_32)
-public class DivNode extends BinaryArithmeticNode<Div> {
-
- public static final NodeClass<DivNode> TYPE = NodeClass.create(DivNode.class);
-
- public DivNode(ValueNode x, ValueNode y) {
- super(TYPE, ArithmeticOpTable::getDiv, x, y);
- }
-
- protected DivNode(NodeClass<? extends DivNode> c, ValueNode x, ValueNode y) {
- super(c, ArithmeticOpTable::getDiv, x, y);
- }
-
- public static ValueNode create(ValueNode x, ValueNode y) {
- BinaryOp<Div> op = ArithmeticOpTable.forStamp(x.stamp()).getDiv();
- Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
- ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
- if (tryConstantFold != null) {
- return tryConstantFold;
- }
- 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;
- }
-
- return canonical(this, getOp(forX, forY), forX, forY);
- }
-
- private static ValueNode canonical(DivNode self, BinaryOp<Div> op, ValueNode forX, ValueNode forY) {
- if (forY.isConstant()) {
- Constant c = forY.asConstant();
- if (op.isNeutral(c)) {
- return forX;
- }
- if (c instanceof PrimitiveConstant && ((PrimitiveConstant) c).getJavaKind().isNumericInteger()) {
- long i = ((PrimitiveConstant) c).asLong();
- boolean signFlip = false;
- if (i < 0) {
- i = -i;
- signFlip = true;
- }
- ValueNode divResult = null;
- if (CodeUtil.isPowerOf2(i)) {
- divResult = new RightShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(i)));
- }
- if (divResult != null) {
- if (signFlip) {
- return NegateNode.create(divResult);
- } else {
- return divResult;
- }
- }
- }
- }
- return self != null ? self : new DivNode(forX, forY);
- }
-
- @Override
- public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
- nodeValueMap.setResult(this, gen.emitDiv(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatDivNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.calc;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_32;
+
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Div;
+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;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import jdk.vm.ci.meta.Constant;
+
+@NodeInfo(shortName = "/", cycles = CYCLES_32)
+public class FloatDivNode extends BinaryArithmeticNode<Div> {
+
+ public static final NodeClass<FloatDivNode> TYPE = NodeClass.create(FloatDivNode.class);
+
+ public FloatDivNode(ValueNode x, ValueNode y) {
+ this(TYPE, x, y);
+ }
+
+ protected FloatDivNode(NodeClass<? extends FloatDivNode> c, ValueNode x, ValueNode y) {
+ super(c, ArithmeticOpTable::getDiv, x, y);
+ assert stamp instanceof FloatStamp;
+ }
+
+ public static ValueNode create(ValueNode x, ValueNode y) {
+ BinaryOp<Div> op = ArithmeticOpTable.forStamp(x.stamp()).getDiv();
+ Stamp stamp = op.foldStamp(x.stamp(), y.stamp());
+ ConstantNode tryConstantFold = tryConstantFold(op, x, y, stamp);
+ if (tryConstantFold != null) {
+ return tryConstantFold;
+ }
+ 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;
+ }
+
+ return canonical(this, getOp(forX, forY), forX, forY);
+ }
+
+ private static ValueNode canonical(FloatDivNode self, BinaryOp<Div> op, ValueNode forX, ValueNode forY) {
+ if (forY.isConstant()) {
+ Constant c = forY.asConstant();
+ if (op.isNeutral(c)) {
+ return forX;
+ }
+ }
+ return self != null ? self : new FloatDivNode(forX, forY);
+ }
+
+ @Override
+ public void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) {
+ nodeValueMap.setResult(this, gen.emitDiv(nodeValueMap.operand(getX()), nodeValueMap.operand(getY()), null));
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerConvertNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -129,7 +129,7 @@
ValueNode convert = convert(input, stamp, false);
if (!convert.isAlive()) {
assert !convert.isDeleted();
- convert = graph.addOrUnique(convert);
+ convert = graph.addOrUniqueWithInputs(convert);
}
return convert;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -52,7 +52,7 @@
@NodeInfo(shortName = "<")
public final class IntegerLessThanNode extends IntegerLowerThanNode {
public static final NodeClass<IntegerLessThanNode> TYPE = NodeClass.create(IntegerLessThanNode.class);
- public static final LessThanOp OP = new LessThanOp();
+ private static final LessThanOp OP = new LessThanOp();
public IntegerLessThanNode(ValueNode x, ValueNode y) {
super(TYPE, x, y, OP);
@@ -203,49 +203,52 @@
}
}
- 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();
+ if (forX.stamp() instanceof IntegerStamp) {
+ assert forY.stamp() instanceof IntegerStamp;
+ 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();
}
- } 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();
+ 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();
}
- } 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 || 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);
}
- 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);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IsNullNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -121,7 +121,8 @@
@Override
public Stamp getSucceedingStampForValue(boolean negated) {
- AbstractPointerStamp pointerStamp = (AbstractPointerStamp) getValue().stamp();
+ // Ignore any more precise input stamp since canonicalization will skip through PiNodes
+ AbstractPointerStamp pointerStamp = (AbstractPointerStamp) getValue().stamp().unrestricted();
return negated ? pointerStamp.asNonNull() : pointerStamp.asAlwaysNull();
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -63,29 +63,9 @@
return ConstantNode.forIntegerStamp(stamp(), forX.asJavaConstant().asLong() / y);
} else if (forY.isConstant()) {
long c = forY.asJavaConstant().asLong();
- if (c == 1) {
- return forX;
- }
- if (c == -1) {
- return NegateNode.create(forX);
- }
- long abs = Math.abs(c);
- if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) {
- ValueNode dividend = forX;
- IntegerStamp stampX = (IntegerStamp) forX.stamp();
- int log2 = CodeUtil.log2(abs);
- // no rounding if dividend is positive or if its low bits are always 0
- if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) {
- int bits = PrimitiveStamp.getBits(stamp());
- RightShiftNode sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1));
- UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2));
- dividend = BinaryArithmeticNode.add(dividend, round);
- }
- RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2));
- if (c < 0) {
- return NegateNode.create(shift);
- }
- return shift;
+ ValueNode v = canonical(forX, c);
+ if (v != null) {
+ return v;
}
}
@@ -113,6 +93,34 @@
return this;
}
+ public static ValueNode canonical(ValueNode forX, long c) {
+ if (c == 1) {
+ return forX;
+ }
+ if (c == -1) {
+ return NegateNode.create(forX);
+ }
+ long abs = Math.abs(c);
+ if (CodeUtil.isPowerOf2(abs) && forX.stamp() instanceof IntegerStamp) {
+ ValueNode dividend = forX;
+ IntegerStamp stampX = (IntegerStamp) forX.stamp();
+ int log2 = CodeUtil.log2(abs);
+ // no rounding if dividend is positive or if its low bits are always 0
+ if (stampX.canBeNegative() || (stampX.upMask() & (abs - 1)) != 0) {
+ int bits = PrimitiveStamp.getBits(forX.stamp());
+ RightShiftNode sign = new RightShiftNode(forX, ConstantNode.forInt(bits - 1));
+ UnsignedRightShiftNode round = new UnsignedRightShiftNode(sign, ConstantNode.forInt(bits - log2));
+ dividend = BinaryArithmeticNode.add(dividend, round);
+ }
+ RightShiftNode shift = new RightShiftNode(dividend, ConstantNode.forInt(log2));
+ if (c < 0) {
+ return NegateNode.create(shift);
+ }
+ return shift;
+ }
+ return null;
+ }
+
@Override
public void generate(NodeLIRBuilderTool gen) {
gen.setResult(this, gen.getLIRGeneratorTool().getArithmetic().emitDiv(gen.operand(getX()), gen.operand(getY()), gen.state(this)));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -72,13 +72,14 @@
return ConstantNode.forIntegerStamp(stamp(), 0);
} else if (CodeUtil.isPowerOf2(constY)) {
if (xStamp.isPositive()) {
+ // x & (y - 1)
return new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1));
} else if (xStamp.isNegative()) {
+ // -((-x) & (y - 1))
return new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1)));
} else {
- return new ConditionalNode(IntegerLessThanNode.create(forX, ConstantNode.forIntegerStamp(forX.stamp(), 0)),
- new NegateNode(new AndNode(new NegateNode(forX), ConstantNode.forIntegerStamp(stamp(), constY - 1))),
- new AndNode(forX, ConstantNode.forIntegerStamp(stamp(), constY - 1)));
+ // x - ((x / y) << log2(y))
+ return SubNode.create(forX, LeftShiftNode.create(SignedDivNode.canonical(forX, constY), ConstantNode.forInt(CodeUtil.log2(constY))));
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnaryNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -45,6 +45,11 @@
return value;
}
+ public void setValue(ValueNode value) {
+ updateUsages(this.value, value);
+ this.value = value;
+ }
+
/**
* Creates a new UnaryNode instance.
*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnpackEndianHalfNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,90 @@
+/*
+ * 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.nodes.calc;
+
+import java.nio.ByteOrder;
+
+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;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+
+import jdk.vm.ci.meta.JavaKind;
+
+/**
+ * Produces the platform dependent first or second half of a long or double value as an int.
+ */
+@NodeInfo(cycles = NodeCycles.CYCLES_2)
+public final class UnpackEndianHalfNode extends UnaryNode implements Lowerable {
+ public static final NodeClass<UnpackEndianHalfNode> TYPE = NodeClass.create(UnpackEndianHalfNode.class);
+
+ private final boolean firstHalf;
+
+ protected UnpackEndianHalfNode(ValueNode value, boolean firstHalf) {
+ super(TYPE, StampFactory.forKind(JavaKind.Int), value);
+ assert value.getStackKind() == JavaKind.Double || value.getStackKind() == JavaKind.Long : "unexpected kind " + value.getStackKind();
+ this.firstHalf = firstHalf;
+ }
+
+ public static ValueNode create(ValueNode value, boolean firstHalf) {
+ if (value.isConstant() && value.asConstant().isDefaultForKind()) {
+ return ConstantNode.defaultForKind(JavaKind.Int);
+ }
+ return new UnpackEndianHalfNode(value, firstHalf);
+ }
+
+ public boolean isFirstHalf() {
+ return firstHalf;
+ }
+
+ @Override
+ public Node canonical(CanonicalizerTool tool, ValueNode forValue) {
+ if (forValue.isConstant() && forValue.asConstant().isDefaultForKind()) {
+ return ConstantNode.defaultForKind(stamp.getStackKind());
+ }
+ return this;
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ tool.getLowerer().lower(this, tool);
+ }
+
+ public void lower(ByteOrder byteOrder) {
+ ValueNode result = value;
+ if (value.getStackKind() == JavaKind.Double) {
+ result = graph().unique(new ReinterpretNode(JavaKind.Long, value));
+ }
+ if ((byteOrder == ByteOrder.BIG_ENDIAN) == firstHalf) {
+ result = graph().unique(new UnsignedRightShiftNode(result, ConstantNode.forInt(32, graph())));
+ }
+ result = IntegerConvertNode.convert(result, StampFactory.forKind(JavaKind.Int), graph());
+ replaceAtUsagesAndDelete(result);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java Mon Nov 06 20:29:49 2017 -0800
@@ -592,7 +592,11 @@
for (Block block : reversePostOrder) {
AbstractBeginNode beginNode = block.getBeginNode();
if (beginNode instanceof LoopBeginNode) {
- Loop<Block> loop = new HIRLoop(block.getLoop(), loops.size(), block);
+ Loop<Block> parent = block.getLoop();
+ Loop<Block> loop = new HIRLoop(parent, loops.size(), block);
+ if (parent != null) {
+ parent.getChildren().add(loop);
+ }
loops.add(loop);
block.setLoop(loop);
loop.getBlocks().add(block);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -82,6 +82,9 @@
@Override
public void simplify(SimplifierTool tool) {
+ if (!hasUsages()) {
+ return;
+ }
if (probability.isConstant()) {
double probabilityValue = probability.asJavaConstant().asDouble();
if (probabilityValue < 0.0) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -79,7 +79,7 @@
super(TYPE, stamp, object, offset, accessKind, locationIdentity, false);
}
- public RawLoadNode(NodeClass<? extends RawLoadNode> c, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
+ protected RawLoadNode(NodeClass<? extends RawLoadNode> c, ValueNode object, ValueNode offset, JavaKind accessKind, LocationIdentity locationIdentity) {
super(c, StampFactory.forKind(accessKind.getStackKind()), object, offset, accessKind, locationIdentity, false);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -29,7 +29,6 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.ValueNode;
@@ -39,12 +38,10 @@
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
-import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
import org.graalvm.word.LocationIdentity;
import jdk.vm.ci.meta.Assumptions;
-import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaField;
@@ -123,41 +120,8 @@
if (indexValue.isConstant()) {
long off = indexValue.asJavaConstant().asLong();
int entryIndex = virtual.entryIndexForOffset(off, accessKind());
- if (entryIndex != -1) {
- JavaKind entryKind = virtual.entryKind(entryIndex);
- boolean canVirtualize = entryKind == accessKind() || (entryKind == accessKind().getStackKind() && !StampTool.typeOrNull(object()).isArray());
- if (!canVirtualize) {
- /*
- * Special case: If the entryKind is long, allow arbitrary kinds as long as
- * a value of the same kind is already there. This can only happen if some
- * other node initialized the entry with a value of a different kind. One
- * example where this happens is the Truffle NewFrameNode.
- */
- ValueNode entry = tool.getEntry(virtual, entryIndex);
- if (entryKind == JavaKind.Long && entry.getStackKind() == value.getStackKind()) {
- canVirtualize = true;
- }
- }
- if (canVirtualize) {
- tool.setVirtualEntry(virtual, entryIndex, value(), true);
- tool.delete();
- } else {
- /*
- * Special case: Allow storing a single long or double value into two
- * consecutive int slots.
- */
- if ((accessKind() == JavaKind.Long || accessKind() == JavaKind.Double) && entryKind == JavaKind.Int) {
- int nextIndex = virtual.entryIndexForOffset(off + 4, entryKind);
- if (nextIndex != -1) {
- JavaKind nextKind = virtual.entryKind(nextIndex);
- if (nextKind == JavaKind.Int) {
- tool.setVirtualEntry(virtual, entryIndex, value(), true);
- tool.setVirtualEntry(virtual, nextIndex, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()), true);
- tool.delete();
- }
- }
- }
- }
+ if (entryIndex != -1 && tool.setVirtualEntry(virtual, entryIndex, value(), accessKind(), off)) {
+ tool.delete();
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderContext.java Mon Nov 06 20:29:49 2017 -0800
@@ -280,7 +280,7 @@
ObjectStamp receiverStamp = (ObjectStamp) value.stamp();
Stamp stamp = receiverStamp.join(objectNonNull());
FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, NullCheckException, action, true));
- ValueNode nonNullReceiver = getGraph().addOrUnique(PiNode.create(value, stamp, fixedGuard));
+ ValueNode nonNullReceiver = getGraph().addOrUniqueWithInputs(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.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java Mon Nov 06 20:29:49 2017 -0800
@@ -53,6 +53,12 @@
*/
public static final InlineInfo DO_NOT_INLINE_NO_EXCEPTION = new InlineInfo(null, null);
+ /**
+ * Denotes a call site must not be inlined and the execution should be transferred to
+ * interpreter in case of an exception.
+ */
+ public static final InlineInfo DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION = new InlineInfo(null, null);
+
private final ResolvedJavaMethod methodToInline;
private final BytecodeProvider intrinsicBytecodeProvider;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java Mon Nov 06 20:29:49 2017 -0800
@@ -66,6 +66,34 @@
*/
final BytecodeProvider bytecodeProvider;
+ final CompilationContext compilationContext;
+
+ final boolean allowPartialIntrinsicArgumentMismatch;
+
+ public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
+ this(method, intrinsic, bytecodeProvider, compilationContext, false);
+ }
+
+ public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext,
+ boolean allowPartialIntrinsicArgumentMismatch) {
+ this.method = method;
+ this.intrinsic = intrinsic;
+ this.bytecodeProvider = bytecodeProvider;
+ assert bytecodeProvider != null;
+ this.compilationContext = compilationContext;
+ this.allowPartialIntrinsicArgumentMismatch = allowPartialIntrinsicArgumentMismatch;
+ assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
+ }
+
+ /**
+ * A partial intrinsic exits by (effectively) calling the intrinsified method. Normally, this
+ * call must use exactly the same arguments as the call that is being intrinsified. This allows
+ * to override this behavior.
+ */
+ public boolean allowPartialIntrinsicArgumentMismatch() {
+ return allowPartialIntrinsicArgumentMismatch;
+ }
+
/**
* Gets the method being intrinsified.
*/
@@ -96,17 +124,6 @@
return method.equals(targetMethod) || intrinsic.equals(targetMethod);
}
- final CompilationContext compilationContext;
-
- public IntrinsicContext(ResolvedJavaMethod method, ResolvedJavaMethod intrinsic, BytecodeProvider bytecodeProvider, CompilationContext compilationContext) {
- this.method = method;
- this.intrinsic = intrinsic;
- this.bytecodeProvider = bytecodeProvider;
- assert bytecodeProvider != null;
- this.compilationContext = compilationContext;
- assert !isCompilationRoot() || method.hasBytecodes() : "Cannot root compile intrinsic for native or abstract method " + method.format("%H.%n(%p)");
- }
-
public boolean isPostParseInlined() {
return compilationContext.equals(INLINE_AFTER_PARSING);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -49,6 +49,8 @@
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.TriState;
+import java.util.Objects;
+
/**
* The {@code InstanceOfNode} represents an instanceof test.
*/
@@ -56,7 +58,7 @@
public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable {
public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class);
- protected final ObjectStamp checkedStamp;
+ private ObjectStamp checkedStamp;
private JavaTypeProfile profile;
@OptionalInput(Anchor) protected AnchoringNode anchor;
@@ -126,7 +128,9 @@
// The check will always succeed, the union of the two stamps is equal to the
// checked stamp.
return LogicConstantNode.tautology();
- } else if (checkedStamp.type().equals(meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) {
+ } else if (checkedStamp.alwaysNull()) {
+ return IsNullNode.create(object);
+ } else if (Objects.equals(checkedStamp.type(), meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) {
assert checkedStamp.nonNull() != inputStamp.nonNull();
// The only difference makes the null-ness of the value => simplify the check.
if (checkedStamp.nonNull()) {
@@ -135,8 +139,8 @@
return IsNullNode.create(object);
}
}
+ assert checkedStamp.type() != null;
}
-
return null;
}
@@ -204,4 +208,13 @@
public AnchoringNode getAnchor() {
return anchor;
}
+
+ public ObjectStamp getCheckedStamp() {
+ return checkedStamp;
+ }
+
+ public void strengthenCheckedStamp(ObjectStamp newCheckedStamp) {
+ assert this.checkedStamp.join(newCheckedStamp).equals(newCheckedStamp) : "stamp can only improve";
+ this.checkedStamp = newCheckedStamp;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadFieldNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -25,7 +25,6 @@
import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
-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;
@@ -47,15 +46,16 @@
import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.meta.Assumptions;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
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.
@@ -150,7 +150,7 @@
}
public ConstantNode asConstant(CanonicalizerTool tool, JavaConstant constant) {
- return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, getOptions());
+ return ConstantFoldUtil.tryConstantFold(tool.getConstantFieldProvider(), tool.getConstantReflection(), tool.getMetaAccess(), field(), constant, tool.getOptions());
}
private static PhiNode asPhi(ConstantFieldProvider constantFields, ConstantReflectionProvider constantReflection,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreFieldNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -29,7 +29,6 @@
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.ValueNode;
@@ -38,7 +37,6 @@
import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
-import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaField;
/**
@@ -90,15 +88,8 @@
VirtualInstanceNode virtual = (VirtualInstanceNode) alias;
int fieldIndex = virtual.fieldIndex(field());
if (fieldIndex != -1) {
- ValueNode existing = tool.getEntry((VirtualObjectNode) alias, fieldIndex);
- if (existing.stamp().isCompatible(value().stamp())) {
- tool.setVirtualEntry(virtual, fieldIndex, value(), false);
- tool.delete();
- } else {
- // stamp of the value is not compatible with the value in the virtualizer
- // can only happen with unsafe two slot writes on one slot fields
- assert existing instanceof ConstantNode && ((ConstantNode) existing).asConstant().equals(JavaConstant.forIllegal()) : value.stamp() + " vs " + existing.stamp();
- }
+ tool.setVirtualEntry(virtual, fieldIndex, value());
+ tool.delete();
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -89,7 +89,7 @@
ResolvedJavaType componentType = virtual.type().getComponentType();
if (componentType.isPrimitive() || StampTool.isPointerAlwaysNull(value) || componentType.getSuperclass() == null ||
(StampTool.typeReferenceOrNull(value) != null && componentType.isAssignableFrom(StampTool.typeOrNull(value)))) {
- tool.setVirtualEntry(virtual, idx, value(), false);
+ tool.setVirtualEntry(virtual, idx, value());
tool.delete();
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryPhiNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -62,4 +62,9 @@
public NodeInputList<ValueNode> values() {
return values;
}
+
+ @Override
+ protected String valueDescription() {
+ return locationIdentity.toString();
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/OffsetAddressNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/address/OffsetAddressNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.nodes.memory.address;
+import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.Node;
@@ -52,6 +53,9 @@
super(TYPE);
this.base = base;
this.offset = offset;
+
+ assert base != null && (base.stamp() instanceof AbstractPointerStamp || IntegerStamp.getBits(base.stamp()) == 64) &&
+ offset != null && IntegerStamp.getBits(offset.stamp()) == 64 : "both values must have 64 bits";
}
@Override
@@ -62,6 +66,7 @@
public void setBase(ValueNode base) {
updateUsages(this.base, base);
this.base = base;
+ assert base != null && (base.stamp() instanceof AbstractPointerStamp || IntegerStamp.getBits(base.stamp()) == 64);
}
public ValueNode getOffset() {
@@ -71,6 +76,7 @@
public void setOffset(ValueNode offset) {
updateUsages(this.offset, offset);
this.offset = offset;
+ assert offset != null && IntegerStamp.getBits(offset.stamp()) == 64;
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java Mon Nov 06 20:29:49 2017 -0800
@@ -25,6 +25,7 @@
import java.util.List;
import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
@@ -91,9 +92,17 @@
*
* @param index the index to be set.
* @param value the new value for the given index.
- * @param unsafe if true, then mismatching value {@link JavaKind}s will be accepted.
+ * @param accessKind the kind of the store which might be different than
+ * {@link VirtualObjectNode#entryKind(int)}.
+ * @return true if the operation was permitted
*/
- void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, boolean unsafe);
+ boolean setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value, JavaKind accessKind, long offset);
+
+ default void setVirtualEntry(VirtualObjectNode virtualObject, int index, ValueNode value) {
+ if (!setVirtualEntry(virtualObject, index, value, null, 0)) {
+ throw new GraalError("unexpected failure when updating virtual entry");
+ }
+ }
ValueNode getEntry(VirtualObjectNode virtualObject, int index);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Mon Nov 06 20:29:49 2017 -0800
@@ -242,7 +242,7 @@
EconomicSet<Node> collectedUnusedNodes = unusedNodes = EconomicSet.create(Equivalence.IDENTITY);
nodeEventScope = node.graph().trackNodeEvents(new Graph.NodeEventListener() {
@Override
- public void event(Graph.NodeEvent e, Node n) {
+ public void changed(Graph.NodeEvent e, Node n) {
if (e == Graph.NodeEvent.ZERO_USAGES && isFloatingNode(n) && !(n instanceof GuardNode)) {
collectedUnusedNodes.add(n);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/JavaConstantFormattable.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,31 @@
+/*
+ * 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.nodes.util;
+
+/**
+ * Performs special formatting of values involving {@link jdk.vm.ci.meta.JavaConstant JavaConstants}
+ * when they are being dumped.
+ */
+public interface JavaConstantFormattable {
+ String format(JavaConstantFormatter formatter);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/JavaConstantFormatter.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,29 @@
+/*
+ * 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.nodes.util;
+
+import jdk.vm.ci.meta.JavaConstant;
+
+public interface JavaConstantFormatter {
+ String format(JavaConstant constant);
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,7 +37,7 @@
import jdk.vm.ci.meta.ResolvedJavaType;
import sun.misc.Unsafe;
-@NodeInfo(nameTemplate = "VirtualArray {p#componentType/s}[{p#length}]")
+@NodeInfo(nameTemplate = "VirtualArray({p#objectId}) {p#componentType/s}[{p#length}]")
public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
public static final NodeClass<VirtualArrayNode> TYPE = NodeClass.create(VirtualArrayNode.class);
@@ -76,7 +76,7 @@
@Override
public String toString(Verbosity verbosity) {
if (verbosity == Verbosity.Name) {
- return super.toString(Verbosity.Name) + " " + componentType.getName() + "[" + length + "]";
+ return super.toString(Verbosity.Name) + "(" + getObjectId() + ") " + componentType.getName() + "[" + length + "]";
} else {
return super.toString(verbosity);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -32,7 +32,7 @@
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaType;
-@NodeInfo(nameTemplate = "VirtualInstance {p#type/s}")
+@NodeInfo(nameTemplate = "VirtualInstance({p#objectId}) {p#type/s}")
public class VirtualInstanceNode extends VirtualObjectNode {
public static final NodeClass<VirtualInstanceNode> TYPE = NodeClass.create(VirtualInstanceNode.class);
@@ -78,7 +78,7 @@
@Override
public String toString(Verbosity verbosity) {
if (verbosity == Verbosity.Name) {
- return super.toString(Verbosity.Name) + " " + type.toJavaName(false);
+ return super.toString(Verbosity.Name) + "(" + getObjectId() + ") " + type.toJavaName(false);
} else {
return super.toString(verbosity);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Mon Nov 06 20:29:49 2017 -0800
@@ -394,6 +394,9 @@
options = new OptionsInfo(topDeclaringType);
map.put(topDeclaringType, options);
}
+ if (!element.getEnclosingElement().getSimpleName().toString().endsWith("Options")) {
+ processingEnv.getMessager().printMessage(Kind.ERROR, "Option declaring classes must have a name that ends with 'Options'", element.getEnclosingElement());
+ }
processElement(element, options);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -248,7 +248,7 @@
/**
* Tests which may be eliminated because post dominating tests to prove a broader condition.
*/
- private Deque<PendingTest> pendingTests;
+ private Deque<DeoptimizingGuard> pendingTests;
public Instance(StructuredGraph graph, BlockMap<List<Node>> blockToNodes, PhaseContext context) {
this.graph = graph;
@@ -555,7 +555,8 @@
}
}
if (guard instanceof DeoptimizingGuard) {
- pendingTests.push(new PendingTest(condition, (DeoptimizingGuard) guard));
+ assert ((DeoptimizingGuard) guard).getCondition() == condition;
+ pendingTests.push((DeoptimizingGuard) guard);
}
registerCondition(condition, negated, guard);
}
@@ -628,15 +629,16 @@
}
protected boolean foldPendingTest(DeoptimizingGuard thisGuard, ValueNode original, Stamp newStamp, GuardRewirer rewireGuardFunction) {
- for (PendingTest pending : pendingTests) {
+ for (DeoptimizingGuard pendingGuard : pendingTests) {
+ LogicNode pendingCondition = pendingGuard.getCondition();
TriState result = TriState.UNKNOWN;
- if (pending.condition instanceof UnaryOpLogicNode) {
- UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pending.condition;
+ if (pendingCondition instanceof UnaryOpLogicNode) {
+ UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) pendingCondition;
if (unaryLogicNode.getValue() == original) {
result = unaryLogicNode.tryFold(newStamp);
}
- } else if (pending.condition instanceof BinaryOpLogicNode) {
- BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pending.condition;
+ } else if (pendingCondition instanceof BinaryOpLogicNode) {
+ BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) pendingCondition;
ValueNode x = binaryOpLogicNode.getX();
ValueNode y = binaryOpLogicNode.getY();
if (x == original) {
@@ -659,7 +661,7 @@
*/
InputFilter v = new InputFilter(original);
thisGuard.getCondition().applyInputs(v);
- if (v.ok && foldGuard(thisGuard, pending.guard, newStamp, rewireGuardFunction)) {
+ if (v.ok && foldGuard(thisGuard, pendingGuard, newStamp, rewireGuardFunction)) {
return true;
}
}
@@ -1026,16 +1028,6 @@
boolean rewire(GuardingNode guard, boolean result, Stamp guardedValueStamp, ValueNode newInput);
}
- protected static class PendingTest {
- private final LogicNode condition;
- private final DeoptimizingGuard guard;
-
- public PendingTest(LogicNode condition, DeoptimizingGuard guard) {
- this.condition = condition;
- this.guard = guard;
- }
- }
-
protected static final class InfoElement {
private final Stamp stamp;
private final GuardingNode guard;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -221,7 +221,12 @@
EconomicMap<ValueNode, Stamp> endMap = endMaps.get(node);
MapCursor<ValueNode, Stamp> entries = endMap.getEntries();
while (entries.advance()) {
- if (registerNewValueStamp(entries.getKey(), entries.getValue())) {
+ ValueNode value = entries.getKey();
+ if (value.isDeleted()) {
+ // nodes from this map can be deleted when a loop dies
+ continue;
+ }
+ if (registerNewValueStamp(value, entries.getValue())) {
counterBetterMergedStamps.increment(debug);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -48,7 +48,7 @@
import org.graalvm.compiler.nodes.VirtualState;
import org.graalvm.compiler.nodes.calc.BinaryNode;
import org.graalvm.compiler.nodes.calc.ConvertNode;
-import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.FloatDivNode;
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
import org.graalvm.compiler.nodes.calc.MulNode;
import org.graalvm.compiler.nodes.calc.NotNode;
@@ -162,7 +162,7 @@
return 2;
} else if (node instanceof LogicNode || node instanceof ConvertNode || node instanceof BinaryNode || node instanceof NotNode) {
return 1;
- } else if (node instanceof IntegerDivRemNode || node instanceof DivNode || node instanceof RemNode) {
+ } else if (node instanceof IntegerDivRemNode || node instanceof FloatDivNode || node instanceof RemNode) {
return 10;
} else if (node instanceof MulNode) {
return 3;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java Mon Nov 06 20:29:49 2017 -0800
@@ -43,7 +43,6 @@
import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache;
import org.graalvm.compiler.phases.tiers.HighTierContext;
-import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
@@ -159,11 +158,11 @@
if (param.usages().isNotEmpty()) {
ValueNode arg = args.get(param.index());
if (arg.isConstant()) {
- Constant constant = arg.asConstant();
+ ConstantNode constant = (ConstantNode) arg;
parameterUsages = trackParameterUsages(param, parameterUsages);
// collect param usages before replacing the param
param.replaceAtUsagesAndDelete(graph.unique(
- ConstantNode.forConstant(arg.stamp(), constant, ((ConstantNode) arg).getStableDimension(), ((ConstantNode) arg).isDefaultStable(), context.getMetaAccess())));
+ ConstantNode.forConstant(arg.stamp(), constant.getValue(), constant.getStableDimension(), constant.isDefaultStable(), context.getMetaAccess())));
// param-node gone, leaving a gap in the sequence given by param.index()
} else {
Stamp impro = improvedStamp(arg, param);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,7 +37,7 @@
* A simple {@link NodeEventListener} implementation that accumulates event nodes in a
* {@link HashSet}.
*/
-public class HashSetNodeEventListener implements NodeEventListener {
+public class HashSetNodeEventListener extends NodeEventListener {
private final EconomicSet<Node> nodes;
private final Set<NodeEvent> filter;
@@ -68,7 +68,7 @@
}
@Override
- public void event(NodeEvent e, Node node) {
+ public void changed(NodeEvent e, Node node) {
if (filter.contains(e)) {
nodes.add(node);
if (node instanceof IndirectCanonicalization) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/BasePhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -258,7 +258,7 @@
return false;
}
- private final class GraphChangeListener implements NodeEventListener {
+ private final class GraphChangeListener extends NodeEventListener {
boolean changed;
private StructuredGraph graph;
private Mark mark;
@@ -269,7 +269,7 @@
}
@Override
- public void event(NodeEvent e, Node node) {
+ public void changed(NodeEvent e, Node node) {
if (!graph.isNew(mark, node) && node.isAlive()) {
if (e == NodeEvent.INPUT_CHANGED || e == NodeEvent.ZERO_USAGES) {
changed = true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -109,7 +109,7 @@
if (immutableGraph && Assertions.assertionsEnabled()) {
return graph.trackNodeEvents(new NodeEventListener() {
@Override
- public void event(NodeEvent e, Node node) {
+ public void changed(NodeEvent e, Node node) {
assert false : "graph changed: " + e + " on node " + node;
}
});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGetOptionsUsage.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,86 @@
+/*
+ * 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.phases.verify;
+
+import java.lang.reflect.MalformedParametersException;
+import java.lang.reflect.Method;
+
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * {@link Node#getOptions()} is unsafe for use during canonicalization so try to verify that it
+ * isn't used when a {@link CanonicalizerTool} is available in the arguments. This is slightly more
+ * general but since there are several canonical methods with varying signatures this covers more
+ * cases.
+ */
+public class VerifyGetOptionsUsage extends VerifyPhase<PhaseContext> {
+ static Method lookupMethod(Class<?> klass, String name) {
+ for (Method m : klass.getDeclaredMethods()) {
+ if (m.getName().equals(name)) {
+ return m;
+ }
+ }
+ throw new InternalError();
+ }
+
+ @Override
+ protected boolean verify(StructuredGraph graph, PhaseContext context) {
+ MetaAccessProvider metaAccess = context.getMetaAccess();
+ ResolvedJavaType canonicalizerToolClass = metaAccess.lookupJavaType(CanonicalizerTool.class);
+ boolean hasTool = false;
+ try {
+ for (ResolvedJavaMethod.Parameter parameter : graph.method().getParameters()) {
+ if (parameter.getType().getName().equals(canonicalizerToolClass.getName())) {
+ hasTool = true;
+ break;
+ }
+ }
+ } catch (MalformedParametersException e) {
+ // Lambdas sometimes have malformed parameters so ignore this.
+ }
+ if (hasTool) {
+ ResolvedJavaMethod getOptionsMethod = metaAccess.lookupJavaMethod(lookupMethod(Node.class, "getOptions"));
+ for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+ ResolvedJavaMethod callee = t.targetMethod();
+ if (callee.equals(getOptionsMethod)) {
+ if (hasTool) {
+ throw new VerificationError("Must use CanonicalizerTool.getOptions() instead of Node.getOptions() in method '%s' of class '%s'.",
+ graph.method().getName(), graph.method().getDeclaringClass().getName());
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,117 @@
+/*
+ * 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.phases.verify;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Graph;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.Invoke;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.PiNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
+import org.graalvm.compiler.nodes.java.NewInstanceNode;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
+import org.graalvm.compiler.phases.VerifyPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.util.EconomicSet;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+public class VerifyGraphAddUsage extends VerifyPhase<PhaseContext> {
+ private static final Method ADD_OR_UNIQUE;
+ private static final Method CONSTRUCTOR_NEW_INSTANCE;
+ private static final EconomicSet<Class<?>> ALLOWED_CLASSES = EconomicSet.create();
+
+ static {
+ try {
+ ADD_OR_UNIQUE = Graph.class.getDeclaredMethod("addOrUnique", Node.class);
+ CONSTRUCTOR_NEW_INSTANCE = Constructor.class.getDeclaredMethod("newInstance", Object[].class);
+ } catch (NoSuchMethodException e) {
+ throw new GraalError(e);
+ }
+
+ ALLOWED_CLASSES.add(Graph.class);
+ ALLOWED_CLASSES.add(LoweringProvider.class);
+ }
+
+ @Override
+ protected boolean verify(StructuredGraph graph, PhaseContext context) {
+ boolean allowed = false;
+ for (Class<?> cls : ALLOWED_CLASSES) {
+ ResolvedJavaType declaringClass = graph.method().getDeclaringClass();
+ if (context.getMetaAccess().lookupJavaType(cls).isAssignableFrom(declaringClass)) {
+ allowed = true;
+ }
+ }
+ if (!allowed) {
+ ResolvedJavaMethod addOrUniqueMethod = context.getMetaAccess().lookupJavaMethod(ADD_OR_UNIQUE);
+ for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) {
+ ResolvedJavaMethod callee = t.targetMethod();
+ if (callee.equals(addOrUniqueMethod)) {
+ ValueNode nodeArgument = t.arguments().get(1);
+ EconomicSet<Node> seen = EconomicSet.create();
+ checkNonFactory(graph, seen, context, nodeArgument);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private void checkNonFactory(StructuredGraph graph, EconomicSet<Node> seen, PhaseContext context, ValueNode node) {
+ if (seen.contains(node)) {
+ return;
+ }
+ seen.add(node);
+
+ // Check where the value came from recursively, or if it is allowed.
+ if (node instanceof ValuePhiNode) {
+ for (ValueNode input : ((ValuePhiNode) node).values()) {
+ checkNonFactory(graph, seen, context, input);
+ }
+ } else if (node instanceof PiNode) {
+ checkNonFactory(graph, seen, context, ((PiNode) node).object());
+ } else if (node instanceof ParameterNode) {
+ return;
+ } else if (node instanceof ConstantNode) {
+ return;
+ } else if (node instanceof ValueProxyNode) {
+ checkNonFactory(graph, seen, context, ((ValueProxyNode) node).value());
+ } else if (node instanceof Invoke && ((Invoke) node).callTarget().targetMethod().equals(context.getMetaAccess().lookupJavaMethod(CONSTRUCTOR_NEW_INSTANCE))) {
+ return;
+ } else if (!(node instanceof NewInstanceNode)) {
+ // In all other cases, the argument must be a new instance.
+ throw new VerificationError("Must add node '%s' with inputs in method '%s' of class '%s'.",
+ node, graph.method().getName(), graph.method().getDeclaringClass().getName());
+ }
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BasicIdealGraphPrinter.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.printer;
-
-import java.io.BufferedOutputStream;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Elementary, generic generator of Ideal Graph Visualizer input for use in printers for specific
- * data structures.
- */
-class BasicIdealGraphPrinter {
-
- /**
- * Edge between two nodes.
- */
- protected static class Edge {
-
- final String from;
- final int fromIndex;
- final String to;
- final int toIndex;
- final String label;
-
- public Edge(String from, int fromIndex, String to, int toIndex, String label) {
- assert (from != null && to != null);
- this.from = from;
- this.fromIndex = fromIndex;
- this.to = to;
- this.toIndex = toIndex;
- this.label = label;
- }
-
- @Override
- public int hashCode() {
- int h = from.hashCode() ^ to.hashCode();
- h = 3 * h + fromIndex;
- h = 5 * h + toIndex;
- if (label != null) {
- h ^= label.hashCode();
- }
- return h;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
- if (obj instanceof Edge) {
- Edge other = (Edge) obj;
- return from.equals(other.from) && fromIndex == other.fromIndex && to.equals(other.to) && toIndex == other.toIndex &&
- (label == other.label || (label != null && label.equals(other.label)));
- }
- return false;
- }
- }
-
- private final PrintStream stream;
-
- /**
- * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
- */
- protected BasicIdealGraphPrinter(OutputStream stream) {
- try {
- OutputStream buffered;
- if (stream instanceof BufferedOutputStream) {
- buffered = stream;
- } else {
- buffered = new BufferedOutputStream(stream, 256 * 1024);
- }
- this.stream = new PrintStream(buffered, false, Charset.defaultCharset().name());
- } catch (UnsupportedEncodingException e) {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Flushes any buffered output.
- */
- protected void flush() {
- stream.flush();
- }
-
- /**
- * Starts a new graph document.
- */
- protected void begin() {
- stream.println("<graphDocument>");
- }
-
- protected void beginGroup() {
- stream.println("<group>");
- }
-
- protected void beginMethod(String name, String shortName, int bci) {
- stream.printf(" <method name='%s' shortName='%s' bci='%d'>%n", escape(name), escape(shortName), bci);
- }
-
- protected void beginBytecodes() {
- stream.println(" <bytecodes>\n<![CDATA[");
- }
-
- protected void printBytecode(int bci, String mnemonic, int[] extra) {
- stream.print(bci);
- stream.print(' ');
- stream.print(mnemonic);
- if (extra != null) {
- for (int b : extra) {
- stream.print(' ');
- stream.print(b);
- }
- }
- stream.println();
- }
-
- protected void endBytecodes() {
- stream.println(" ]]></bytecodes>");
- }
-
- protected void printBytecodes(String disassembly) {
- beginBytecodes();
- stream.println(disassembly);
- endBytecodes();
- }
-
- protected void endMethod() {
- stream.println(" </method>");
- }
-
- protected void beginGraph(String title) {
- stream.printf(" <graph name='%s'>%n", escape(title));
- }
-
- protected void beginProperties() {
- stream.print("<properties>");
- }
-
- protected void printProperty(String name, String value) {
- stream.printf("<p name='%s'>%s</p>", escape(name), escape(value));
- }
-
- protected void endProperties() {
- stream.print("</properties>");
- }
-
- protected void printProperties(Map<String, String> properties) {
- beginProperties();
- for (Entry<String, String> entry : properties.entrySet()) {
- printProperty(entry.getKey(), entry.getValue());
- }
- endProperties();
- }
-
- protected void beginNodes() {
- stream.println(" <nodes>");
- }
-
- protected void beginNode(String id) {
- stream.printf(" <node id='%s'>", escape(id));
- }
-
- protected void endNode() {
- stream.println(" </node>");
- }
-
- protected void printNode(String id, Map<String, String> properties) {
- beginNode(id);
- if (properties != null) {
- printProperties(properties);
- }
- endNode();
- }
-
- protected void endNodes() {
- stream.println(" </nodes>");
- }
-
- protected void beginEdges() {
- stream.println(" <edges>");
- }
-
- protected void printEdge(Edge edge) {
- stream.printf(" <edge from='%s' fromIndex='%d' to='%s' toIndex='%d' label='%s' />%n", escape(edge.from), edge.fromIndex, escape(edge.to), edge.toIndex, escape(edge.label));
- }
-
- protected void endEdges() {
- stream.println(" </edges>");
- }
-
- protected void beginControlFlow() {
- stream.println(" <controlFlow>");
- }
-
- protected void beginBlock(String name) {
- stream.printf(" <block name='%s'>%n", escape(name));
- }
-
- protected void beginSuccessors() {
- stream.println(" <successors>");
- }
-
- protected void printSuccessor(String name) {
- stream.printf(" <successor name='%s'/>%n", escape(name));
- }
-
- protected void endSuccessors() {
- stream.println(" </successors>");
- }
-
- protected void beginBlockNodes() {
- stream.println(" <nodes>");
- }
-
- protected void printBlockNode(String nodeId) {
- stream.printf(" <node id='%s'/>%n", escape(nodeId));
- }
-
- protected void endBlockNodes() {
- stream.println(" </nodes>");
- }
-
- protected void endBlock() {
- stream.println(" </block>");
- }
-
- protected void endControlFlow() {
- stream.println(" </controlFlow>");
- }
-
- protected void endGraph() {
- stream.println(" </graph>");
- }
-
- /**
- * Ends the current group.
- */
- public void endGroup() {
- stream.println("</group>");
- }
-
- /**
- * Finishes the graph document and flushes the output stream.
- */
- protected void end() {
- stream.println("</graphDocument>");
- flush();
- }
-
- public void close() {
- end();
- stream.close();
- }
-
- public boolean isValid() {
- return !stream.checkError();
- }
-
- private static String escape(String s) {
- StringBuilder str = null;
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- switch (c) {
- case '&':
- case '<':
- case '>':
- case '"':
- case '\'':
- if (str == null) {
- str = new StringBuilder();
- str.append(s, 0, i);
- }
- switch (c) {
- case '&':
- str.append("&");
- break;
- case '<':
- str.append("<");
- break;
- case '>':
- str.append(">");
- break;
- case '"':
- str.append(""");
- break;
- case '\'':
- str.append("'");
- break;
- default:
- assert false;
- }
- break;
- case '\u0000':
- case '\u0001':
- case '\u0002':
- case '\u0003':
- case '\u0004':
- case '\u0005':
- case '\u0006':
- case '\u0007':
- case '\u0008':
- case '\u000b':
- case '\u000c':
- case '\u000e':
- case '\u000f':
- case '\u0010':
- case '\u0011':
- case '\u0012':
- case '\u0013':
- case '\u0014':
- case '\u0015':
- case '\u0016':
- case '\u0017':
- case '\u0018':
- case '\u0019':
- case '\u001a':
- case '\u001b':
- case '\u001c':
- case '\u001d':
- case '\u001e':
- case '\u001f':
- if (str == null) {
- str = new StringBuilder();
- str.append(s, 0, i);
- }
- str.append("'0x").append(Integer.toHexString(c));
- break;
- default:
- if (str != null) {
- str.append(c);
- }
- break;
- }
- }
- if (str == null) {
- return s;
- } else {
- return str.toString();
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java Mon Nov 06 20:29:49 2017 -0800
@@ -26,18 +26,17 @@
import static org.graalvm.compiler.graph.Edges.Type.Successors;
import java.io.IOException;
-import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
-import jdk.vm.ci.meta.ResolvedJavaField;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.Bytecode;
import org.graalvm.compiler.core.common.cfg.BlockMap;
+import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.graph.CachedGraph;
import org.graalvm.compiler.graph.Edges;
@@ -46,6 +45,7 @@
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractEndNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
@@ -55,15 +55,11 @@
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.PhiNode;
import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.VirtualState;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.graph.NodeSourcePosition;
-import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.util.JavaConstantFormattable;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.graphio.GraphBlocks;
import org.graalvm.graphio.GraphElements;
@@ -71,6 +67,11 @@
import org.graalvm.graphio.GraphStructure;
import org.graalvm.graphio.GraphTypes;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+
public class BinaryGraphPrinter implements
GraphStructure<BinaryGraphPrinter.GraphInfo, Node, NodeClass<?>, Edges>,
GraphBlocks<BinaryGraphPrinter.GraphInfo, Block, Node>,
@@ -79,8 +80,8 @@
private final SnippetReflectionProvider snippetReflection;
private final GraphOutput<BinaryGraphPrinter.GraphInfo, ResolvedJavaMethod> output;
- public BinaryGraphPrinter(WritableByteChannel channel, SnippetReflectionProvider snippetReflection) throws IOException {
- this.output = GraphOutput.newBuilder(this).blocks(this).elements(this).types(this).build(channel);
+ public BinaryGraphPrinter(DebugContext ctx, SnippetReflectionProvider snippetReflection) throws IOException {
+ this.output = ctx.buildOutput(GraphOutput.newBuilder(this).protocolVersion(5, 0).blocks(this).elements(this).types(this));
this.snippetReflection = snippetReflection;
}
@@ -116,17 +117,24 @@
}
@Override
+ public Node node(Object obj) {
+ return obj instanceof Node ? (Node) obj : null;
+ }
+
+ @Override
public NodeClass<?> nodeClass(Object obj) {
if (obj instanceof NodeClass<?>) {
return (NodeClass<?>) obj;
}
- if (obj instanceof Node) {
- return ((Node) obj).getNodeClass();
- }
return null;
}
@Override
+ public NodeClass<?> classForNode(Node node) {
+ return node.getNodeClass();
+ }
+
+ @Override
public Object nodeClassType(NodeClass<?> node) {
return node.getJavaClass();
}
@@ -257,6 +265,13 @@
}
props.put("category", "floating");
}
+ if (getSnippetReflectionProvider() != null) {
+ for (Map.Entry<String, Object> prop : props.entrySet()) {
+ if (prop.getValue() instanceof JavaConstantFormattable) {
+ props.put(prop.getKey(), ((JavaConstantFormattable) prop.getValue()).format(this));
+ }
+ }
+ }
}
private Object getBlockForNode(Node node, NodeMap<Block> nodeToBlocks) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinterObserver.java Mon Nov 06 20:29:49 2017 -0800
@@ -23,13 +23,13 @@
package org.graalvm.compiler.printer;
import static org.graalvm.compiler.debug.DebugOptions.PrintCFG;
-import static org.graalvm.compiler.printer.GraalDebugHandlersFactory.createDumpPath;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -153,8 +153,8 @@
if (cfgPrinter == null) {
try {
- Graph graph = debug.contextLookupTopdown(Graph.class);
- cfgFile = createDumpPath(options, graph, "cfg", false).toFile();
+ Path dumpFile = debug.getDumpPath(".cfg", false);
+ cfgFile = dumpFile.toFile();
OutputStream out = new BufferedOutputStream(new FileOutputStream(cfgFile));
cfgPrinter = new CFGPrinter(out);
} catch (IOException e) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CanonicalStringGraphPrinter.java Mon Nov 06 20:29:49 2017 -0800
@@ -26,7 +26,6 @@
import static org.graalvm.compiler.debug.DebugOptions.CanonicalGraphStringsExcludeVirtuals;
import static org.graalvm.compiler.debug.DebugOptions.CanonicalGraphStringsRemoveIdentities;
import static org.graalvm.compiler.debug.DebugOptions.PrintCanonicalGraphStringFlavor;
-import static org.graalvm.compiler.printer.GraalDebugHandlersFactory.sanitizedFileName;
import java.io.BufferedWriter;
import java.io.FileWriter;
@@ -44,6 +43,7 @@
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.core.common.Fields;
import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.PathUtilities;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeMap;
@@ -260,11 +260,11 @@
private StructuredGraph currentGraph;
private Path currentDirectory;
- private Path getDirectory(StructuredGraph graph) throws IOException {
+ private Path getDirectory(DebugContext debug, StructuredGraph graph) {
if (graph == currentGraph) {
return currentDirectory;
}
- currentDirectory = GraalDebugHandlersFactory.createDumpPath(graph.getOptions(), graph, "graph-strings", true);
+ currentDirectory = debug.getDumpPath(".graph-strings", true);
currentGraph = graph;
return currentDirectory;
}
@@ -274,9 +274,9 @@
if (graph instanceof StructuredGraph) {
OptionValues options = graph.getOptions();
StructuredGraph structuredGraph = (StructuredGraph) graph;
- Path outDirectory = getDirectory(structuredGraph);
+ Path outDirectory = getDirectory(debug, structuredGraph);
String title = String.format("%03d-%s.txt", id, String.format(format, simplifyClassArgs(args)));
- Path filePath = outDirectory.resolve(sanitizedFileName(title));
+ Path filePath = outDirectory.resolve(PathUtilities.sanitizeFileName(title));
try (PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(filePath.toFile())))) {
switch (PrintCanonicalGraphStringFlavor.getValue(options)) {
case 1:
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraalDebugHandlersFactory.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,44 +22,18 @@
*/
package org.graalvm.compiler.printer;
-import static org.graalvm.compiler.debug.DebugOptions.PrintBinaryGraphPort;
-import static org.graalvm.compiler.debug.DebugOptions.PrintBinaryGraphs;
-import static org.graalvm.compiler.debug.DebugOptions.PrintGraphHost;
-import static org.graalvm.compiler.debug.DebugOptions.PrintXmlGraphPort;
-import static org.graalvm.compiler.debug.DebugOptions.ShowDumpFiles;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.nio.channels.ClosedByInterruptException;
-import java.nio.channels.FileChannel;
-import java.nio.channels.SocketChannel;
-import java.nio.file.FileAlreadyExistsException;
-import java.nio.file.Files;
-import java.nio.file.InvalidPathException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.core.common.CompilationIdentifier;
-import org.graalvm.compiler.debug.Assertions;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugDumpHandler;
import org.graalvm.compiler.debug.DebugHandler;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.debug.TTY;
-import org.graalvm.compiler.debug.PathUtilities;
-import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodeinfo.Verbosity;
-import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.serviceprovider.ServiceProvider;
@@ -80,17 +54,13 @@
@Override
public List<DebugHandler> createHandlers(OptionValues options) {
List<DebugHandler> handlers = new ArrayList<>();
- if (DebugOptions.PrintGraphFile.getValue(options)) {
- handlers.add(new GraphPrinterDumpHandler((graph) -> createFilePrinter(graph, options, snippetReflection)));
- } else {
- handlers.add(new GraphPrinterDumpHandler((graph) -> createNetworkPrinter(graph, options, snippetReflection)));
- }
+ handlers.add(new GraphPrinterDumpHandler((debug, graph) -> new BinaryGraphPrinter(debug, snippetReflection)));
if (DebugOptions.PrintCanonicalGraphStrings.getValue(options)) {
- handlers.add(new GraphPrinterDumpHandler((graph) -> createStringPrinter(snippetReflection)));
+ handlers.add(new GraphPrinterDumpHandler((debug, graph) -> createStringPrinter(snippetReflection)));
}
handlers.add(new NodeDumper());
if (DebugOptions.PrintCFG.getValue(options) || DebugOptions.PrintBackendCFG.getValue(options)) {
- if (DebugOptions.PrintBinaryGraphs.getValue(options) && DebugOptions.PrintCFG.getValue(options)) {
+ if (DebugOptions.PrintCFG.getValue(options)) {
TTY.out.println("Complete C1Visualizer dumping slows down PrintBinaryGraphs: use -Dgraal.PrintCFG=false to disable it");
}
handlers.add(new CFGPrinterObserver());
@@ -119,162 +89,4 @@
return new CanonicalStringGraphPrinter(snippetReflection);
}
- public static String sanitizedFileName(String n) {
- /*
- * First ensure that the name does not contain the directory separator (which would be
- * considered a valid path).
- */
- String name = n.replace(File.separatorChar, '_');
-
- try {
- Paths.get(name);
- return name;
- } catch (InvalidPathException e) {
- // fall through
- }
- StringBuilder buf = new StringBuilder(name.length());
- for (int i = 0; i < name.length(); i++) {
- char c = name.charAt(i);
- try {
- Paths.get(String.valueOf(c));
- } catch (InvalidPathException e) {
- buf.append('_');
- }
- buf.append(c);
- }
- return buf.toString();
- }
-
- private static GraphPrinter createNetworkPrinter(Graph graph, OptionValues options, SnippetReflectionProvider snippetReflection) throws IOException {
- String host = PrintGraphHost.getValue(options);
- int port = PrintBinaryGraphs.getValue(options) ? PrintBinaryGraphPort.getValue(options) : PrintXmlGraphPort.getValue(options);
- try {
- GraphPrinter printer;
- if (DebugOptions.PrintBinaryGraphs.getValue(options)) {
- printer = new BinaryGraphPrinter(SocketChannel.open(new InetSocketAddress(host, port)), snippetReflection);
- } else {
- printer = new IdealGraphPrinter(new Socket(host, port).getOutputStream(), true, snippetReflection);
- }
- TTY.println("Connected to the IGV on %s:%d", host, port);
- return printer;
- } catch (ClosedByInterruptException | InterruptedIOException e) {
- /*
- * Interrupts should not count as errors because they may be caused by a cancelled Graal
- * compilation. ClosedByInterruptException occurs if the SocketChannel could not be
- * opened. InterruptedIOException occurs if new Socket(..) was interrupted.
- */
- return null;
- } catch (IOException e) {
- if (!DebugOptions.PrintGraphFile.hasBeenSet(options)) {
- return createFilePrinter(graph, options, snippetReflection);
- } else {
- throw new IOException(String.format("Could not connect to the IGV on %s:%d", host, port), e);
- }
- }
- }
-
- private static final AtomicInteger unknownCompilationId = new AtomicInteger();
-
- /**
- * Creates a new file or directory for dumping based on a given graph and a file extension.
- *
- * @param graph a base path name is derived from {@code graph}
- * @param extension a suffix which if non-null and non-empty added to the end of the returned
- * path separated by a {@code "."}
- * @param createDirectory specifies if this is a request to create a directory instead of a file
- * @return the created directory or file
- * @throws IOException if there was an error creating the directory or file
- */
- static Path createDumpPath(OptionValues options, Graph graph, String extension, boolean createDirectory) throws IOException {
- CompilationIdentifier compilationId = CompilationIdentifier.INVALID_COMPILATION_ID;
- String id = null;
- String label = null;
- if (graph instanceof StructuredGraph) {
- StructuredGraph sgraph = (StructuredGraph) graph;
- label = getGraphName(sgraph);
- compilationId = sgraph.compilationId();
- if (compilationId == CompilationIdentifier.INVALID_COMPILATION_ID) {
- id = graph.getClass().getSimpleName() + "-" + sgraph.graphId();
- } else {
- id = compilationId.toString(CompilationIdentifier.Verbosity.ID);
- }
- } else {
- label = graph == null ? null : graph.name != null ? graph.name : graph.toString();
- id = "UnknownCompilation-" + unknownCompilationId.incrementAndGet();
- }
- String ext = PathUtilities.formatExtension(extension);
- Path result = createUnique(DebugOptions.getDumpDirectory(options), id, label, ext, createDirectory);
- if (ShowDumpFiles.getValue(options) || Assertions.assertionsEnabled()) {
- TTY.println("Dumping debug output to %s", result.toAbsolutePath().toString());
- }
- return result;
- }
-
- /**
- * A maximum file name length supported by most file systems. There is no platform independent
- * way to get this in Java.
- */
- private static final int MAX_FILE_NAME_LENGTH = 255;
-
- private static final String ELLIPSIS = "...";
-
- private static Path createUnique(Path dumpDir, String id, String label, String ext, boolean createDirectory) throws IOException {
- String timestamp = "";
- for (;;) {
- int fileNameLengthWithoutLabel = timestamp.length() + ext.length() + id.length() + "[]".length();
- int labelLengthLimit = MAX_FILE_NAME_LENGTH - fileNameLengthWithoutLabel;
- String fileName;
- if (labelLengthLimit < ELLIPSIS.length()) {
- // This means `id` is very long
- String suffix = timestamp + ext;
- int idLengthLimit = Math.min(MAX_FILE_NAME_LENGTH - suffix.length(), id.length());
- fileName = sanitizedFileName(id.substring(0, idLengthLimit) + suffix);
- } else {
- if (label == null) {
- fileName = sanitizedFileName(id + timestamp + ext);
- } else {
- String adjustedLabel = label;
- if (label.length() > labelLengthLimit) {
- adjustedLabel = label.substring(0, labelLengthLimit - ELLIPSIS.length()) + ELLIPSIS;
- }
- fileName = sanitizedFileName(id + '[' + adjustedLabel + ']' + timestamp + ext);
- }
- }
- Path result = dumpDir.resolve(fileName);
- try {
- if (createDirectory) {
- return Files.createDirectory(result);
- } else {
- return Files.createFile(result);
- }
- } catch (FileAlreadyExistsException e) {
- timestamp = "_" + Long.toString(System.currentTimeMillis());
- }
- }
- }
-
- private static String getGraphName(StructuredGraph graph) {
- if (graph.name != null) {
- return graph.name;
- } else if (graph.method() != null) {
- return graph.method().format("%h.%n(%p)").replace(" ", "");
- } else {
- return graph.toString();
- }
- }
-
- private static GraphPrinter createFilePrinter(Graph graph, OptionValues options, SnippetReflectionProvider snippetReflection) throws IOException {
- Path path = createDumpPath(options, graph, PrintBinaryGraphs.getValue(options) ? "bgv" : "gv.xml", false);
- try {
- GraphPrinter printer;
- if (DebugOptions.PrintBinaryGraphs.getValue(options)) {
- printer = new BinaryGraphPrinter(FileChannel.open(path, StandardOpenOption.WRITE), snippetReflection);
- } else {
- printer = new IdealGraphPrinter(Files.newOutputStream(path), true, snippetReflection);
- }
- return printer;
- } catch (IOException e) {
- throw new IOException(String.format("Failed to open %s to dump IGV graphs", path), e);
- }
- }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Mon Nov 06 20:29:49 2017 -0800
@@ -35,6 +35,7 @@
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.util.JavaConstantFormatter;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.compiler.serviceprovider.JDK9Method;
@@ -46,7 +47,7 @@
import jdk.vm.ci.runtime.JVMCI;
import jdk.vm.ci.services.Services;
-interface GraphPrinter extends Closeable {
+interface GraphPrinter extends Closeable, JavaConstantFormatter {
/**
* Starts a new group of graphs with the given name, short name and method byte code index (BCI)
@@ -116,30 +117,44 @@
return true;
}
}
+ if (c.getClassLoader() == GraphPrinter.class.getClassLoader()) {
+ return true;
+ }
return false;
}
/**
+ * Use the real {@link Object#toString()} method for {@link JavaConstant JavaConstants} that are
+ * wrapping trusted types, other just return the results of {@link JavaConstant#toString()}.
+ */
+ @Override
+ default String format(JavaConstant constant) {
+ SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider();
+ if (snippetReflection != null) {
+ if (constant.getJavaKind() == JavaKind.Object) {
+ Object obj = snippetReflection.asObject(Object.class, constant);
+ if (obj != null) {
+ return GraphPrinter.constantToString(obj);
+ }
+ }
+ }
+ return constant.toString();
+ }
+
+ /**
* Sets or updates the {@code "rawvalue"} and {@code "toString"} properties in {@code props} for
* {@code cn} if it's a boxed Object value and {@code snippetReflection} can access the raw
* value.
*/
default void updateStringPropertiesForConstant(Map<Object, Object> props, ConstantNode cn) {
- SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider();
- if (snippetReflection != null && cn.getValue() instanceof JavaConstant) {
- JavaConstant constant = (JavaConstant) cn.getValue();
- if (constant.getJavaKind() == JavaKind.Object) {
- Object obj = snippetReflection.asObject(Object.class, constant);
- if (obj != null) {
- String toString = GraphPrinter.constantToString(obj);
- String rawvalue = GraphPrinter.truncate(toString);
- // Overwrite the value inserted by
- // ConstantNode.getDebugProperties()
- props.put("rawvalue", rawvalue);
- if (!rawvalue.equals(toString)) {
- props.put("toString", toString);
- }
- }
+ if (cn.isJavaConstant() && cn.getStackKind().isObject()) {
+ String toString = format(cn.asJavaConstant());
+ String rawvalue = GraphPrinter.truncate(toString);
+ // Overwrite the value inserted by
+ // ConstantNode.getDebugProperties()
+ props.put("rawvalue", rawvalue);
+ if (!rawvalue.equals(toString)) {
+ props.put("toString", toString);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinterDumpHandler.java Mon Nov 06 20:29:49 2017 -0800
@@ -52,8 +52,8 @@
//JaCoCo Exclude
/**
- * Observes compilation events and uses {@link IdealGraphPrinter} to generate a graph representation
- * that can be inspected with the Graph Visualizer.
+ * Observes compilation events and uses {@link BinaryGraphPrinter} to generate a graph
+ * representation that can be inspected with the Graph Visualizer.
*/
public class GraphPrinterDumpHandler implements DebugDumpHandler {
@@ -69,7 +69,7 @@
@FunctionalInterface
public interface GraphPrinterSupplier {
- GraphPrinter get(Graph graph) throws IOException;
+ GraphPrinter get(DebugContext ctx, Graph graph) throws IOException;
}
/**
@@ -93,7 +93,7 @@
}
}
- private void ensureInitialized(Graph graph) {
+ private void ensureInitialized(DebugContext ctx, Graph graph) {
if (printer == null) {
if (failuresCount >= FAILURE_LIMIT) {
return;
@@ -102,7 +102,7 @@
inlineContextMap = new WeakHashMap<>();
DebugContext debug = graph.getDebug();
try {
- printer = printerSupplier.get(graph);
+ printer = printerSupplier.get(ctx, graph);
} catch (IOException e) {
handleException(debug, e);
}
@@ -123,7 +123,7 @@
OptionValues options = debug.getOptions();
if (object instanceof Graph && DebugOptions.PrintGraph.getValue(options)) {
final Graph graph = (Graph) object;
- ensureInitialized(graph);
+ ensureInitialized(debug, graph);
if (printer == null) {
return;
}
@@ -168,11 +168,13 @@
// Save inline context for next dump.
previousInlineContext = inlineContext;
+ // Capture before creating the sandbox
+ String currentScopeName = debug.getCurrentScopeName();
try (DebugContext.Scope s = debug.sandbox("PrintingGraph", null)) {
// Finally, output the graph.
Map<Object, Object> properties = new HashMap<>();
properties.put("graph", graph.toString());
- properties.put("scope", debug.getCurrentScopeName());
+ properties.put("scope", currentScopeName);
if (graph instanceof StructuredGraph) {
properties.put("compilationIdentifier", ((StructuredGraph) graph).compilationId());
try {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/IdealGraphPrinter.java Mon Nov 06 14:12:37 2017 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.printer;
-
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.bytecode.BytecodeDisassembler;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.debug.DebugOptions;
-import org.graalvm.compiler.graph.Graph;
-import org.graalvm.compiler.graph.Node;
-import org.graalvm.compiler.graph.NodeMap;
-import org.graalvm.compiler.graph.Position;
-import org.graalvm.compiler.nodeinfo.Verbosity;
-import org.graalvm.compiler.nodes.AbstractMergeNode;
-import org.graalvm.compiler.nodes.BeginNode;
-import org.graalvm.compiler.nodes.ConstantNode;
-import org.graalvm.compiler.nodes.EndNode;
-import org.graalvm.compiler.nodes.ParameterNode;
-import org.graalvm.compiler.nodes.PhiNode;
-import org.graalvm.compiler.nodes.StateSplit;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
-import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.phases.schedule.SchedulePhase;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-/**
- * Generates a representation of {@link Graph Graphs} that can be visualized and inspected with the
- * <a href="http://kenai.com/projects/igv">Ideal Graph Visualizer</a>.
- */
-public class IdealGraphPrinter extends BasicIdealGraphPrinter implements GraphPrinter {
-
- private final boolean tryToSchedule;
- private final SnippetReflectionProvider snippetReflection;
-
- /**
- * Creates a new {@link IdealGraphPrinter} that writes to the specified output stream.
- *
- * @param tryToSchedule If false, no scheduling is done, which avoids exceptions for
- * non-schedulable graphs.
- */
- public IdealGraphPrinter(OutputStream stream, boolean tryToSchedule, SnippetReflectionProvider snippetReflection) {
- super(stream);
- this.snippetReflection = snippetReflection;
- this.begin();
- this.tryToSchedule = tryToSchedule;
- }
-
- @Override
- public SnippetReflectionProvider getSnippetReflectionProvider() {
- return snippetReflection;
- }
-
- /**
- * Starts a new group of graphs with the given name, short name and method byte code index (BCI)
- * as properties.
- */
- @Override
- public void beginGroup(DebugContext debug, String name, String shortName, ResolvedJavaMethod method, int bci, Map<Object, Object> properties) {
- beginGroup();
- beginProperties();
- printProperty("name", name);
- if (properties != null) {
- for (Entry<Object, Object> entry : properties.entrySet()) {
- printProperty(entry.getKey().toString(), entry.getValue().toString());
- }
- }
- endProperties();
- beginMethod(name, shortName, bci);
- if (method != null && method.getCode() != null) {
- printBytecodes(new BytecodeDisassembler(false).disassemble(method));
- }
- endMethod();
- }
-
- /**
- * Prints an entire {@link Graph} with the specified title, optionally using short names for
- * nodes.
- */
- @Override
- public void print(DebugContext debug, Graph graph, Map<Object, Object> properties, int id, String format, Object... args) {
- String title = id + ": " + String.format(format, simplifyClassArgs(args));
- beginGraph(title);
- EconomicSet<Node> noBlockNodes = EconomicSet.create(Equivalence.IDENTITY);
- ScheduleResult schedule = null;
- if (graph instanceof StructuredGraph) {
- StructuredGraph structuredGraph = (StructuredGraph) graph;
- schedule = structuredGraph.getLastSchedule();
- if (schedule == null && tryToSchedule) {
- OptionValues options = graph.getOptions();
- if (DebugOptions.PrintGraphWithSchedule.getValue(options)) {
- try {
- SchedulePhase schedulePhase = new SchedulePhase(options);
- schedulePhase.apply(structuredGraph);
- schedule = structuredGraph.getLastSchedule();
- } catch (Throwable t) {
- }
- }
- }
- }
- ControlFlowGraph cfg = schedule == null ? null : schedule.getCFG();
-
- if (properties != null) {
- beginProperties();
- for (Entry<Object, Object> entry : properties.entrySet()) {
- printProperty(entry.getKey().toString(), entry.getValue().toString());
- }
- endProperties();
- }
-
- beginNodes();
- List<Edge> edges = printNodes(graph, cfg == null ? null : cfg.getNodeToBlock(), noBlockNodes);
- endNodes();
-
- beginEdges();
- for (Edge edge : edges) {
- printEdge(edge);
- }
- endEdges();
-
- if (cfg != null && cfg.getBlocks() != null) {
- beginControlFlow();
- for (Block block : cfg.getBlocks()) {
- printBlock(graph, block, cfg.getNodeToBlock());
- }
- printNoBlock(noBlockNodes);
- endControlFlow();
- }
-
- endGraph();
- flush();
- }
-
- private List<Edge> printNodes(Graph graph, NodeMap<Block> nodeToBlock, EconomicSet<Node> noBlockNodes) {
- ArrayList<Edge> edges = new ArrayList<>();
-
- NodeMap<Set<Entry<String, Integer>>> colors = graph.createNodeMap();
- NodeMap<Set<Entry<String, String>>> colorsToString = graph.createNodeMap();
- NodeMap<Set<String>> bits = graph.createNodeMap();
-
- for (Node node : graph.getNodes()) {
-
- beginNode(node.toString(Verbosity.Id));
- beginProperties();
- printProperty("idx", node.toString(Verbosity.Id));
-
- Map<Object, Object> props = node.getDebugProperties();
- if (!props.containsKey("name") || props.get("name").toString().trim().length() == 0) {
- String name = node.toString(Verbosity.Name);
- printProperty("name", name);
- }
- printProperty("class", node.getClass().getSimpleName());
-
- Block block = nodeToBlock == null || nodeToBlock.isNew(node) ? null : nodeToBlock.get(node);
- if (block != null) {
- printProperty("block", Integer.toString(block.getId()));
- // if (!(node instanceof PhiNode || node instanceof FrameState || node instanceof
- // ParameterNode) && !block.nodes().contains(node)) {
- // printProperty("notInOwnBlock", "true");
- // }
- } else {
- printProperty("block", "noBlock");
- noBlockNodes.add(node);
- }
-
- Set<Entry<String, Integer>> nodeColors = colors.get(node);
- if (nodeColors != null) {
- for (Entry<String, Integer> color : nodeColors) {
- String name = color.getKey();
- Integer value = color.getValue();
- printProperty(name, Integer.toString(value));
- }
- }
- Set<Entry<String, String>> nodeColorStrings = colorsToString.get(node);
- if (nodeColorStrings != null) {
- for (Entry<String, String> color : nodeColorStrings) {
- String name = color.getKey();
- String value = color.getValue();
- printProperty(name, value);
- }
- }
- Set<String> nodeBits = bits.get(node);
- if (nodeBits != null) {
- for (String bit : nodeBits) {
- printProperty(bit, "true");
- }
- }
- if (node instanceof BeginNode) {
- printProperty("shortName", "B");
- } else if (node.getClass() == EndNode.class) {
- printProperty("shortName", "E");
- } else if (node instanceof ConstantNode) {
- ConstantNode cn = (ConstantNode) node;
- updateStringPropertiesForConstant(props, cn);
- }
- if (node.predecessor() != null) {
- printProperty("hasPredecessor", "true");
- }
-
- try {
- printProperty("NodeCost-Size", node.estimatedNodeSize().toString());
- printProperty("NodeCost-Cycles", node.estimatedNodeCycles().toString());
- } catch (Throwable t) {
- props.put("node-cost-exception", t.getMessage());
- }
-
- for (Entry<Object, Object> entry : props.entrySet()) {
- String key = entry.getKey().toString();
- Object value = entry.getValue();
- String valueString;
- if (value == null) {
- valueString = "null";
- } else {
- Class<?> type = value.getClass();
- if (type.isArray()) {
- if (!type.getComponentType().isPrimitive()) {
- valueString = Arrays.toString((Object[]) value);
- } else if (type.getComponentType() == Integer.TYPE) {
- valueString = Arrays.toString((int[]) value);
- } else if (type.getComponentType() == Double.TYPE) {
- valueString = Arrays.toString((double[]) value);
- } else {
- valueString = toString();
- }
- } else {
- valueString = value.toString();
- }
- }
- printProperty(key, valueString);
- }
-
- endProperties();
- endNode();
-
- // successors
- int fromIndex = 0;
- for (Position position : node.successorPositions()) {
- Node successor = position.get(node);
- if (successor != null) {
- edges.add(new Edge(node.toString(Verbosity.Id), fromIndex, successor.toString(Verbosity.Id), 0, position.getName()));
- }
- fromIndex++;
- }
-
- // inputs
- int toIndex = 1;
- for (Position position : node.inputPositions()) {
- Node input = position.get(node);
- if (input != null) {
- edges.add(new Edge(input.toString(Verbosity.Id), input.successors().count(), node.toString(Verbosity.Id), toIndex, position.getName()));
- }
- toIndex++;
- }
- }
-
- return edges;
- }
-
- private void printBlock(Graph graph, Block block, NodeMap<Block> nodeToBlock) {
- beginBlock(Integer.toString(block.getId()));
- beginSuccessors();
- for (Block sux : block.getSuccessors()) {
- if (sux != null) {
- printSuccessor(Integer.toString(sux.getId()));
- }
- }
- endSuccessors();
- beginBlockNodes();
-
- EconomicSet<Node> nodes = EconomicSet.create(Equivalence.IDENTITY);
-
- if (nodeToBlock != null) {
- for (Node n : graph.getNodes()) {
- Block blk = nodeToBlock.isNew(n) ? null : nodeToBlock.get(n);
- if (blk == block) {
- nodes.add(n);
- }
- }
- }
-
- if (nodes.size() > 0) {
- // if this is the first block: add all locals to this block
- if (block.getBeginNode() == ((StructuredGraph) graph).start()) {
- for (Node node : graph.getNodes()) {
- if (node instanceof ParameterNode) {
- nodes.add(node);
- }
- }
- }
-
- EconomicSet<Node> snapshot = EconomicSet.create(Equivalence.IDENTITY, nodes);
- // add all framestates and phis to their blocks
- for (Node node : snapshot) {
- if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {
- nodes.add(((StateSplit) node).stateAfter());
- }
- if (node instanceof AbstractMergeNode) {
- for (PhiNode phi : ((AbstractMergeNode) node).phis()) {
- nodes.add(phi);
- }
- }
- }
-
- for (Node node : nodes) {
- printBlockNode(node.toString(Verbosity.Id));
- }
- }
- endBlockNodes();
- endBlock();
- }
-
- private void printNoBlock(EconomicSet<Node> noBlockNodes) {
- if (!noBlockNodes.isEmpty()) {
- beginBlock("noBlock");
- beginBlockNodes();
- for (Node node : noBlockNodes) {
- printBlockNode(node.toString(Verbosity.Id));
- }
- endBlockNodes();
- endBlock();
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,13 +22,13 @@
*/
package org.graalvm.compiler.replacements.amd64;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
@@ -44,7 +44,7 @@
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.Value;
-@NodeInfo(size = SIZE_64, cycles = CYCLES_256)
+@NodeInfo(size = SIZE_64, cycles = NodeCycles.CYCLES_UNKNOWN)
public class AMD64StringIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess {
public static final NodeClass<AMD64StringIndexOfNode> TYPE = NodeClass.create(AMD64StringIndexOfNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantBindingParameterPlugin.java Mon Nov 06 20:29:49 2017 -0800
@@ -63,7 +63,7 @@
* This is a node from another graph, so copy over extra state into a new
* ConstantNode.
*/
- constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), otherCon.asConstant(), otherCon.getStableDimension(), otherCon.isDefaultStable(), metaAccess);
+ constantNode = ConstantNode.forConstant(stamp.getTrustedStamp(), otherCon.getValue(), otherCon.getStableDimension(), otherCon.isDefaultStable(), metaAccess);
} else {
constantNode = otherCon;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Mon Nov 06 20:29:49 2017 -0800
@@ -33,6 +33,7 @@
import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength;
import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
@@ -43,6 +44,7 @@
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;
@@ -50,6 +52,7 @@
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodeinfo.InputType;
+import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FieldLocationIdentity;
import org.graalvm.compiler.nodes.FixedNode;
@@ -69,6 +72,7 @@
import org.graalvm.compiler.nodes.calc.RightShiftNode;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.SubNode;
+import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
import org.graalvm.compiler.nodes.extended.BoxNode;
@@ -150,14 +154,16 @@
protected final MetaAccessProvider metaAccess;
protected final ForeignCallsProvider foreignCalls;
protected final TargetDescription target;
+ private final boolean useCompressedOops;
private BoxingSnippets.Templates boxingSnippets;
private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
- public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target) {
+ public DefaultJavaLoweringProvider(MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, TargetDescription target, boolean useCompressedOops) {
this.metaAccess = metaAccess;
this.foreignCalls = foreignCalls;
this.target = target;
+ this.useCompressedOops = useCompressedOops;
}
public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
@@ -218,11 +224,18 @@
lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
} else if (n instanceof StringIndexOfNode) {
lowerIndexOf((StringIndexOfNode) n);
+ } else if (n instanceof UnpackEndianHalfNode) {
+ lowerSecondHalf((UnpackEndianHalfNode) n);
} else {
throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
}
}
+ private void lowerSecondHalf(UnpackEndianHalfNode n) {
+ ByteOrder byteOrder = target.arch.getByteOrder();
+ n.lower(byteOrder);
+ }
+
private void lowerIndexOf(StringIndexOfNode n) {
if (n.getArgument(3).isConstant()) {
SnippetLowering lowering = new SnippetLowering() {
@@ -326,19 +339,21 @@
}
}
+ protected abstract JavaKind getStorageKind(ResolvedJavaField field);
+
protected void lowerLoadFieldNode(LoadFieldNode loadField, LoweringTool tool) {
assert loadField.getStackKind() != JavaKind.Illegal;
StructuredGraph graph = loadField.graph();
ResolvedJavaField field = loadField.field();
ValueNode object = loadField.isStatic() ? staticFieldBase(graph, field) : loadField.object();
object = createNullCheckedValue(object, loadField, tool);
- Stamp loadStamp = loadStamp(loadField.stamp(), field.getJavaKind());
+ Stamp loadStamp = loadStamp(loadField.stamp(), getStorageKind(field));
AddressNode address = createFieldAddress(graph, object, field);
assert address != null : "Field that is loaded must not be eliminated: " + field.getDeclaringClass().toJavaName(true) + "." + field.getName();
ReadNode memoryRead = graph.add(new ReadNode(address, fieldLocationIdentity(field), loadStamp, fieldLoadBarrierType(field)));
- ValueNode readValue = implicitLoadConvert(graph, field.getJavaKind(), memoryRead);
+ ValueNode readValue = implicitLoadConvert(graph, getStorageKind(field), memoryRead);
loadField.replaceAtUsages(readValue);
graph.replaceFixed(loadField, memoryRead);
@@ -355,7 +370,7 @@
ResolvedJavaField field = storeField.field();
ValueNode object = storeField.isStatic() ? staticFieldBase(graph, field) : storeField.object();
object = createNullCheckedValue(object, storeField, tool);
- ValueNode value = implicitStoreConvert(graph, storeField.field().getJavaKind(), storeField.value());
+ ValueNode value = implicitStoreConvert(graph, getStorageKind(storeField.field()), storeField.value());
AddressNode address = createFieldAddress(graph, object, field);
assert address != null;
@@ -651,9 +666,7 @@
protected void lowerJavaWriteNode(JavaWriteNode write) {
StructuredGraph graph = write.graph();
- JavaKind valueKind = write.getWriteKind();
- ValueNode value = implicitStoreConvert(graph, valueKind, write.value(), write.isCompressible());
-
+ ValueNode value = implicitStoreConvert(graph, write.getWriteKind(), write.value(), write.isCompressible());
WriteNode memoryWrite = graph.add(new WriteNode(write.getAddress(), write.getLocationIdentity(), value, write.getBarrierType()));
memoryWrite.setStateAfter(write.stateAfter());
graph.replaceFixedWithFixed(write, memoryWrite);
@@ -918,10 +931,20 @@
return loadStamp(stamp, kind, true);
}
+ private boolean useCompressedOops(JavaKind kind, boolean compressible) {
+ return kind == JavaKind.Object && compressible && useCompressedOops;
+ }
+
+ protected abstract Stamp loadCompressedStamp(ObjectStamp stamp);
+
/**
* @param compressible whether the stamp should be compressible
*/
protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
+ if (useCompressedOops(kind, compressible)) {
+ return loadCompressedStamp((ObjectStamp) stamp);
+ }
+
switch (kind) {
case Boolean:
case Byte:
@@ -949,10 +972,16 @@
return ret;
}
+ protected abstract ValueNode newCompressionNode(CompressionOp op, ValueNode value);
+
/**
- * @param compressible whether the covert should be compressible
+ * @param compressible whether the convert should be compressible
*/
protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
+ if (useCompressedOops(kind, compressible)) {
+ return newCompressionNode(CompressionOp.Uncompress, value);
+ }
+
switch (kind) {
case Byte:
case Short:
@@ -984,6 +1013,10 @@
* @param compressible whether the covert should be compressible
*/
protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
+ if (useCompressedOops(kind, compressible)) {
+ return newCompressionNode(CompressionOp.Compress, value);
+ }
+
switch (kind) {
case Boolean:
case Byte:
@@ -1011,9 +1044,8 @@
LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength);
if (boundsCheck.isTautology()) {
return null;
- } else {
- return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile);
}
+ return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile);
}
protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) {
@@ -1027,9 +1059,8 @@
GuardingNode nullCheck = createNullCheck(object, before, tool);
if (nullCheck == null) {
return object;
- } else {
- return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck));
}
+ return before.graph().maybeAddOrUnique(PiNode.create(object, (object.stamp()).join(StampFactory.objectNonNull()), (ValueNode) nullCheck));
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Mon Nov 06 20:29:49 2017 -0800
@@ -75,7 +75,6 @@
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
/**
@@ -252,6 +251,10 @@
return new MethodCallTargetNode(invokeKind, targetMethod, args, returnStamp, null);
}
+ protected final JavaKind asKind(JavaType type) {
+ return wordTypes != null ? wordTypes.asKind(type) : type.getJavaKind();
+ }
+
/**
* Determines if a given set of arguments is compatible with the signature of a given method.
*
@@ -267,14 +270,12 @@
}
int argIndex = 0;
if (!isStatic) {
- ResolvedJavaType expectedType = method.getDeclaringClass();
- JavaKind expected = wordTypes == null ? expectedType.getJavaKind() : wordTypes.asKind(expectedType);
+ JavaKind expected = asKind(method.getDeclaringClass());
JavaKind actual = args[argIndex++].stamp().getStackKind();
assert expected == actual : graph + ": wrong kind of value for receiver argument of call to " + method + " [" + actual + " != " + expected + "]";
}
for (int i = 0; i != signature.getParameterCount(false); i++) {
- JavaType expectedType = signature.getParameterType(i, method.getDeclaringClass());
- JavaKind expected = wordTypes == null ? expectedType.getJavaKind().getStackKind() : wordTypes.asKind(expectedType).getStackKind();
+ JavaKind expected = asKind(signature.getParameterType(i, method.getDeclaringClass())).getStackKind();
JavaKind actual = args[argIndex++].stamp().getStackKind();
if (expected != actual) {
throw new AssertionError(graph + ": wrong kind of value for argument " + i + " of call to " + method + " [" + actual + " != " + expected + "]");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java Mon Nov 06 20:29:49 2017 -0800
@@ -433,13 +433,14 @@
}
IntrinsicContext initialIntrinsicContext = null;
- if (method.getAnnotation(Snippet.class) == null) {
+ Snippet snippetAnnotation = method.getAnnotation(Snippet.class);
+ if (snippetAnnotation == null) {
// Post-parse inlined intrinsic
initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, bytecodeProvider, INLINE_AFTER_PARSING);
} else {
// Snippet
ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
- initialIntrinsicContext = new IntrinsicContext(original, method, bytecodeProvider, INLINE_AFTER_PARSING);
+ initialIntrinsicContext = new IntrinsicContext(original, method, bytecodeProvider, INLINE_AFTER_PARSING, snippetAnnotation.allowPartialIntrinsicArgumentMismatch());
}
createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), replacements.providers.getConstantFieldProvider(), config,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounter.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetCounter.java Mon Nov 06 20:29:49 2017 -0800
@@ -93,12 +93,7 @@
*/
@Override
public int compareTo(SnippetCounter o) {
- if (value > o.value) {
- return -1;
- } else if (o.value < value) {
- return 1;
- }
- return 0;
+ return Long.signum(o.value - value);
}
private final Group group;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetIntegerHistogram.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,153 @@
+/*
+ * 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.replacements;
+
+/**
+ * A histogram that can (only) be {@linkplain #inc(long) incremented} from within a snippet for
+ * gathering snippet specific metrics.
+ */
+public final class SnippetIntegerHistogram {
+ private final SnippetCounter.Group group;
+ private final String name;
+
+ private final SnippetCounter counter0;
+ private final SnippetCounter counter1;
+ private final SnippetCounter counter2;
+ private final SnippetCounter counter3;
+ private final SnippetCounter counter4;
+ private final SnippetCounter counter5;
+ private final SnippetCounter counter6;
+ private final SnippetCounter counter7;
+ private final SnippetCounter counter8;
+ private final SnippetCounter counter9;
+ private final SnippetCounter counter10;
+
+ private final int counter0UpperBound;
+ private final int counter1UpperBound;
+ private final int counter2UpperBound;
+ private final int counter3UpperBound;
+ private final int counter4UpperBound;
+ private final int counter5UpperBound;
+ private final int counter6UpperBound;
+ private final int counter7UpperBound;
+ private final int counter8UpperBound;
+ private final int counter9UpperBound;
+
+ public SnippetIntegerHistogram(SnippetCounter.Group group, int log2StepLength, String name, String description) {
+ assert log2StepLength > 0;
+
+ this.group = group;
+ this.name = name;
+
+ int lowerBound = 0;
+ counter0UpperBound = 0;
+ counter0 = createCounter(group, name, description, lowerBound, counter0UpperBound);
+
+ lowerBound = counter0UpperBound + 1;
+ counter1UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter1 = createCounter(group, name, description, lowerBound, counter1UpperBound);
+
+ lowerBound = counter1UpperBound + 1;
+ counter2UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter2 = createCounter(group, name, description, lowerBound, counter2UpperBound);
+
+ lowerBound = counter2UpperBound + 1;
+ counter3UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter3 = createCounter(group, name, description, lowerBound, counter3UpperBound);
+
+ lowerBound = counter3UpperBound + 1;
+ counter4UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter4 = createCounter(group, name, description, lowerBound, counter4UpperBound);
+
+ lowerBound = counter4UpperBound + 1;
+ counter5UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter5 = createCounter(group, name, description, lowerBound, counter5UpperBound);
+
+ lowerBound = counter5UpperBound + 1;
+ counter6UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter6 = createCounter(group, name, description, lowerBound, counter6UpperBound);
+
+ lowerBound = counter6UpperBound + 1;
+ counter7UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter7 = createCounter(group, name, description, lowerBound, counter7UpperBound);
+
+ lowerBound = counter7UpperBound + 1;
+ counter8UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter8 = createCounter(group, name, description, lowerBound, counter8UpperBound);
+
+ lowerBound = counter8UpperBound + 1;
+ counter9UpperBound = Math.max(1, lowerBound - 1) << log2StepLength;
+ counter9 = createCounter(group, name, description, lowerBound, counter9UpperBound);
+
+ lowerBound = counter9UpperBound + 1;
+ counter10 = createCounter(group, name, description, lowerBound, Long.MAX_VALUE);
+ }
+
+ private static SnippetCounter createCounter(SnippetCounter.Group group, String name, String description, long lowerBound, long upperBound) {
+ if (group != null) {
+ SnippetCounter snippetCounter = new SnippetCounter(group, name + "[" + lowerBound + ", " + upperBound + "]", description);
+ return snippetCounter;
+ }
+ return null;
+ }
+
+ /**
+ * Increments the value of the matching histogram element. This method can only be used in a
+ * snippet on a compile-time constant {@link SnippetIntegerHistogram} object.
+ */
+ public void inc(long value) {
+ if (group != null) {
+ if (value <= counter0UpperBound) {
+ counter0.inc();
+ } else if (value <= counter1UpperBound) {
+ counter1.inc();
+ } else if (value <= counter2UpperBound) {
+ counter2.inc();
+ } else if (value <= counter3UpperBound) {
+ counter3.inc();
+ } else if (value <= counter4UpperBound) {
+ counter4.inc();
+ } else if (value <= counter5UpperBound) {
+ counter5.inc();
+ } else if (value <= counter6UpperBound) {
+ counter6.inc();
+ } else if (value <= counter7UpperBound) {
+ counter7.inc();
+ } else if (value <= counter8UpperBound) {
+ counter8.inc();
+ } else if (value <= counter9UpperBound) {
+ counter9.inc();
+ } else {
+ counter10.inc();
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (group != null) {
+ return "SnippetHistogram-" + group.name + ":" + name;
+ }
+ return super.toString();
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -23,15 +23,15 @@
package org.graalvm.compiler.replacements.nodes;
import static org.graalvm.compiler.nodeinfo.InputType.Memory;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1024;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1024;
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.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodeinfo.NodeSize;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
@@ -57,7 +57,7 @@
/**
* Compares two arrays with the same length.
*/
-@NodeInfo(cycles = CYCLES_1024, size = SIZE_1024)
+@NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = NodeSize.SIZE_128)
public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLowerable, Canonicalizable, Virtualizable, MemoryAccess {
public static final NodeClass<ArrayEqualsNode> TYPE = NodeClass.create(ArrayEqualsNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -24,7 +24,6 @@
import static org.graalvm.compiler.nodeinfo.InputType.Memory;
import static org.graalvm.compiler.nodeinfo.InputType.State;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
import static org.graalvm.word.LocationIdentity.any;
@@ -32,6 +31,7 @@
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizingNode;
@@ -56,7 +56,7 @@
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaType;
-@NodeInfo(cycles = CYCLES_256, size = SIZE_64)
+@NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = SIZE_64)
public class BasicArrayCopyNode extends AbstractMemoryCheckpoint implements Virtualizable, MemoryCheckpoint.Single, MemoryAccess, Lowerable, DeoptimizingNode.DeoptDuring {
public static final NodeClass<BasicArrayCopyNode> TYPE = NodeClass.create(BasicArrayCopyNode.class);
@@ -215,7 +215,7 @@
return;
}
for (int i = 0; i < len; i++) {
- tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i), false);
+ tool.setVirtualEntry(destVirtual, destPosInt + i, tool.getEntry(srcVirtual, srcPosInt + i));
}
tool.delete();
DebugContext debug = getDebug();
@@ -235,7 +235,7 @@
for (int i = 0; i < len; i++) {
LoadIndexedNode load = new LoadIndexedNode(graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getJavaKind());
tool.addNode(load);
- tool.setVirtualEntry(destVirtual, destPosInt + i, load, false);
+ tool.setVirtualEntry(destVirtual, destPosInt + i, load);
}
tool.delete();
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -22,7 +22,6 @@
*/
package org.graalvm.compiler.replacements.nodes;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
import java.util.Collections;
@@ -32,6 +31,7 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.StampPair;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
import org.graalvm.compiler.nodes.ValueNode;
@@ -49,7 +49,7 @@
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
-@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
+@NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = SIZE_8)
public abstract class BasicObjectCloneNode extends MacroStateSplitNode implements VirtualizableAllocation, ArrayLengthProvider {
public static final NodeClass<BasicObjectCloneNode> TYPE = NodeClass.create(BasicObjectCloneNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BinaryMathIntrinsicNode.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BinaryMathIntrinsicNode.java Mon Nov 06 20:29:49 2017 -0800
@@ -37,7 +37,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.BinaryNode;
-import org.graalvm.compiler.nodes.calc.DivNode;
+import org.graalvm.compiler.nodes.calc.FloatDivNode;
import org.graalvm.compiler.nodes.calc.MulNode;
import org.graalvm.compiler.nodes.calc.SqrtNode;
import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
@@ -141,7 +141,7 @@
// x**-1 = 1/x
if (yValue == -1.0D) {
- return new DivNode(ConstantNode.forDouble(1), x);
+ return new FloatDivNode(ConstantNode.forDouble(1), x);
}
// x**2 = x*x
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java Mon Nov 06 20:29:49 2017 -0800
@@ -36,6 +36,7 @@
import java.util.Collections;
import java.util.List;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugDumpHandler;
@@ -392,6 +393,20 @@
* {@link DebugDumpHandler}s closed in {@link #afterTest()}.
*/
protected DebugContext getDebugContext(OptionValues options) {
+ return getDebugContext(options, null, null);
+ }
+
+ /**
+ * Gets a {@link DebugContext} object corresponding to {@code options}, creating a new one if
+ * none currently exists.Debug contexts created by this method will have their
+ * {@link DebugDumpHandler}s closed in {@link #afterTest()}.
+ *
+ * @param options currently active options
+ * @param id identification of the compilation or {@code null}
+ * @param method method to use for a proper description of the context or {@code null}
+ * @return configured context for compilation
+ */
+ protected DebugContext getDebugContext(OptionValues options, String id, ResolvedJavaMethod method) {
List<DebugContext> cached = cachedDebugs.get();
if (cached == null) {
cached = new ArrayList<>();
@@ -402,7 +417,13 @@
return debug;
}
}
- DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, getDebugHandlersFactories());
+ final DebugContext.Description descr;
+ if (method == null) {
+ descr = NO_DESCRIPTION;
+ } else {
+ descr = new DebugContext.Description(method, id == null ? method.getName() : id);
+ }
+ DebugContext debug = DebugContext.create(options, descr, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, getDebugHandlersFactories());
cached.add(debug);
return debug;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectList.java Mon Nov 06 20:29:49 2017 -0800
@@ -171,9 +171,14 @@
}
public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes, boolean cfgKills) {
+ boolean message = false;
for (int i = 0; i < size(); i++) {
Effect effect = effects[i];
if (effect.isCfgKill() == cfgKills) {
+ if (!message) {
+ message = true;
+ debug.log(cfgKills ? " ==== cfg kill effects" : " ==== effects");
+ }
try {
effect.apply(graph, obsoleteNodes);
} catch (Throwable t) {
@@ -202,7 +207,7 @@
// Inner classes could capture the EffectList itself.
continue;
}
- str.append(first ? "" : ", ").append(format(object));
+ str.append(first ? "" : ", ").append(field.getName()).append("=").append(format(object));
first = false;
} catch (SecurityException | IllegalAccessException e) {
throw new RuntimeException(e);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java Mon Nov 06 20:29:49 2017 -0800
@@ -184,7 +184,6 @@
};
ReentrantBlockIterator.apply(closure, cfg.getStartBlock());
for (GraphEffectList effects : effectList) {
- debug.log(" ==== effects");
effects.apply(graph, obsoleteNodes, false);
}
/*
@@ -193,7 +192,6 @@
* indexes.
*/
for (GraphEffectList effects : effectList) {
- debug.log(" ==== cfg kill effects");
effects.apply(graph, obsoleteNodes, true);
}
debug.dump(DebugContext.DETAILED_LEVEL, graph, "After applying effects");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java Mon Nov 06 20:29:49 2017 -0800
@@ -99,8 +99,8 @@
closure.applyEffects();
}
- if (debug.isDumpEnabled(DebugContext.INFO_LEVEL)) {
- debug.dump(DebugContext.DETAILED_LEVEL, graph, "%s iteration", getName());
+ if (debug.isDumpEnabled(DebugContext.VERBOSE_LEVEL)) {
+ debug.dump(DebugContext.VERBOSE_LEVEL, graph, "%s iteration", getName());
}
new DeadCodeEliminationPhase(Required).apply(graph);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ObjectState.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ObjectState.java Mon Nov 06 20:29:49 2017 -0800
@@ -68,6 +68,7 @@
}
public ObjectState(ValueNode[] entries, LockState locks, boolean ensureVirtualized) {
+ assert checkIllegalValues(entries);
this.entries = entries;
this.locks = locks;
this.ensureVirtualized = ensureVirtualized;
@@ -92,6 +93,30 @@
return new ObjectState(this);
}
+ /**
+ * Ensure that if an {@link JavaConstant#forIllegal() illegal value} is seen that the previous
+ * value is a double word value.
+ */
+ public static boolean checkIllegalValues(ValueNode[] values) {
+ if (values != null) {
+ for (int v = 1; v < values.length; v++) {
+ checkIllegalValue(values, v);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Ensure that if an {@link JavaConstant#forIllegal() illegal value} is seen that the previous
+ * value is a double word value.
+ */
+ public static boolean checkIllegalValue(ValueNode[] values, int v) {
+ if (v > 0 && values[v].isConstant() && values[v].asConstant().equals(JavaConstant.forIllegal())) {
+ assert values[v - 1].getStackKind().needsTwoSlots();
+ }
+ return true;
+ }
+
public EscapeObjectState createEscapeObjectState(DebugContext debug, VirtualObjectNode virtual) {
GET_ESCAPED_OBJECT_STATE.increment(debug);
if (cachedState == null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Mon Nov 06 20:29:49 2017 -0800
@@ -854,6 +854,7 @@
ValueNode nextValue = objectState.getEntry(valueIndex + 1);
if (value.isConstant() && value.asConstant().equals(JavaConstant.INT_0) && nextValue.isConstant() && nextValue.asConstant().equals(JavaConstant.INT_0)) {
// rewrite to a zero constant of the larger kind
+ debug.log("Rewriting entry %s to constant of larger size", valueIndex);
states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph()));
states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()));
} else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java Mon Nov 06 20:29:49 2017 -0800
@@ -30,18 +30,22 @@
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
@@ -58,6 +62,7 @@
private final OptionValues options;
private final DebugContext debug;
private final LoweringProvider loweringProvider;
+ private ConstantNode illegalConstant;
VirtualizerToolImpl(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, PartialEscapeClosure<?> closure,
Assumptions assumptions, OptionValues options, DebugContext debug, LoweringProvider loweringProvider) {
@@ -125,17 +130,81 @@
}
@Override
- public void setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, boolean unsafe) {
+ public boolean setVirtualEntry(VirtualObjectNode virtual, int index, ValueNode value, JavaKind theAccessKind, long offset) {
ObjectState obj = state.getObjectState(virtual);
assert obj.isVirtual() : "not virtual: " + obj;
ValueNode newValue;
+ JavaKind entryKind = virtual.entryKind(index);
+ JavaKind accessKind = theAccessKind != null ? theAccessKind : entryKind;
if (value == null) {
newValue = null;
} else {
newValue = closure.getAliasAndResolve(state, value);
- assert unsafe || obj.getEntry(index) == null || obj.getEntry(index).getStackKind() == newValue.getStackKind() || (isObjectEntry(obj.getEntry(index)) && isObjectEntry(newValue));
+ }
+ getDebug().log(DebugContext.DETAILED_LEVEL, "Setting entry %d in virtual object %s %s results in %s", index, virtual.getObjectId(), virtual, state.getObjectState(virtual.getObjectId()));
+ ValueNode oldValue = getEntry(virtual, index);
+ boolean canVirtualize = entryKind == accessKind || (entryKind == accessKind.getStackKind() && virtual instanceof VirtualInstanceNode);
+ if (!canVirtualize) {
+ if (entryKind == JavaKind.Long && oldValue.getStackKind() == newValue.getStackKind() && oldValue.getStackKind().isPrimitive()) {
+ /*
+ * Special case: If the entryKind is long, allow arbitrary kinds as long as a value
+ * of the same kind is already there. This can only happen if some other node
+ * initialized the entry with a value of a different kind. One example where this
+ * happens is the Truffle NewFrameNode.
+ */
+ getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s with primitive of kind %s in long entry ", current, oldValue.getStackKind());
+ canVirtualize = true;
+ } else if (entryKind == JavaKind.Int && (accessKind == JavaKind.Long || accessKind == JavaKind.Double) && offset % 8 == 0) {
+ /*
+ * Special case: Allow storing a single long or double value into two consecutive
+ * int slots.
+ */
+ int nextIndex = virtual.entryIndexForOffset(offset + 4, JavaKind.Int);
+ if (nextIndex != -1) {
+ canVirtualize = true;
+ assert nextIndex == index + 1 : "expected to be sequential";
+ getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s for double word stored in two ints", current);
+ }
+ }
}
- state.setEntry(virtual.getObjectId(), index, newValue);
+
+ if (canVirtualize) {
+ getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s for entryKind %s and access kind %s", current, entryKind, accessKind);
+ state.setEntry(virtual.getObjectId(), index, newValue);
+ if (entryKind == JavaKind.Int) {
+ if (accessKind.needsTwoSlots()) {
+ // Storing double word value two int slots
+ assert virtual.entryKind(index + 1) == JavaKind.Int;
+ state.setEntry(virtual.getObjectId(), index + 1, getIllegalConstant());
+ } else if (oldValue.getStackKind() == JavaKind.Double || oldValue.getStackKind() == JavaKind.Long) {
+ // Splitting double word constant by storing over it with an int
+ getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s producing second half of double word value %s", current, oldValue);
+ ValueNode secondHalf = UnpackEndianHalfNode.create(oldValue, false);
+ addNode(secondHalf);
+ state.setEntry(virtual.getObjectId(), index + 1, secondHalf);
+ }
+ }
+ if (oldValue.isConstant() && oldValue.asConstant().equals(JavaConstant.forIllegal())) {
+ // Storing into second half of double, so replace previous value
+ ValueNode previous = getEntry(virtual, index - 1);
+ getDebug().log(DebugContext.DETAILED_LEVEL, "virtualizing %s producing first half of double word value %s", current, previous);
+ ValueNode firstHalf = UnpackEndianHalfNode.create(previous, true);
+ addNode(firstHalf);
+ state.setEntry(virtual.getObjectId(), index - 1, firstHalf);
+ }
+ return true;
+ }
+ // Should only occur if there are mismatches between the entry and access kind
+ assert entryKind != accessKind;
+ return false;
+ }
+
+ private ValueNode getIllegalConstant() {
+ if (illegalConstant == null) {
+ illegalConstant = ConstantNode.forConstant(JavaConstant.forIllegal(), getMetaAccessProvider());
+ addNode(illegalConstant);
+ }
+ return illegalConstant;
}
@Override
@@ -149,10 +218,6 @@
return state.getObjectState(virtualObject).getEnsureVirtualized();
}
- private static boolean isObjectEntry(ValueNode value) {
- return value.getStackKind() == JavaKind.Object || value instanceof VirtualObjectNode;
- }
-
@Override
public void replaceWithVirtual(VirtualObjectNode virtual) {
closure.addVirtualAlias(virtual, current);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphOutput.java Mon Nov 06 20:29:49 2017 -0800
@@ -113,12 +113,30 @@
private GraphElements<M, ?, ?, ?> elements = null;
private GraphTypes types = DefaultGraphTypes.DEFAULT;
private GraphBlocks<G, ?, N> blocks = DefaultGraphBlocks.empty();
+ private int major = 4;
+ private int minor = 0;
Builder(GraphStructure<G, N, ?, ?> structure) {
this.structure = structure;
}
/**
+ * Chooses which version of the protocol to use. The default version is <code>4.0</code>
+ * (when the {@link GraphOutput} & co. classes were introduced). The default can be changed
+ * to other known versions manually by calling this method.
+ *
+ * @param majorVersion by default 4, newer version may be known
+ * @param minorVersion usually 0
+ * @return this builder
+ * @since 0.28
+ */
+ public Builder<G, N, M> protocolVersion(int majorVersion, int minorVersion) {
+ this.major = majorVersion;
+ this.minor = minorVersion;
+ return this;
+ }
+
+ /**
* Associates different implementation of types.
*
* @param graphTypes implementation of types and enum recognition
@@ -161,7 +179,28 @@
* @throws IOException if something goes wrong when writing to the channel
*/
public GraphOutput<G, M> build(WritableByteChannel channel) throws IOException {
- ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?> p = new ProtocolImpl<>(structure, types, blocks, elements, channel);
+ ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?> p = new ProtocolImpl<>(major, minor, structure, types, blocks, elements, channel);
+ return new GraphOutput<>(p);
+ }
+
+ /**
+ * Support for nesting heterogenous graphs. The newly created output uses all the interfaces
+ * currently associated with this builder, but shares with {@code parent} the output
+ * {@code channel}, internal constant pool and {@link #protocolVersion(int, int) protocol
+ * version}.
+ * <p>
+ * Both GraphOutput (the {@code parent} and the returned one) has to be used in
+ * synchronization - e.g. only one
+ * {@link #beginGroup(java.lang.Object, java.lang.String, java.lang.String, java.lang.Object, int, java.util.Map)
+ * begin}, {@link #endGroup() end} of group or
+ * {@link #print(java.lang.Object, java.util.Map, int, java.lang.String, java.lang.Object...)
+ * printing} can be on at a given moment.
+ *
+ * @param parent the output to inherit {@code channel} and protocol version from
+ * @return new output sharing {@code channel} and other internals with {@code parent}
+ */
+ public GraphOutput<G, M> build(GraphOutput<?, ?> parent) {
+ ProtocolImpl<G, N, ?, ?, ?, M, ?, ?, ?> p = new ProtocolImpl<>(parent.printer, structure, types, blocks, elements);
return new GraphOutput<>(p);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Mon Nov 06 20:29:49 2017 -0800
@@ -52,6 +52,7 @@
private static final int POOL_FIELD = 0x07;
private static final int POOL_SIGNATURE = 0x08;
private static final int POOL_NODE_SOURCE_POSITION = 0x09;
+ private static final int POOL_NODE = 0x0a;
private static final int PROPERTY_POOL = 0x00;
private static final int PROPERTY_INT = 0x01;
@@ -71,19 +72,12 @@
private final ConstantPool constantPool;
private final ByteBuffer buffer;
private final WritableByteChannel channel;
- private final int versionMajor;
- private final int versionMinor;
-
- protected GraphProtocol(WritableByteChannel channel) throws IOException {
- this(channel, 4, 0);
- }
+ final int versionMajor;
+ final int versionMinor;
- private GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException {
- if (major > 4) {
- throw new IllegalArgumentException();
- }
- if (major == 4 && minor > 0) {
- throw new IllegalArgumentException();
+ GraphProtocol(WritableByteChannel channel, int major, int minor) throws IOException {
+ if (major > 5 || (major == 5 && minor > 0)) {
+ throw new IllegalArgumentException("Unrecognized version " + major + "." + minor);
}
this.versionMajor = major;
this.versionMinor = minor;
@@ -93,6 +87,14 @@
writeVersion();
}
+ GraphProtocol(GraphProtocol<?, ?, ?, ?, ?, ?, ?, ?, ?> parent) {
+ this.versionMajor = parent.versionMajor;
+ this.versionMinor = parent.versionMinor;
+ this.constantPool = parent.constantPool;
+ this.buffer = parent.buffer;
+ this.channel = parent.channel;
+ }
+
@SuppressWarnings("all")
public final void print(Graph graph, Map<? extends Object, ? extends Object> properties, int id, String format, Object... args) throws IOException {
writeByte(BEGIN_GRAPH);
@@ -137,9 +139,33 @@
protected abstract ResolvedJavaMethod findMethod(Object obj);
+ /**
+ * Attempts to recognize the provided object as a node. Used to encode it with
+ * {@link #POOL_NODE} pool type.
+ *
+ * @param obj any object
+ * @return <code>null</code> if it is not a node object, non-null otherwise
+ */
+ protected abstract Node findNode(Object obj);
+
+ /**
+ * Determines whether the provided object is node class or not.
+ *
+ * @param obj object to check
+ * @return {@code null} if {@code obj} does not represent a NodeClass otherwise the NodeClass
+ * represented by {@code obj}
+ */
protected abstract NodeClass findNodeClass(Object obj);
/**
+ * Returns the NodeClass for a given Node {@code obj}.
+ *
+ * @param obj instance of node
+ * @return non-{@code null} instance of the node's class object
+ */
+ protected abstract NodeClass findClassForNode(Node obj);
+
+ /**
* Find a Java class. The returned object must be acceptable by
* {@link #findJavaTypeName(java.lang.Object)} and return valid name for the class.
*
@@ -239,7 +265,7 @@
private void flush() throws IOException {
buffer.flip();
/*
- * Try not to let interrupted threads aborting the write. There's still a race here but an
+ * Try not to let interrupted threads abort the write. There's still a race here but an
* interrupt that's been pending for a long time shouldn't stop this writing.
*/
boolean interrupted = Thread.interrupted();
@@ -338,7 +364,8 @@
}
}
- private void writePoolObject(Object object) throws IOException {
+ private void writePoolObject(Object obj) throws IOException {
+ Object object = obj;
if (object == null) {
writeByte(POOL_NULL);
return;
@@ -347,23 +374,31 @@
if (id == null) {
addPoolEntry(object);
} else {
- if (object instanceof Enum<?> || findEnumOrdinal(object) >= 0) {
- writeByte(POOL_ENUM);
- } else if (object instanceof Class<?> || findJavaTypeName(object) != null) {
- writeByte(POOL_CLASS);
- } else if (findJavaField(object) != null) {
+ if (findJavaField(object) != null) {
writeByte(POOL_FIELD);
} else if (findSignature(object) != null) {
writeByte(POOL_SIGNATURE);
} else if (versionMajor >= 4 && findNodeSourcePosition(object) != null) {
writeByte(POOL_NODE_SOURCE_POSITION);
} else {
+ final Node node = findNode(object);
+ if (versionMajor == 4 && node != null) {
+ object = classForNode(node);
+ }
if (findNodeClass(object) != null) {
writeByte(POOL_NODE_CLASS);
+ } else if (versionMajor >= 5 && node != null) {
+ writeByte(POOL_NODE);
} else if (findMethod(object) != null) {
writeByte(POOL_METHOD);
} else {
- writeByte(POOL_STRING);
+ if (object instanceof Enum<?> || findEnumOrdinal(object) >= 0) {
+ writeByte(POOL_ENUM);
+ } else if (object instanceof Class<?> || findJavaTypeName(object) != null) {
+ writeByte(POOL_CLASS);
+ } else {
+ writeByte(POOL_STRING);
+ }
}
}
writeShort(id.charValue());
@@ -383,10 +418,7 @@
writeInt(size);
int cnt = 0;
for (Node node : findNodes(info)) {
- NodeClass nodeClass = findNodeClass(node);
- if (nodeClass == null) {
- throw new IOException("No class for " + node);
- }
+ NodeClass nodeClass = classForNode(node);
findNodeProperties(node, props, info);
writeInt(findNodeId(node));
@@ -405,7 +437,7 @@
}
private void writeEdges(Graph graph, Node node, boolean dumpInputs) throws IOException {
- NodeClass clazz = findNodeClass(node);
+ NodeClass clazz = classForNode(node);
Edges edges = findClassEdges(clazz, dumpInputs);
int size = findSize(edges);
for (int i = 0; i < size; i++) {
@@ -434,6 +466,14 @@
}
}
+ private NodeClass classForNode(Node node) throws IOException {
+ NodeClass clazz = findClassForNode(node);
+ if (clazz == null) {
+ throw new IOException("No class for " + node);
+ }
+ return clazz;
+ }
+
private void writeNodeRef(Node node) throws IOException {
writeInt(findNodeId(node));
}
@@ -480,7 +520,8 @@
}
@SuppressWarnings("all")
- private void addPoolEntry(Object object) throws IOException {
+ private void addPoolEntry(Object obj) throws IOException {
+ Object object = obj;
ResolvedJavaField field;
String typeName;
Signature signature;
@@ -489,24 +530,7 @@
char index = constantPool.add(object);
writeByte(POOL_NEW);
writeShort(index);
- if ((typeName = findJavaTypeName(object)) != null) {
- writeByte(POOL_CLASS);
- writeString(typeName);
- String[] enumValueNames = findEnumTypeValues(object);
- if (enumValueNames != null) {
- writeByte(ENUM_KLASS);
- writeInt(enumValueNames.length);
- for (String o : enumValueNames) {
- writePoolObject(o);
- }
- } else {
- writeByte(KLASS);
- }
- } else if ((enumOrdinal = findEnumOrdinal(object)) >= 0) {
- writeByte(POOL_ENUM);
- writePoolObject(findEnumClass(object));
- writeInt(enumOrdinal);
- } else if ((field = findJavaField(object)) != null) {
+ if ((field = findJavaField(object)) != null) {
writeByte(POOL_FIELD);
writePoolObject(findFieldDeclaringClass(field));
writePoolObject(findFieldName(field));
@@ -535,6 +559,18 @@
}
writePoolObject(findNodeSourcePositionCaller(pos));
} else {
+ Node node = findNode(object);
+ if (node != null) {
+ if (versionMajor >= 5) {
+ writeByte(POOL_NODE);
+ writeInt(findNodeId(node));
+ writePoolObject(classForNode(node));
+ return;
+ }
+ if (versionMajor == 4) {
+ object = classForNode(node);
+ }
+ }
NodeClass nodeClass = findNodeClass(object);
if (nodeClass != null) {
writeByte(POOL_NODE_CLASS);
@@ -553,8 +589,27 @@
}
ResolvedJavaMethod method = findMethod(object);
if (method == null) {
- writeByte(POOL_STRING);
- writeString(object.toString());
+ if ((typeName = findJavaTypeName(object)) != null) {
+ writeByte(POOL_CLASS);
+ writeString(typeName);
+ String[] enumValueNames = findEnumTypeValues(object);
+ if (enumValueNames != null) {
+ writeByte(ENUM_KLASS);
+ writeInt(enumValueNames.length);
+ for (String o : enumValueNames) {
+ writePoolObject(o);
+ }
+ } else {
+ writeByte(KLASS);
+ }
+ } else if ((enumOrdinal = findEnumOrdinal(object)) >= 0) {
+ writeByte(POOL_ENUM);
+ writePoolObject(findEnumClass(object));
+ writeInt(enumOrdinal);
+ } else {
+ writeByte(POOL_STRING);
+ writeString(object.toString());
+ }
return;
}
writeByte(POOL_METHOD);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphSnippets.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,285 @@
+/*
+ * 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.graphio;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+final class GraphSnippets {
+ static GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> acmeGraphStructure() {
+ // @formatter:off
+ // BEGIN: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
+ class AcmeGraphStructure implements
+ GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> {
+
+ @Override
+ public AcmeGraph graph(AcmeGraph currentGraph, Object obj) {
+ return obj instanceof AcmeGraph ? (AcmeGraph) obj : null;
+ }
+
+ @Override
+ public Iterable<? extends AcmeNode> nodes(AcmeGraph graph) {
+ return graph.allNodes();
+ }
+
+ @Override
+ public int nodesCount(AcmeGraph graph) {
+ return graph.allNodes().size();
+ }
+
+ @Override
+ public int nodeId(AcmeNode node) {
+ return node.id;
+ }
+
+ @Override
+ public boolean nodeHasPredecessor(AcmeNode node) {
+ return node.id > 0;
+ }
+
+ @Override
+ public void nodeProperties(
+ AcmeGraph graph, AcmeNode node, Map<String, ? super Object> properties
+ ) {
+ properties.put("id", node.id);
+ }
+
+ @Override
+ public AcmeNodeType nodeClass(Object obj) {
+ return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null;
+ }
+
+ @Override
+ public AcmeNode node(Object obj) {
+ return obj instanceof AcmeNode ? (AcmeNode) obj : null;
+ }
+
+ @Override
+ public AcmeNodeType classForNode(AcmeNode node) {
+ // we have only one type of nodes
+ return AcmeNodeType.STANDARD;
+ }
+
+
+ @Override
+ public String nameTemplate(AcmeNodeType nodeClass) {
+ return "Acme ({p#id})";
+ }
+
+ @Override
+ public Object nodeClassType(AcmeNodeType nodeClass) {
+ return nodeClass.getClass();
+ }
+
+ @Override
+ public AcmePorts portInputs(AcmeNodeType nodeClass) {
+ return AcmePorts.INPUT;
+ }
+
+ @Override
+ public AcmePorts portOutputs(AcmeNodeType nodeClass) {
+ return AcmePorts.OUTPUT;
+ }
+
+ @Override
+ public int portSize(AcmePorts port) {
+ return port == AcmePorts.OUTPUT ? 1 : 0;
+ }
+
+ @Override
+ public boolean edgeDirect(AcmePorts port, int index) {
+ return false;
+ }
+
+ @Override
+ public String edgeName(AcmePorts port, int index) {
+ return port.name();
+ }
+
+ @Override
+ public Object edgeType(AcmePorts port, int index) {
+ return port;
+ }
+
+ @Override
+ public Collection<? extends AcmeNode> edgeNodes(
+ AcmeGraph graph, AcmeNode node, AcmePorts port, int index
+ ) {
+ if (port == AcmePorts.OUTPUT) {
+ return node.outgoing.targets;
+ }
+ return null;
+ }
+ }
+
+ // END: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
+
+ return new AcmeGraphStructure();
+ }
+
+ // BEGIN: org.graalvm.graphio.GraphSnippets#buildOutput
+ static GraphOutput<AcmeGraph, ?> buildOutput(WritableByteChannel channel)
+ throws IOException {
+ return GraphOutput.newBuilder(acmeGraphStructure()).
+ // use the latest version; currently 5.0
+ protocolVersion(5, 0).
+ build(channel);
+ }
+ // END: org.graalvm.graphio.GraphSnippets#buildOutput
+
+ // BEGIN: org.graalvm.graphio.GraphSnippets#buildAll
+ static GraphOutput<AcmeGraph, ?> buildAll(WritableByteChannel channel)
+ throws IOException {
+ GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = acmeBlocks();
+ GraphElements<AcmeMethod, AcmeField,
+ AcmeSignature, AcmeCodePosition> graphElements = acmeElements();
+ GraphTypes graphTypes = acmeTypes();
+
+ return GraphOutput.newBuilder(acmeGraphStructure()).
+ protocolVersion(5, 0).
+ blocks(graphBlocks).
+ elements(graphElements).
+ types(graphTypes).
+ build(channel);
+ }
+ // END: org.graalvm.graphio.GraphSnippets#buildAll
+
+ private static GraphTypes acmeTypes() {
+ GraphTypes graphTypes = null;
+ // in real world don't return null
+ return graphTypes;
+ }
+
+ private static GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> acmeElements() {
+ GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> graphElements = null;
+ // in real world don't return null
+ return graphElements;
+ }
+
+ private static GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> acmeBlocks() {
+ GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = null;
+ // in real world don't return null
+ return graphBlocks;
+ }
+
+ private static class AcmeGraph {
+ final AcmeNode root;
+
+ AcmeGraph(AcmeNode root) {
+ this.root = root;
+ }
+
+ Set<AcmeNode> allNodes() {
+ return allNodes(root, new LinkedHashSet<>());
+ }
+
+ private static Set<AcmeNode> allNodes(AcmeNode node, Set<AcmeNode> collectTo) {
+ if (collectTo.add(node)) {
+ for (AcmeNode target : node.outgoing.targets) {
+ allNodes(target, collectTo);
+ }
+ }
+ return collectTo;
+ }
+ }
+
+ private static class AcmeNode {
+ final int id;
+ final AcmeEdges outgoing;
+
+ AcmeNode(int id) {
+ this.id = id;
+ this.outgoing = new AcmeEdges();
+ }
+
+ void linkTo(AcmeNode target) {
+ outgoing.targets.add(target);
+ }
+ }
+
+ private enum AcmeNodeType {
+ STANDARD
+ }
+
+ private enum AcmePorts {
+ INPUT,
+ OUTPUT;
+ }
+
+ private static class AcmeEdges {
+ final Set<AcmeNode> targets;
+
+ AcmeEdges() {
+ this.targets = new LinkedHashSet<>();
+ }
+ }
+
+ private static class AcmeBlocks {
+ }
+
+ private static class AcmeMethod {
+ }
+
+ private static class AcmeField {
+ }
+
+ private static class AcmeSignature {
+ }
+
+ private static class AcmeCodePosition {
+ }
+
+ // BEGIN: org.graalvm.graphio.GraphSnippets#dump
+ static void dump(File toFile) throws IOException {
+ try (
+ FileChannel ch = new FileOutputStream(toFile).getChannel();
+ GraphOutput<AcmeGraph, ?> output = buildOutput(ch);
+ ) {
+ AcmeNode root = new AcmeNode(0);
+ AcmeNode n1 = new AcmeNode(1);
+ AcmeNode n2 = new AcmeNode(2);
+ AcmeNode n3 = new AcmeNode(3);
+
+ root.linkTo(n1);
+ root.linkTo(n2);
+ n1.linkTo(n3);
+ n2.linkTo(n3);
+
+ AcmeGraph diamondGraph = new AcmeGraph(root);
+
+ output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null);
+ output.print(diamondGraph, null, 0, "Diamond graph #%d", 1);
+ output.endGroup();
+ }
+ }
+ // END: org.graalvm.graphio.GraphSnippets#dump
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphStructure.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphStructure.java Mon Nov 06 20:29:49 2017 -0800
@@ -38,9 +38,9 @@
*/
public interface GraphStructure<G, N, C, P> {
/**
- * Casts the provided object to graph, if possible. If the given object <code>obj</code> can be
- * seen as a graph or sub-graph of a graph, then return the properly typed instance. Otherwise
- * return <code>null</code>
+ * Casts {@code obj} to graph, if possible. If the given object <code>obj</code> can be seen as
+ * a graph or sub-graph of a graph, then return the properly typed instance. Otherwise return
+ * <code>null</code>
*
* @param currentGraph the currently processed graph
* @param obj an object to check and view as a graph
@@ -69,8 +69,8 @@
int nodesCount(G graph);
/**
- * Id of a node. Each node in the graph is uniquely identified by a integer value. If two nodes
- * have the same id, then they shall be <code>==</code> to each other.
+ * Id of {@code node}. Each node in the graph is uniquely identified by an integer value. If two
+ * nodes have the same id, then they shall be <code>==</code> to each other.
*
* @param node the node to query for an id
* @return the id of the node
@@ -96,16 +96,35 @@
void nodeProperties(G graph, N node, Map<String, ? super Object> properties);
/**
- * Finds the node class for the provided object, if possible. If the given object
- * <code>obj</code> can be seen as an instance of node class or it is a node in this graph,
- * return the properly typed instance of the node class. Otherwise return <code>null</code>
+ * Finds a node for {@code obj}, if possible. If the given object <code>obj</code> can be seen
+ * as an instance of node return the properly typed instance of the node class. Otherwise return
+ * <code>null</code>.
+ *
+ * @param obj an object to find node for
+ * @return appropriate graph object or <code>null</code> if the object doesn't represent a node
+ */
+ N node(Object obj);
+
+ /**
+ * Finds a node class for {@code obj}, if possible. If the given object <code>obj</code> can be
+ * seen as an instance of node class return the properly typed instance of the node class.
+ * Otherwise return <code>null</code>.
*
* @param obj an object to find node class for
- * @return appropriate graph object or <code>null</code> if the object doesn't represent a graph
+ * @return appropriate graph object or <code>null</code> if the object doesn't represent a node
+ * class
*/
C nodeClass(Object obj);
/**
+ * Finds a node class for {@code node}.
+ *
+ * @param node an instance of node in this graph
+ * @return the node's node class, never <code>null</code>
+ */
+ C classForNode(N node);
+
+ /**
* The template used to build the name of nodes of this class. The template may use references
* to inputs ({i#inputName}) and its properties ({p#propertyName}).
*
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java Mon Nov 06 14:12:37 2017 -0500
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java Mon Nov 06 20:29:49 2017 -0800
@@ -34,9 +34,18 @@
private final GraphBlocks<Graph, Block, Node> blocks;
private final GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> elements;
- ProtocolImpl(GraphStructure<Graph, Node, NodeClass, Port> structure, GraphTypes enums, GraphBlocks<Graph, Block, Node> blocks,
+ ProtocolImpl(int major, int minor, GraphStructure<Graph, Node, NodeClass, Port> structure, GraphTypes enums, GraphBlocks<Graph, Block, Node> blocks,
GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> elements, WritableByteChannel channel) throws IOException {
- super(channel);
+ super(channel, major, minor);
+ this.structure = structure;
+ this.types = enums;
+ this.blocks = blocks;
+ this.elements = elements;
+ }
+
+ ProtocolImpl(GraphProtocol<?, ?, ?, ?, ?, ?, ?, ?, ?> parent, GraphStructure<Graph, Node, NodeClass, Port> structure, GraphTypes enums, GraphBlocks<Graph, Block, Node> blocks,
+ GraphElements<ResolvedJavaMethod, ResolvedJavaField, Signature, NodeSourcePosition> elements) {
+ super(parent);
this.structure = structure;
this.types = enums;
this.blocks = blocks;
@@ -49,11 +58,21 @@
}
@Override
+ protected Node findNode(Object obj) {
+ return structure.node(obj);
+ }
+
+ @Override
protected NodeClass findNodeClass(Object obj) {
return structure.nodeClass(obj);
}
@Override
+ protected NodeClass findClassForNode(Node obj) {
+ return structure.classForNode(obj);
+ }
+
+ @Override
protected String findNameTemplate(NodeClass clazz) {
return structure.nameTemplate(clazz);
}
Binary file src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/doc-files/diamond.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,86 @@
+
+/*
+ * 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.
+ */
+
+/**
+ * Send your graphs to <b>IGV</b> via a socket or a file. This package allows one to easily encode
+ * any graph-like data structure and send it for visualization to
+ * <em>OracleLab's Ideal Graph Visualizer</em> tool. Assuming you already have your own data
+ * structure that contains <b>nodes</b> and <b>edges</b> among them, creating a
+ * {@link org.graalvm.graphio.GraphOutput} specialized for your data is a matter of implementing a
+ * single interface:
+ *
+ * {@link org.graalvm.graphio.GraphSnippets#acmeGraphStructure}
+ *
+ * The {@link org.graalvm.graphio.GraphStructure} interface defines the set of operations that are
+ * needed by the <em>graph protocol</em> to encode a graph into the <b>IGV</b> expected format. The
+ * graph structure is implemented as a so called
+ * <a href="http://wiki.apidesign.org/wiki/Singletonizer">singletonizer</a> API pattern: there is no
+ * need to change your data structures or implement some special interfaces - everything needed is
+ * provided by implementing the {@link org.graalvm.graphio.GraphStructure} operations.
+ * <p>
+ * The next step is to turn this graph structure into an instance of
+ * {@link org.graalvm.graphio.GraphOutput}. To do so use the associated
+ * {@link org.graalvm.graphio.GraphOutput.Builder builder} just like shown in the following method:
+ *
+ * {@link org.graalvm.graphio.GraphSnippets#buildOutput}
+ *
+ * Now you are ready to dump your graph into <b>IGV</b>. Where to obtain the right channel? One
+ * option is to create a {@link java.nio.channels.FileChannel} and dump the data into a file
+ * (preferrably with <code>.bgv</code> extension). The other is to open a socket to port
+ * <code>4445</code> (the default port <b>IGV</b> listens to) and dump the data there. Here is an
+ * example:
+ *
+ * {@link org.graalvm.graphio.GraphSnippets#dump}
+ *
+ * Call the {@code dump} method with pointer to file {@code diamond.bgv} and then you can open the
+ * file in <b>IGV</b>. The result will look like this:
+ * <p>
+ * <img src="doc-files/diamond.png">
+ * <p>
+ * You can verify the behavior directly in the <b>IGV</b> by downloading
+ * <a href="doc-files/diamond.bgv">diamond.bgv</a> file generated from the above diamond structure
+ * graph.
+ * <p>
+ * The primary <b>IGV</b> focus is on graphs used by Graal compiler. As such they aren't plain
+ * graphs, but contain various compiler oriented attributes:
+ * <ul>
+ * <li>{@linkplain org.graalvm.graphio.GraphBlocks code blocks} information</li>
+ * <li>{@linkplain org.graalvm.graphio.GraphElements method and fields} information</li>
+ * <li>Advanced support for {@linkplain org.graalvm.graphio.GraphTypes recognizing types}</li>
+ * </ul>
+ * all these additional interfaces ({@link org.graalvm.graphio.GraphBlocks},
+ * {@link org.graalvm.graphio.GraphElements} and {@link org.graalvm.graphio.GraphTypes}) are
+ * optional - they don't have to be provided. As such they can be specified via
+ * {@link org.graalvm.graphio.GraphOutput.Builder} instance methods, which may, but need not be
+ * called at all. Here is an example:
+ *
+ * {@link org.graalvm.graphio.GraphSnippets#buildAll}
+ *
+ * All these interfaces follow the
+ * <a href="http://wiki.apidesign.org/wiki/Singletonizer">singletonizer</a> API pattern again - e.g.
+ * no need to change your existing data structures, just implement the operations provided by the
+ * interfaces you pass into the builder. By combining these interfaces together you can get as rich,
+ * colorful, source linked graphs as Graal compiler produces to describe its optimizations.
+ */
+package org.graalvm.graphio;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml Mon Nov 06 20:29:49 2017 -0800
@@ -0,0 +1,240 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
+
+<!--
+ This configuration file was written by the eclipse-cs plugin configuration editor
+-->
+<!--
+ Checkstyle-Configuration: Checks
+ Description: none
+-->
+<module name="Checker">
+ <property name="severity" value="error"/>
+ <module name="TreeWalker">
+ <module name="AvoidStarImport">
+ <property name="allowClassImports" value="false"/>
+ <property name="allowStaticMemberImports" value="false"/>
+ </module>
+ <property name="tabWidth" value="4"/>
+ <module name="FileContentsHolder"/>
+ <module name="JavadocStyle">
+ <property name="checkHtml" value="false"/>
+ </module>
+ <module name="LocalFinalVariableName"/>
+ <module name="LocalVariableName"/>
+ <module name="MemberName">
+ <property name="format" value="^(([a-z][a-zA-Z0-9]*$)|(_[A-Z][a-zA-Z0-9]*_[a-z][a-zA-Z0-9]*$))"/>
+ </module>
+ <module name="MethodName"/>
+ <module name="PackageName"/>
+ <module name="ParameterName"/>
+ <module name="TypeName">
+ <property name="format" value="^[A-Z][_a-zA-Z0-9]*$"/>
+ </module>
+ <module name="RedundantImport"/>
+ <module name="LineLength">
+ <property name="max" value="250"/>
+ </module>
+ <module name="MethodParamPad"/>
+ <module name="NoWhitespaceAfter">
+ <property name="tokens" value="ARRAY_INIT,BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
+ </module>
+ <module name="NoWhitespaceBefore">
+ <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+ </module>
+ <module name="ParenPad"/>
+ <module name="TypecastParenPad">
+ <property name="tokens" value="RPAREN,TYPECAST"/>
+ </module>
+ <module name="WhitespaceAfter"/>
+ <module name="WhitespaceAround">
+ <property name="tokens" value="ASSIGN,BAND,BAND_ASSIGN,BOR,BOR_ASSIGN,BSR,BSR_ASSIGN,BXOR,BXOR_ASSIGN,COLON,DIV,DIV_ASSIGN,EQUAL,GE,GT,LAND,LE,LITERAL_ASSERT,LITERAL_CATCH,LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_FOR,LITERAL_IF,LITERAL_RETURN,LITERAL_SYNCHRONIZED,LITERAL_TRY,LITERAL_WHILE,LOR,LT,MINUS,MINUS_ASSIGN,MOD,MOD_ASSIGN,NOT_EQUAL,PLUS,PLUS_ASSIGN,QUESTION,SL,SLIST,SL_ASSIGN,SR,SR_ASSIGN,STAR,STAR_ASSIGN,LITERAL_ASSERT,TYPE_EXTENSION_AND"/>
+ </module>
+ <module name="RedundantModifier"/>
+ <module name="AvoidNestedBlocks">
+ <property name="allowInSwitchCase" value="true"/>
+ </module>
+ <module name="EmptyBlock">
+ <property name="option" value="text"/>
+ <property name="tokens" value="LITERAL_DO,LITERAL_ELSE,LITERAL_FINALLY,LITERAL_IF,LITERAL_TRY,LITERAL_WHILE,STATIC_INIT"/>
+ </module>
+ <module name="LeftCurly"/>
+ <module name="NeedBraces"/>
+ <module name="RightCurly"/>
+ <module name="EmptyStatement"/>
+ <module name="HiddenField">
+ <property name="severity" value="ignore"/>
+ <property name="ignoreConstructorParameter" value="true"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="FinalClass"/>
+ <module name="HideUtilityClassConstructor">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="ArrayTypeStyle"/>
+ <module name="UpperEll"/>
+ <module name="FallThrough"/>
+ <module name="FinalLocalVariable">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="MultipleVariableDeclarations"/>
+ <module name="StringLiteralEquality">
+ <property name="severity" value="error"/>
+ </module>
+ <module name="SuperFinalize"/>
+ <module name="UnnecessaryParentheses">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="Indentation">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="StaticVariableName">
+ <property name="format" value="^[A-Za-z][a-zA-Z0-9]*$"/>
+ </module>
+ <module name="EmptyForInitializerPad"/>
+ <module name="EmptyForIteratorPad"/>
+ <module name="ModifierOrder"/>
+ <module name="DefaultComesLast"/>
+ <module name="InnerAssignment">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="ModifiedControlVariable"/>
+ <module name="MutableException">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="ParameterAssignment">
+ <property name="severity" value="ignore"/>
+ <metadata name="net.sf.eclipsecs.core.lastEnabledSeverity" value="inherit"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
+ <property name="format" value="\s$"/>
+ <property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
+ <property name="ignoreComments" value="true"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <metadata name="net.sf.eclipsecs.core.comment" value="illegal space before a comma"/>
+ <property name="format" value=" ,"/>
+ <property name="message" value="illegal space before a comma"/>
+ <property name="ignoreComments" value="true"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for whitespace before a comma."/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.customMessage" value="Illegal whitespace before a comma."/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="[^\x00-\x7F]"/>
+ <property name="message" value="Only use ASCII characters."/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="new (Hashtable|Vector|Stack|StringBuffer)[^\w]"/>
+ <property name="message" value="Don't use old synchronized collection classes"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="instanceof MoveOp"/>
+ <property name="message" value="Do not use `op instanceof MoveOp`. Use `MoveOp.isMoveOp(op)` instead!"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="instanceof ValueMoveOp"/>
+ <property name="message" value="Do not use `op instanceof ValueMoveOp`. Use `ValueMoveOp.isValueMoveOp(op)` instead!"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="instanceof LoadConstantOp"/>
+ <property name="message" value="Do not use `op instanceof LoadConstantOp`. Use `LoadConstantOp.isLoadConstantOp(op)` instead!"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="\(MoveOp\)"/>
+ <property name="message" value="Do not cast directly to `MoveOp`. Use `MoveOp.asMoveOp(op)` instead!"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="\(ValueMoveOp\)"/>
+ <property name="message" value="Do not cast directly to `ValueMoveOp`. Use `ValueMoveOp.asValueMoveOp(op)` instead!"/>
+ </module>
+ <module name="RegexpSinglelineJava">
+ <property name="format" value="\(LoadConstantOp\)"/>
+ <property name="message" value="Do not cast directly to `LoadConstantOp`. Use `LoadConstantOp.asLoadConstantOp(op)` instead!"/>
+ </module>
+ </module>
+ <module name="RegexpHeader">
+ <property name="header" value="/\*\n \* Copyright \(c\) (20[0-9][0-9], )?20[0-9][0-9], Oracle and/or its affiliates. All rights reserved.\n \* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.\n \*\n \* This code is free software; you can redistribute it and/or modify it\n \* under the terms of the GNU General Public License version 2 only, as\n \* published by the Free Software Foundation. Oracle designates this\n \* particular file as subject to the "Classpath" exception as provided\n \* by Oracle in the LICENSE file that accompanied this code.\n \*\n \* This code is distributed in the hope that it will be useful, but WITHOUT\n \* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n \* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n \* version 2 for more details \(a copy is included in the LICENSE file that\n \* accompanied this code\).\n \*\n \* You should have received a copy of the GNU General Public License version\n \* 2 along with this work; if not, write to the Free Software Foundation,\n \* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.\n \*\n \* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA\n \* or visit www.oracle.com if you need additional information or have any\n \* questions.\n \*/\n"/>
+ <property name="fileExtensions" value="java"/>
+ </module>
+ <module name="FileTabCharacter">
+ <property name="severity" value="error"/>
+ <property name="fileExtensions" value="java"/>
+ </module>
+ <module name="NewlineAtEndOfFile">
+ <property name="lineSeparator" value="lf"/>
+ </module>
+ <module name="Translation"/>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="Checkstyle: stop constant name check"/>
+ <property name="onCommentFormat" value="Checkstyle: resume constant name check"/>
+ <property name="checkFormat" value="ConstantNameCheck"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Allow non-conforming constant names"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="Checkstyle: stop method name check"/>
+ <property name="onCommentFormat" value="Checkstyle: resume method name check"/>
+ <property name="checkFormat" value="MethodName"/>
+ <property name="checkC" value="false"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable method name checks"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CheckStyle: stop parameter assignment check"/>
+ <property name="onCommentFormat" value="CheckStyle: resume parameter assignment check"/>
+ <property name="checkFormat" value="ParameterAssignment"/>
+ <property name="checkC" value="false"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable Parameter Assignment"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="Checkstyle: stop final variable check"/>
+ <property name="onCommentFormat" value="Checkstyle: resume final variable check"/>
+ <property name="checkFormat" value="FinalLocalVariable"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable final variable checks"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="Checkstyle: stop"/>
+ <property name="onCommentFormat" value="Checkstyle: resume"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable all checks"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CheckStyle: stop inner assignment check"/>
+ <property name="onCommentFormat" value="CheckStyle: resume inner assignment check"/>
+ <property name="checkFormat" value="InnerAssignment"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable inner assignment checks"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="Checkstyle: stop field name check"/>
+ <property name="onCommentFormat" value="Checkstyle: resume field name check"/>
+ <property name="checkFormat" value="MemberName"/>
+ <property name="checkC" value="false"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable field name checks"/>
+ </module>
+ <module name="RegexpMultiline">
+ <metadata name="net.sf.eclipsecs.core.comment" value="illegal Windows line ending"/>
+ <property name="format" value="\r\n"/>
+ <property name="message" value="illegal Windows line ending"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CheckStyle: stop header check"/>
+ <property name="onCommentFormat" value="CheckStyle: resume header check"/>
+ <property name="checkFormat" value=".*Header"/>
+ <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Disable header checks"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CheckStyle: stop line length check"/>
+ <property name="onCommentFormat" value="CheckStyle: resume line length check"/>
+ <property name="checkFormat" value="LineLength"/>
+ </module>
+ <module name="SuppressionCommentFilter">
+ <property name="offCommentFormat" value="CheckStyle: start generated"/>
+ <property name="onCommentFormat" value="CheckStyle: stop generated"/>
+ <property name="checkFormat" value=".*Name|.*LineLength|.*Header"/>
+ </module>
+</module>