8226771: Update Graal

Reviewed-by: kvn
This commit is contained in:
Dean Long 2019-07-25 17:35:58 -04:00
parent a8af569fa0
commit bc1ccab62c
131 changed files with 2693 additions and 610 deletions
src
jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management
jdk.internal.vm.compiler/share/classes
jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal
org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test
org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test
org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64
org.graalvm.compiler.core.amd64.test/src/org/graalvm/compiler/core/amd64/test
org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64
org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common
org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc
org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test
org.graalvm.compiler.core/src/org/graalvm/compiler/core
org.graalvm.compiler.graph/src/org/graalvm/compiler/graph
org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64
org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64
org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test
org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc
org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test
org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot
org.graalvm.compiler.java/src/org/graalvm/compiler/java
org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64
org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64
org.graalvm.compiler.lir.jtt/src/org/graalvm/compiler/lir/jtt
org.graalvm.compiler.lir/src/org/graalvm/compiler/lir
org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test
org.graalvm.compiler.loop/src/org/graalvm/compiler/loop
org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes

@ -156,9 +156,10 @@ public final class HotSpotGraalManagement implements HotSpotGraalManagementRegis
platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
process();
}
} catch (SecurityException e) {
} catch (SecurityException | UnsatisfiedLinkError | NoClassDefFoundError | UnsupportedOperationException e) {
// Without permission to find or create the MBeanServer,
// we cannot process any Graal mbeans.
// Various other errors can occur in the ManagementFactory (JDK-8076557)
deferred = null;
}
} else {

@ -0,0 +1,69 @@
/*
* Copyright (c) 2019, 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.api.directives.test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.junit.Assert;
import org.junit.Test;
public class ConstantProbablityBranchFoldingTest extends GraalCompilerTest {
public static int branchFoldingSnippet1() {
if (GraalDirectives.injectBranchProbability(0.5, true)) {
return 1;
} else {
return 2;
}
}
public static int branchFoldingSnippet2() {
if (GraalDirectives.injectBranchProbability(0.5, false)) {
return 1;
} else {
return 2;
}
}
@Test
public void testEarlyFolding1() {
test("branchFoldingSnippet1");
}
@Test
public void testEarlyFolding2() {
test("branchFoldingSnippet2");
}
@Override
protected void checkLowTierGraph(StructuredGraph graph) {
NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
Assert.assertEquals("IfNode count", 0, ifNodes.count());
}
}

@ -75,6 +75,9 @@ public class AArch64BitCountAssemblerTest extends AssemblerTest {
AArch64MacroAssembler masm = new AArch64MacroAssembler(target);
Register dst = registerConfig.getReturnRegister(JavaKind.Int);
Register src = asRegister(cc.getArgument(0));
// Generate a nop first as AArch64 Hotspot requires instruction at nmethod verified
// entry to be a jump or nop. (See https://github.com/oracle/graal/issues/1439)
masm.nop();
RegisterArray registers = registerConfig.filterAllocatableRegisters(AArch64Kind.V64_BYTE, registerConfig.getAllocatableRegisters());
masm.popcnt(size, dst, src, registers.get(registers.size() - 1));
masm.ret(AArch64.lr);

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, 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.aarch64;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
public interface AArch64LoweringProviderMixin extends LoweringProvider {
@Override
default Integer smallestCompareWidth() {
return 32;
}
@Override
default boolean supportBulkZeroing() {
return false;
}
}

@ -80,9 +80,9 @@ public class AArch64ReadNode extends ReadNode {
*/
public static void replace(ReadNode readNode) {
assert readNode.getUsageCount() == 1;
assert readNode.getUsageAt(0) instanceof ZeroExtendNode || readNode.getUsageAt(0) instanceof SignExtendNode;
assert readNode.usages().first() instanceof ZeroExtendNode || readNode.usages().first() instanceof SignExtendNode;
ValueNode usage = (ValueNode) readNode.getUsageAt(0);
ValueNode usage = (ValueNode) readNode.usages().first();
boolean isSigned = usage instanceof SignExtendNode;
IntegerStamp accessStamp = ((IntegerStamp) readNode.getAccessStamp());

@ -49,7 +49,7 @@ public class AArch64ReadReplacementPhase extends Phase {
if (node instanceof ReadNode) {
ReadNode readNode = (ReadNode) node;
if (readNode.hasExactlyOneUsage()) {
Node usage = readNode.getUsageAt(0);
Node usage = readNode.usages().first();
if (usage instanceof ZeroExtendNode || usage instanceof SignExtendNode) {
AArch64ReadNode.replace(readNode);
}

@ -24,8 +24,10 @@
package org.graalvm.compiler.core.aarch64;
import java.util.List;
import java.util.ListIterator;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.java.DefaultSuitesCreator;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValues;
@ -37,24 +39,33 @@ import org.graalvm.compiler.phases.tiers.LowTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
public class AArch64SuitesCreator extends DefaultSuitesCreator {
private final Class<? extends Phase> insertReadReplacementBefore;
private final List<Class<? extends Phase>> insertReadReplacementBeforePositions;
public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, Class<? extends Phase> insertReadReplacementBefore) {
public AArch64SuitesCreator(CompilerConfiguration compilerConfiguration, Plugins plugins, List<Class<? extends Phase>> insertReadReplacementBeforePositions) {
super(compilerConfiguration, plugins);
this.insertReadReplacementBefore = insertReadReplacementBefore;
this.insertReadReplacementBeforePositions = insertReadReplacementBeforePositions;
}
@Override
public Suites createSuites(OptionValues options) {
Suites suites = super.createSuites(options);
ListIterator<BasePhase<? super LowTierContext>> findPhase = suites.getLowTier().findPhase(insertReadReplacementBefore);
// Put AArch64ReadReplacementPhase right before the SchedulePhase
while (PhaseSuite.findNextPhase(findPhase, insertReadReplacementBefore)) {
// Search for last occurrence of SchedulePhase
ListIterator<BasePhase<? super LowTierContext>> findPhase = null;
for (Class<? extends Phase> phase : insertReadReplacementBeforePositions) {
findPhase = suites.getLowTier().findPhase(phase);
if (findPhase != null) {
// Put AArch64ReadReplacementPhase right before the requested phase
while (PhaseSuite.findNextPhase(findPhase, phase)) {
// Search for last occurrence of SchedulePhase
}
findPhase.previous();
break;
}
}
if (findPhase != null) {
findPhase.add(new AArch64ReadReplacementPhase());
} else {
throw GraalError.shouldNotReachHere("Cannot find phase to insert AArch64ReadReplacementPhase");
}
findPhase.previous();
findPhase.add(new AArch64ReadReplacementPhase());
return suites;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -143,7 +143,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runByte() throws Throwable {
public void runByte() {
runTest("testByte");
}
@ -157,7 +157,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runShort() throws Throwable {
public void runShort() {
runTest("testShort");
}
@ -171,7 +171,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runInt() throws Throwable {
public void runInt() {
runTest("testInt");
}
@ -185,7 +185,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runLong() throws Throwable {
public void runLong() {
runTest("testLong");
}
@ -199,7 +199,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runFloat() throws Throwable {
public void runFloat() {
runTest("testFloat");
}
@ -213,7 +213,7 @@ public class ConstantStackMoveTest extends LIRTest {
}
@Test
public void runDouble() throws Throwable {
public void runDouble() {
runTest("testDouble");
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -113,7 +113,7 @@ public class StackStoreTest extends LIRTest {
}
@Test
public void run0() throws Throwable {
public void run0() {
runTest("test0", 0xDEADDEAD);
}
@ -122,7 +122,7 @@ public class StackStoreTest extends LIRTest {
}
@Test
public void run1() throws Throwable {
public void run1() {
runTest("test1", 0xDEADDEAD);
}
@ -131,7 +131,7 @@ public class StackStoreTest extends LIRTest {
}
@Test
public void run2() throws Throwable {
public void run2() {
runTest("test2", 0xDEADDEAD);
}

@ -126,6 +126,7 @@ import org.graalvm.compiler.lir.amd64.AMD64Ternary;
import org.graalvm.compiler.lir.amd64.AMD64Unary;
import org.graalvm.compiler.lir.amd64.AMD64ZeroMemoryOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary.AVXBinaryConstFloatOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary.AVXBinaryOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorUnary;
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
@ -1360,9 +1361,13 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
}
}
private Variable emitBinary(LIRKind resultKind, VexRVMOp op, Value a, Value b) {
protected Variable emitBinary(LIRKind resultKind, VexRVMOp op, Value a, Value b) {
Variable result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new AVXBinaryOp(op, getRegisterSize(result), result, asAllocatable(a), asAllocatable(b)));
if (b instanceof ConstantValue && (b.getPlatformKind() == AMD64Kind.SINGLE || b.getPlatformKind() == AMD64Kind.DOUBLE)) {
getLIRGen().append(new AVXBinaryConstFloatOp(op, getRegisterSize(result), result, asAllocatable(a), (ConstantValue) b));
} else {
getLIRGen().append(new AVXBinaryOp(op, getRegisterSize(result), result, asAllocatable(a), asAllocatable(b)));
}
return result;
}

@ -47,8 +47,8 @@ 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.AMD64BaseAssembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.Condition;
@ -80,10 +80,10 @@ 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.HashTableSwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.HashTableSwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64LFenceOp;
import org.graalvm.compiler.lir.amd64.AMD64Move;
import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, 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;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
public interface AMD64LoweringProviderMixin extends LoweringProvider {
@Override
default Integer smallestCompareWidth() {
return 8;
}
@Override
default boolean supportBulkZeroing() {
return true;
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -50,6 +50,7 @@ import jdk.vm.ci.code.Register;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.PrimitiveConstant;
import jdk.vm.ci.meta.Value;
public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
@ -65,6 +66,9 @@ public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
switch (c.getJavaKind()) {
case Long:
return NumUtil.isInt(c.asLong());
case Float:
case Double:
return false;
case Object:
return c.isNull();
default:
@ -74,6 +78,12 @@ public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
return false;
}
@Override
public boolean mayEmbedConstantLoad(Constant constant) {
// Only consider not inlineable constants here.
return constant instanceof PrimitiveConstant && ((PrimitiveConstant) constant).getJavaKind().isNumericFloat();
}
@Override
public boolean allowConstantToStackMove(Constant constant) {
if (constant instanceof DataPointerConstant) {

@ -289,4 +289,6 @@ public final class GraalOptions {
@Option(help = "If applicable, use bulk zeroing instructions when the zeroing size in bytes exceeds this threshold.", type = OptionType.Expert)
public static final OptionKey<Integer> MinimalBulkZeroingSize = new OptionKey<>(2048);
@Option(help = "Alignment in bytes for loop header blocks.", type = OptionType.Expert)
public static final OptionKey<Integer> LoopHeaderAlignment = new OptionKey<>(16);
}

@ -32,6 +32,8 @@ import static org.graalvm.compiler.core.common.util.TypeConversion.asU2;
import static org.graalvm.compiler.core.common.util.TypeConversion.asU4;
import static org.graalvm.compiler.serviceprovider.GraalUnsafeAccess.getUnsafe;
import java.nio.ByteBuffer;
import org.graalvm.compiler.core.common.calc.UnsignedMath;
import sun.misc.Unsafe;
@ -103,6 +105,17 @@ public abstract class UnsafeArrayTypeWriter implements TypeWriter {
return result;
}
/** Copies the buffer into the provided ByteBuffer at its current position. */
public final ByteBuffer toByteBuffer(ByteBuffer buffer) {
assert buffer.remaining() <= totalSize;
int initialPos = buffer.position();
for (Chunk cur = firstChunk; cur != null; cur = cur.next) {
buffer.put(cur.data, 0, cur.size);
}
assert buffer.position() - initialPos == totalSize;
return buffer;
}
@Override
public final void putS1(long value) {
long offset = writeOffset(Byte.BYTES);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2019, 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

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019, 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.sparc;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
public interface SparcLoweringProviderMixin extends LoweringProvider {
@Override
default Integer smallestCompareWidth() {
return 32;
}
@Override
default boolean supportBulkZeroing() {
return false;
}
}

@ -63,4 +63,3 @@ public class ConditionalEliminationPiTest extends ConditionalEliminationTestBase
test("testSnippet1", 1);
}
}

@ -24,6 +24,7 @@
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
import org.junit.Test;
public class ConditionalNodeTest extends GraalCompilerTest {
@ -106,4 +107,23 @@ public class ConditionalNodeTest extends GraalCompilerTest {
sink0 = 1;
return Math.min(-1, value);
}
@Test
public void test4() {
test("conditionalTest4", this, 0);
test("conditionalTest4", this, 1);
}
int a;
InvokeKind b;
public static int conditionalTest4(ConditionalNodeTest node, int a) {
if (a == 1) {
node.b = InvokeKind.Virtual;
} else {
node.b = InvokeKind.Special;
}
node.a = a;
return a;
}
}

@ -53,17 +53,18 @@ public class DumpPathTest extends GraalCompilerTest {
String[] extensions = new String[]{".cfg", ".bgv", ".graph-strings"};
EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
overrides.put(DebugOptions.DumpPath, dumpDirectoryPath.toString());
overrides.put(DebugOptions.PrintCFG, true);
overrides.put(DebugOptions.PrintGraph, PrintGraphTarget.File);
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.
// Check that IGV files got created, in the right place.
checkForFiles(dumpDirectoryPath, extensions);
// Clean up the generated files.
scrubDirectory(dumpDirectoryPath);
removeDirectory(dumpDirectoryPath);
}
/**
@ -92,24 +93,4 @@ public class DumpPathTest extends GraalCompilerTest {
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();
}
}
}

@ -29,7 +29,6 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest {
@ -44,7 +43,6 @@ public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest {
* {@link PersonImpl#getName()} and {@link Tenant#getName()}).
*/
@Test
@Ignore("fix HotSpotResolvedObjectTypeImpl.findUniqueConcreteMethod")
public void test() throws NoSuchMethodException {
ResolvedJavaMethod ifaceMethod = getMetaAccess().lookupJavaMethod(Person.class.getDeclaredMethod("getName"));
@ -64,9 +62,8 @@ public class FindUniqueConcreteMethodBugTest extends GraalCompilerTest {
// this causes a VM crash as getLabelLength() directly invokes PersonImpl.getName().
test("getLabelLength", tenant);
ResolvedJavaMethod expected = null;
AssumptionResult<ResolvedJavaMethod> actual = getMetaAccess().lookupJavaType(AbstractPerson.class).findUniqueConcreteMethod(ifaceMethod);
Assert.assertEquals(expected, actual.getResult());
Assert.assertNull(String.valueOf(actual), actual);
}

@ -1116,8 +1116,14 @@ public abstract class GraalCompilerTest extends GraalTest {
return graph;
}
@SuppressWarnings("try")
protected void applyFrontEnd(StructuredGraph graph) {
GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), getOptimisticOptimizations(), graph.getProfilingInfo(), createSuites(graph.getOptions()));
DebugContext debug = graph.getDebug();
try (DebugContext.Scope s = debug.scope("FrontEnd", graph)) {
GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), getOptimisticOptimizations(), graph.getProfilingInfo(), createSuites(graph.getOptions()));
} catch (Throwable e) {
throw debug.handle(e);
}
}
protected StructuredGraph lastCompiledGraph;

@ -0,0 +1,491 @@
/*
* Copyright (c) 2019, 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.debug.DebugContext;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.junit.Test;
public class SwitchFoldingTest extends GraalCompilerTest {
private static final String REFERENCE_SNIPPET = "referenceSnippet";
private static final String REFERENCE_SNIPPET_2 = "reference2Snippet";
private static final String REFERENCE_SNIPPET_3 = "reference3Snippet";
private static final String REFERENCE_SNIPPET_4 = "reference4Snippet";
private static final String REFERENCE_SNIPPET_5 = "reference5Snippet";
public static int referenceSnippet(int a) {
switch (a) {
case 0:
return 10;
case 1:
return 5;
case 2:
return 3;
case 3:
return 11;
case 4:
return 14;
case 5:
return 2;
case 6:
return 1;
case 7:
return 0;
case 8:
return 7;
default:
return 6;
}
}
public static int reference2Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
case 2:
return 1;
case 3:
return 6;
default:
return 7;
}
}
public static int reference3Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
case 2:
case 4:
return 6;
case 6:
case 7:
default:
return 7;
}
}
public static int test1Snippet(int a) {
if (a == 0) {
return 10;
} else if (a == 1) {
return 5;
} else if (a == 2) {
return 3;
} else if (a == 3) {
return 11;
} else if (a == 4) {
return 14;
} else if (a == 5) {
return 2;
} else if (a == 6) {
return 1;
} else if (a == 7) {
return 0;
} else if (a == 8) {
return 7;
} else {
return 6;
}
}
@Test
public void test1() {
test1("test1Snippet");
}
public static int test2Snippet(int a) {
switch (a) {
case 0:
return 10;
case 1:
return 5;
case 2:
return 3;
case 3:
return 11;
case 4:
return 14;
default:
switch (a) {
case 5:
return 2;
case 6:
return 1;
case 7:
return 0;
case 8:
return 7;
default:
return 6;
}
}
}
@Test
public void test2() {
test1("test2Snippet");
}
public static int test3Snippet(int a) {
switch (a) {
case 0:
return 10;
default:
switch (a) {
case 1:
return 5;
default:
switch (a) {
case 2:
return 3;
default:
switch (a) {
case 3:
return 11;
default:
switch (a) {
case 4:
return 14;
default:
switch (a) {
case 5:
return 2;
default:
switch (a) {
case 6:
return 1;
default:
switch (a) {
case 7:
return 0;
default:
switch (a) {
case 8:
return 7;
default:
return 6;
}
}
}
}
}
}
}
}
}
}
@Test
public void test3() {
test1("test3Snippet");
}
public static int test4Snippet(int a) {
switch (a) {
case 0:
return 10;
case 1:
return 5;
case 2:
return 3;
case 3:
return 11;
case 4:
return 14;
case 5:
return 2;
case 6:
return 1;
default:
if (a == 7) {
return 0;
} else if (a == 8) {
return 7;
} else {
return 6;
}
}
}
@Test
public void test4() {
test1("test4Snippet");
}
public static int test5Snippet(int a) {
switch (a) {
case 0:
return 10;
default:
switch (a) {
case 1:
return 5;
default:
switch (a) {
case 2:
return 3;
default:
switch (a) {
case 3:
return 11;
default:
switch (a) {
case 4:
return 14;
default:
switch (a) {
case 5:
return 2;
default:
switch (a) {
case 6:
return 1;
default:
if (a == 7) {
return 0;
} else if (a == 8) {
return 7;
} else {
return 6;
}
}
}
}
}
}
}
}
}
@Test
public void test5() {
test1("test5Snippet");
}
public static int test6Snippet(int a) {
if (a == 0) {
return 10;
} else {
switch (a) {
case 1:
return 5;
default:
if (a == 2) {
return 3;
} else if (a == 3) {
return 11;
} else {
switch (a) {
case 4:
return 14;
case 5:
return 2;
case 6:
return 1;
default:
if (a == 7) {
return 0;
} else if (a == 8) {
return 7;
} else {
return 6;
}
}
}
}
}
}
@Test
public void test6() {
test1("test6Snippet");
}
public static int test7Snippet(int a) {
if (a == 0) {
return 4;
} else {
switch (a) {
case 1:
case 2:
return 1;
case 3:
return 6;
default:
return 7;
}
}
}
@Test
public void test7() {
test2("test7Snippet");
}
public static int test8Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
case 2:
case 7:
default:
switch (a) {
case 2:
case 6:
default:
switch (a) {
case 1:
case 2:
case 4:
return 6;
default:
return 7;
}
}
}
}
@Test
public void test8() {
test3("test8Snippet");
}
public static int reference4Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
case 2:
case 4:
return 6;
case 6:
return 7;
case 7:
return 7;
default:
return 7;
}
}
public static int test9Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
case 2:
case 4:
return 6;
case 6:
case 7:
default:
if (a == 6) {
return 7;
} else if (a == 7) {
return 7;
} else {
return 7;
}
}
}
@Test
public void test9() {
test4("test9Snippet");
}
public static int reference5Snippet(int a) {
switch (a) {
case 0:
return 4;
case 1:
return 1;
case 2:
return 1;
case 3:
return 6;
default:
return 7;
}
}
public static int test10Snippet(int a) {
if (a == 0) {
return 4;
} else {
if (a == 1 || a == 2) {
return 1;
} else {
switch (a) {
case 3:
return 6;
default:
return 7;
}
}
}
}
@Test
public void test10() {
test5("test10Snippet");
}
private void test1(String snippet) {
test(snippet, REFERENCE_SNIPPET);
}
private void test2(String snippet) {
test(snippet, REFERENCE_SNIPPET_2);
}
private void test3(String snippet) {
test(snippet, REFERENCE_SNIPPET_3);
}
private void test4(String snippet) {
test(snippet, REFERENCE_SNIPPET_4);
}
private void test5(String snippet) {
test(snippet, REFERENCE_SNIPPET_5);
}
private void test(String snippet, String ref) {
StructuredGraph graph = parseEager(snippet, StructuredGraph.AllowAssumptions.YES);
DebugContext debug = graph.getDebug();
debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
new CanonicalizerPhase().apply(graph, getProviders());
StructuredGraph referenceGraph = parseEager(ref, StructuredGraph.AllowAssumptions.YES);
assertEquals(referenceGraph, graph);
}
}

@ -45,10 +45,10 @@ public abstract class BackendTest extends GraalCompilerTest {
}
@SuppressWarnings("try")
protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph, OptimisticOptimizations optimizations) {
DebugContext debug = graph.getDebug();
try (DebugContext.Scope s = debug.scope("FrontEnd")) {
GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE, graph.getProfilingInfo(), createSuites(graph.getOptions()));
GraalCompiler.emitFrontEnd(getProviders(), getBackend(), graph, getDefaultGraphBuilderSuite(), optimizations, graph.getProfilingInfo(), createSuites(graph.getOptions()));
} catch (Throwable e) {
throw debug.handle(e);
}
@ -57,4 +57,7 @@ public abstract class BackendTest extends GraalCompilerTest {
return lirGen;
}
protected LIRGenerationResult getLIRGenerationResult(final StructuredGraph graph) {
return getLIRGenerationResult(graph, OptimisticOptimizations.NONE);
}
}

@ -302,10 +302,16 @@ public abstract class CompilationWrapper<T> {
}
}
/**
* Calls {@link System#exit(int)} in the runtime embedding the Graal compiler. This will be a
* different runtime than Graal's runtime in the case of libgraal.
*/
protected abstract void exitHostVM(int status);
private void maybeExitVM(ExceptionAction action) {
if (action == ExitVM) {
TTY.println("Exiting VM after retry compilation of " + this);
System.exit(-1);
exitHostVM(-1);
}
}

@ -156,10 +156,6 @@ public class DebugInfoBuilder {
}
assert checkValues(vobjValue.getType(), values, slotKinds);
vobjValue.setValues(values, slotKinds);
if (vobjNode instanceof VirtualBoxingNode) {
GraalServices.markVirtualObjectAsAutoBox(vobjValue);
}
}
virtualObjectsArray = new VirtualObject[virtualObjects.size()];
@ -323,7 +319,8 @@ public class DebugInfoBuilder {
assert obj.entryCount() == 0 || state instanceof VirtualObjectState;
VirtualObject vobject = virtualObjects.get(obj);
if (vobject == null) {
vobject = VirtualObject.get(obj.type(), virtualObjects.size());
boolean isAutoBox = obj instanceof VirtualBoxingNode;
vobject = GraalServices.createVirtualObject(obj.type(), virtualObjects.size(), isAutoBox);
virtualObjects.put(obj, vobject);
pendingVirtualObjects.add(obj);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2019, 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

@ -257,7 +257,6 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
* @throws BailoutException if the code installation failed
*/
public InstalledCode createDefaultInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationResult compilationResult) {
System.out.println(compilationResult.getSpeculationLog());
return createInstalledCode(debug, method, compilationResult, null, true);
}

@ -818,22 +818,24 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
private void replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
if (filter == null) {
fail("filter cannot be null");
throw fail("filter cannot be null");
}
checkReplaceWith(other);
int i = 0;
while (i < this.getUsageCount()) {
int usageCount = this.getUsageCount();
while (i < usageCount) {
Node usage = this.getUsageAt(i);
if (filter.test(usage)) {
replaceAtUsage(other, toBeDeleted, usage);
this.movUsageFromEndTo(i);
usageCount--;
} else {
++i;
}
}
}
public Node getUsageAt(int index) {
private Node getUsageAt(int index) {
if (index == 0) {
return this.usage0;
} else if (index == 1) {
@ -848,14 +850,35 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
replaceAtMatchingUsages(other, usagePredicate, null);
}
private void replaceAtUsagePos(Node other, Node usage, Position pos) {
pos.initialize(usage, other);
maybeNotifyInputChanged(usage);
if (other != null) {
other.addUsage(usage);
}
}
public void replaceAtUsages(InputType type, Node other) {
checkReplaceWith(other);
for (Node usage : usages().snapshot()) {
int i = 0;
int usageCount = this.getUsageCount();
if (usageCount == 0) {
return;
}
usages: while (i < usageCount) {
Node usage = this.getUsageAt(i);
for (Position pos : usage.inputPositions()) {
if (pos.getInputType() == type && pos.get(usage) == this) {
pos.set(usage, other);
replaceAtUsagePos(other, usage, pos);
this.movUsageFromEndTo(i);
usageCount--;
continue usages;
}
}
i++;
}
if (hasNoUsages()) {
maybeNotifyZeroUsages(this);
}
}
@ -913,6 +936,14 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
}
}
public void replaceFirstInput(Node oldInput, Node newInput, InputType type) {
for (Position pos : inputPositions()) {
if (pos.getInputType() == type && pos.get(this) == oldInput) {
pos.set(this, newInput);
}
}
}
public void clearInputs() {
assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
getNodeClass().unregisterAtInputsAsUsage(this);
@ -1059,6 +1090,8 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
assertFalse(input.isDeleted(), "input was deleted %s", input);
assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph");
assertTrue(pos.getInputType() == InputType.Unchecked || input.isAllowedUsageType(pos.getInputType()), "invalid usage type %s %s", input, pos.getInputType());
Class<?> expectedType = pos.getType();
assertTrue(expectedType.isAssignableFrom(input.getClass()), "Invalid input type for %s: expected a %s but was a %s", pos, expectedType, input.getClass());
}
}
return true;

@ -126,7 +126,7 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
field.setAccessible(true);
return (NodeClass<T>) field.get(null);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
throw new RuntimeException("Could not load Graal NodeClass TYPE field for " + clazz, e);
}
}

@ -127,6 +127,7 @@ public class NodeMap<T> extends NodeIdAccessor implements EconomicMap<Node, T> {
private boolean check(Node node) {
assert node.graph() == graph : String.format("%s is not part of the graph", node);
assert !isNew(node) : "this node was added to the graph after creating the node map : " + node;
assert node.isAlive() : "this node is not alive: " + node;
return true;
}

@ -146,4 +146,12 @@ public final class Position {
public int getIndex() {
return index;
}
public Class<?> getType() {
if (index < edges.getDirectCount()) {
return edges.getType(index);
} else {
return Node.class;
}
}
}

@ -49,6 +49,7 @@ import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.gen.LIRGenerationProvider;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@ -72,12 +73,16 @@ import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess;
import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CompilationRequest;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterConfig;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
@ -85,6 +90,8 @@ import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import sun.misc.Unsafe;
/**
* HotSpot AArch64 specific backend.
*/
@ -126,6 +133,46 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
}
}
@Override
public InstalledCode createInstalledCode(DebugContext debug,
ResolvedJavaMethod method,
CompilationRequest compilationRequest,
CompilationResult compilationResult,
InstalledCode predefinedInstalledCode,
boolean isDefault,
Object[] context) {
boolean isStub = (method == null);
boolean isAOT = compilationResult.isImmutablePIC();
if (!isStub && !isAOT) {
// Non-stub compilation results are installed into HotSpot as nmethods. As AArch64 has
// a constraint that the instruction at nmethod verified entry point should be a nop or
// jump, AArch64HotSpotBackend always generate a nop placeholder before the code body
// for non-AOT compilations. See AArch64HotSpotBackend.emitInvalidatePlaceholder(). This
// assert checks if the nop placeholder is generated at all required places, including
// in manually assembled code in CodeGenTest cases.
assert hasInvalidatePlaceholder(compilationResult);
}
return super.createInstalledCode(debug, method, compilationRequest, compilationResult, predefinedInstalledCode, isDefault, context);
}
private boolean hasInvalidatePlaceholder(CompilationResult compilationResult) {
byte[] targetCode = compilationResult.getTargetCode();
int verifiedEntryOffset = 0;
for (Mark mark : compilationResult.getMarks()) {
Object markId = mark.id;
if (markId instanceof Integer && (int) markId == config.MARKID_VERIFIED_ENTRY) {
// The nmethod verified entry is located at some pc offset.
verifiedEntryOffset = mark.pcOffset;
break;
}
}
Unsafe unsafe = GraalUnsafeAccess.getUnsafe();
int instruction = unsafe.getIntVolatile(targetCode, unsafe.arrayBaseOffset(byte[].class) + verifiedEntryOffset);
AArch64MacroAssembler masm = new AArch64MacroAssembler(getTarget());
masm.nop();
return instruction == masm.getInt(0);
}
private class HotSpotFrameContext implements FrameContext {
final boolean isStub;

@ -29,6 +29,7 @@ import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.common.InitTimer.timer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.graalvm.compiler.bytecode.BytecodeProvider;
@ -193,7 +194,7 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
protected HotSpotSuitesProvider createSuites(GraalHotSpotVMConfig config, HotSpotGraalRuntimeProvider runtime, CompilerConfiguration compilerConfiguration, Plugins plugins,
@SuppressWarnings("unused") Replacements replacements) {
AArch64SuitesCreator suitesCreator = new AArch64SuitesCreator(compilerConfiguration, plugins, SchedulePhase.class);
AArch64SuitesCreator suitesCreator = new AArch64SuitesCreator(compilerConfiguration, plugins, Arrays.asList(SchedulePhase.class));
Phase addressLoweringPhase = new AddressLoweringByUsePhase(new AArch64AddressLoweringByUse(new AArch64LIRKindTool()));
return new AddressLoweringHotSpotSuitesProvider(suitesCreator, config, runtime, addressLoweringPhase);
}

@ -25,6 +25,7 @@
package org.graalvm.compiler.hotspot.aarch64;
import org.graalvm.compiler.core.aarch64.AArch64LoweringProviderMixin;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node;
@ -45,7 +46,7 @@ import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
public class AArch64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
public class AArch64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements AArch64LoweringProviderMixin {
private AArch64IntegerArithmeticSnippets integerArithmeticSnippets;
private AArch64FloatArithmeticSnippets floatArithmeticSnippets;

@ -27,6 +27,7 @@ package org.graalvm.compiler.hotspot.amd64;
import static org.graalvm.compiler.hotspot.HotSpotBackend.Options.GraalArithmeticStubs;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.core.amd64.AMD64LoweringProviderMixin;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node;
@ -53,7 +54,7 @@ import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements AMD64LoweringProviderMixin {
private AMD64ConvertSnippets.Templates convertSnippets;
private ProbabilisticProfileSnippets.Templates profileSnippets;
@ -135,14 +136,4 @@ public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider
ForeignCallNode call = graph.add(new ForeignCallNode(foreignCalls, dispatchNode.getStubCallDescriptor(), dispatchNode.getStubCallArgs()));
graph.replaceFixed(dispatchNode, call);
}
@Override
public Integer smallestCompareWidth() {
return 8;
}
@Override
public boolean supportBulkZeroing() {
return true;
}
}

@ -34,7 +34,7 @@ import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.ValueUtil;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotConstant;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.Value;
@ -58,8 +58,8 @@ final class AMD64HotSpotStrategySwitchOp extends AMD64ControlFlow.StrategySwitch
@Override
protected void emitComparison(Constant c) {
if (c instanceof HotSpotMetaspaceConstant) {
HotSpotMetaspaceConstant meta = (HotSpotMetaspaceConstant) c;
if (c instanceof HotSpotConstant) {
HotSpotConstant meta = (HotSpotConstant) c;
if (meta.isCompressed()) {
crb.recordInlineDataInCode(meta);
masm.cmpl(keyRegister, 0xDEADDEAD);

@ -28,6 +28,7 @@ import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@ -100,7 +101,7 @@ public class BenchmarkCounterOverflowTest extends LIRTest {
}
@Test
public void spawnSubprocess() throws Throwable {
public void spawnSubprocess() throws IOException, InterruptedException {
Assume.assumeFalse("subprocess already spawned -> skip", Boolean.getBoolean(SUBPROCESS_PROPERTY));
List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
vmArgs.add("-XX:JVMCICounterSize=1");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2019, 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
@ -120,7 +120,7 @@ public class ExceedMaxOopMapStackOffset extends LIRTest {
}
@Test
public void runStackObjects() throws Throwable {
public void runStackObjects() {
int max = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().maxOopMapStackOffset;
if (max == Integer.MAX_VALUE) {
max = 16 * 1024 - 64;

@ -153,7 +153,7 @@ public class MitigateExceedingMaxOopMapStackOffsetTest extends LIRTest {
}
@Test
public void runStackObjects() throws Throwable {
public void runStackObjects() {
int max = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig().maxOopMapStackOffset;
Assume.assumeFalse("no limit on oop map size", max == Integer.MAX_VALUE);
numPrimitiveSlots = (max / 8) * 2;

@ -25,6 +25,7 @@
package org.graalvm.compiler.hotspot.sparc;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.core.sparc.SparcLoweringProviderMixin;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
@ -36,7 +37,7 @@ import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider {
public class SPARCHotSpotLoweringProvider extends DefaultHotSpotLoweringProvider implements SparcLoweringProviderMixin {
public SPARCHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {

@ -24,85 +24,97 @@
package org.graalvm.compiler.hotspot.test;
import static org.graalvm.compiler.serviceprovider.JavaVersionUtil.JAVA_SPEC;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
public class BoxDeoptimizationTest extends GraalCompilerTest {
private static boolean isJDK13OrLater = JavaVersionUtil.JAVA_SPEC >= 13;
public static void testInteger() {
Object[] values = {42, new Exception()};
private static void checkJDK() {
Assume.assumeTrue(JAVA_SPEC == 8 || JAVA_SPEC >= 13);
}
public static void testIntegerSnippet() {
Object[] values = {42, -42, new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Integer.valueOf(42));
Assert.assertSame(values[1], Integer.valueOf(-42));
}
@Test
public void test1() {
Assume.assumeTrue(isJDK13OrLater);
test("testInteger");
public void testInteger() {
checkJDK();
test("testIntegerSnippet");
}
public static void testLong() {
Object[] values = {42L, new Exception()};
public static void testLongSnippet() {
long highBitsOnly = 2L << 40;
Object[] values = {42L, -42L, highBitsOnly, new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Long.valueOf(42));
Assert.assertSame(values[1], Long.valueOf(-42));
Assert.assertNotSame(values[2], highBitsOnly);
}
@Test
public void test2() {
Assume.assumeTrue(isJDK13OrLater);
test("testLong");
public void testLong() {
checkJDK();
test("testLongSnippet");
}
public static void testChar() {
Object[] values = {'a', new Exception()};
public static void testCharSnippet() {
Object[] values = {'a', 'Z', new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Character.valueOf('a'));
Assert.assertSame(values[1], Character.valueOf('Z'));
}
@Test
public void test3() {
Assume.assumeTrue(isJDK13OrLater);
test("testChar");
public void testChar() {
checkJDK();
test("testCharSnippet");
}
public static void testShort() {
Object[] values = {(short) 42, new Exception()};
public static void testShortSnippet() {
Object[] values = {(short) 42, (short) -42, new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Short.valueOf((short) 42));
Assert.assertSame(values[1], Short.valueOf((short) -42));
}
@Test
public void test4() {
Assume.assumeTrue(isJDK13OrLater);
test("testShort");
public void testShort() {
checkJDK();
test("testShortSnippet");
}
public static void testByte() {
Object[] values = {(byte) 42, new Exception()};
public static void testByteSnippet() {
Object[] values = {(byte) 42, (byte) -42, new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Byte.valueOf((byte) 42));
Assert.assertSame(values[1], Byte.valueOf((byte) -42));
}
@Test
public void test5() {
Assume.assumeTrue(isJDK13OrLater);
test("testByte");
public void testByte() {
checkJDK();
test("testByteSnippet");
}
public static void testBoolean() {
Object[] values = {true, new Exception()};
public static void testBooleanSnippet() {
Object[] values = {true, false, new Exception()};
GraalDirectives.deoptimize();
Assert.assertSame(values[0], Boolean.valueOf(true));
Assert.assertSame(values[1], Boolean.valueOf(false));
}
@Test
public void test6() {
Assume.assumeTrue(isJDK13OrLater);
test("testBoolean");
public void testBoolean() {
checkJDK();
test("testBooleanSnippet");
}
}

@ -24,6 +24,9 @@
package org.graalvm.compiler.hotspot.test;
import static org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.aesDecryptName;
import static org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins.aesEncryptName;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@ -41,6 +44,7 @@ import jdk.internal.vm.compiler.collections.MapCursor;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
@ -501,21 +505,17 @@ public class CheckGraalIntrinsics extends GraalTest {
"java/util/zip/CRC32C.updateDirectByteBuffer(IJII)I");
}
boolean implNames = HotSpotGraphBuilderPlugins.cbcUsesImplNames(config);
String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
// AES intrinsics
if (!config.useAESIntrinsics) {
if (isJDK9OrHigher()) {
add(ignore,
"com/sun/crypto/provider/AESCrypt.implDecryptBlock([BI[BI)V",
"com/sun/crypto/provider/AESCrypt.implEncryptBlock([BI[BI)V",
"com/sun/crypto/provider/CipherBlockChaining.implDecrypt([BII[BI)I",
"com/sun/crypto/provider/CipherBlockChaining.implEncrypt([BII[BI)I");
} else {
add(ignore,
"com/sun/crypto/provider/AESCrypt.decryptBlock([BI[BI)V",
"com/sun/crypto/provider/AESCrypt.encryptBlock([BI[BI)V",
"com/sun/crypto/provider/CipherBlockChaining.decrypt([BII[BI)I",
"com/sun/crypto/provider/CipherBlockChaining.encrypt([BII[BI)I");
}
add(ignore,
"com/sun/crypto/provider/AESCrypt." + aesDecryptName + "([BI[BI)V",
"com/sun/crypto/provider/AESCrypt." + aesEncryptName + "([BI[BI)V",
"com/sun/crypto/provider/CipherBlockChaining." + cbcDecryptName + "([BII[BI)I",
"com/sun/crypto/provider/CipherBlockChaining." + cbcEncryptName + "([BII[BI)I");
}
// BigInteger intrinsics

@ -29,6 +29,7 @@ import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -209,10 +210,9 @@ public class CompilationWrapperTest extends GraalCompilerTest {
System.out.println(proc);
}
List<Probe> probes = new ArrayList<>(initialProbes);
Probe diagnosticProbe = null;
if (!extraVmArgs.contains("-Dgraal.TruffleCompilationExceptionsAreFatal=true")) {
diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
try {
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
@ -220,22 +220,20 @@ public class CompilationWrapperTest extends GraalCompilerTest {
return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
}
});
}
for (String line : proc.output) {
for (Probe probe : probes) {
if (probe.matches(line)) {
break;
for (String line : proc.output) {
for (Probe probe : probes) {
if (probe.matches(line)) {
break;
}
}
}
}
for (Probe probe : probes) {
String error = probe.test();
if (error != null) {
Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
for (Probe probe : probes) {
String error = probe.test();
if (error != null) {
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();
@ -263,8 +261,10 @@ public class CompilationWrapperTest extends GraalCompilerTest {
}
} finally {
zip.delete();
dumpPath.delete();
}
} finally {
Path directory = dumpPath.toPath();
removeDirectory(directory);
}
}
}

@ -313,8 +313,8 @@ public class CompressedOopTest extends GraalCompilerTest {
Assert.assertTrue(buffer.length() == 28);
String a = new String("TestTestTestTestTestTestTest");
installedBenchmarkCode.executeVarargs(buffer, a.toCharArray());
Assert.assertTrue(buffer.length() == 56);
Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
Assert.assertEquals(56, buffer.length());
Assert.assertEquals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest", buffer.toString());
}
public static void stringBuilderTest(Object c1, Object c2) {
@ -339,8 +339,8 @@ public class CompressedOopTest extends GraalCompilerTest {
for (int i = 0; i < add.length; i++) {
buffer.append(add[i]);
}
Assert.assertTrue(buffer.length() == 56);
Assert.assertTrue(buffer.toString().equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
Assert.assertEquals(56, buffer.length());
Assert.assertEquals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest", buffer.toString());
}
@Test
@ -356,8 +356,8 @@ public class CompressedOopTest extends GraalCompilerTest {
char[] dst = new char[buffer.length() * 2];
System.arraycopy(buffer.toString().toCharArray(), 0, dst, 0, buffer.length());
System.arraycopy(a.toCharArray(), 0, dst, buffer.length(), buffer.length());
Assert.assertTrue(dst.length == 56);
Assert.assertTrue(new String(dst).equals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest"));
Assert.assertEquals(56, dst.length);
Assert.assertEquals("TestTestTestTestTestTestTestTestTestTestTestTestTestTest", new String(dst));
}
@Test

@ -35,12 +35,11 @@ import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@ -91,7 +90,10 @@ public class HotSpotCryptoSubstitutionTest extends HotSpotGraalCompilerTest {
@Test
public void testCipherBlockChainingIntrinsics() throws Exception {
if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", HotSpotGraphBuilderPlugins.cbcEncryptName, HotSpotGraphBuilderPlugins.cbcDecryptName)) {
boolean implNames = HotSpotGraphBuilderPlugins.cbcUsesImplNames(runtime().getVMConfig());
String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
if (compileAndInstall("com.sun.crypto.provider.CipherBlockChaining", cbcEncryptName, cbcDecryptName)) {
ByteArrayOutputStream actual = new ByteArrayOutputStream();
actual.write(runEncryptDecrypt(aesKey, "AES/CBC/NoPadding"));
actual.write(runEncryptDecrypt(aesKey, "AES/CBC/PKCS5Padding"));

@ -378,12 +378,15 @@ public class HotSpotGraalManagementTest {
MBeanAttributeInfo dumpPath = findAttributeInfo("DumpPath", info);
MBeanAttributeInfo printGraphFile = findAttributeInfo("PrintGraphFile", info);
MBeanAttributeInfo showDumpFiles = findAttributeInfo("ShowDumpFiles", info);
MBeanAttributeInfo methodFilter = findAttributeInfo("MethodFilter", info);
Object originalDumpPath = server.getAttribute(mbeanName, dumpPath.getName());
Object originalPrintGraphFile = server.getAttribute(mbeanName, printGraphFile.getName());
Object originalShowDumpFiles = server.getAttribute(mbeanName, showDumpFiles.getName());
Object originalMethodFilter = server.getAttribute(mbeanName, methodFilter.getName());
final File tmpDir = new File(HotSpotGraalManagementTest.class.getSimpleName() + "_" + System.currentTimeMillis()).getAbsoluteFile();
server.setAttribute(mbeanName, new Attribute(dumpPath.getName(), quoted(tmpDir)));
server.setAttribute(mbeanName, new Attribute(methodFilter.getName(), ""));
// Force output to a file even if there's a running IGV instance available.
server.setAttribute(mbeanName, new Attribute(printGraphFile.getName(), true));
server.setAttribute(mbeanName, new Attribute(showDumpFiles.getName(), false));
@ -392,6 +395,7 @@ public class HotSpotGraalManagementTest {
server.invoke(mbeanName, "dumpMethod", params, null);
boolean found = false;
String expectedIgvDumpSuffix = "[Arrays.asList(Object[])List].bgv";
Assert.assertTrue(tmpDir.toString() + " was not created or is not a directory", tmpDir.isDirectory());
List<String> dumpPathEntries = Arrays.asList(tmpDir.list());
for (String entry : dumpPathEntries) {
if (entry.endsWith(expectedIgvDumpSuffix)) {
@ -403,8 +407,11 @@ public class HotSpotGraalManagementTest {
dumpPathEntries.stream().collect(Collectors.joining(System.lineSeparator()))));
}
} finally {
deleteDirectory(tmpDir.toPath());
if (tmpDir.isDirectory()) {
deleteDirectory(tmpDir.toPath());
}
server.setAttribute(mbeanName, new Attribute(dumpPath.getName(), originalDumpPath));
server.setAttribute(mbeanName, new Attribute(methodFilter.getName(), originalMethodFilter));
server.setAttribute(mbeanName, new Attribute(printGraphFile.getName(), originalPrintGraphFile));
server.setAttribute(mbeanName, new Attribute(showDumpFiles.getName(), originalShowDumpFiles));
}

@ -27,9 +27,13 @@ package org.graalvm.compiler.hotspot.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.hotspot.JVMCIVersionCheck;
import org.graalvm.compiler.hotspot.JVMCIVersionCheck.Version;
import org.graalvm.compiler.hotspot.JVMCIVersionCheck.Version2;
import org.graalvm.compiler.hotspot.JVMCIVersionCheck.Version3;
import org.junit.Assert;
import org.junit.Test;
@ -43,24 +47,37 @@ public class JVMCIVersionCheckTest extends GraalCompilerTest {
props.put(name, sprops.getProperty(name));
}
for (int i = 0; i < 100; i++) {
int minMajor = i;
int minMinor = 100 - i;
for (int j = 0; j < 100; j++) {
int major = j;
int minor = 100 - j;
long seed = Long.getLong("test.seed", System.nanoTime());
Random random = new Random(seed);
boolean ok = (major > minMajor) || (major == minMajor && minor >= minMinor);
for (String sep : new String[]{".", "-b"}) {
String javaVmVersion = String.format("prefix-jvmci-%03d%s%03d-suffix", major, sep, minor);
if (ok) {
JVMCIVersionCheck.check(props, minMajor, minMinor, "1.8", javaVmVersion, false);
} else {
try {
JVMCIVersionCheck.check(props, minMajor, minMinor, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against " + minMajor + "." + minMinor);
} catch (InternalError e) {
// pass
for (int i = 0; i < 50; i++) {
int minMajor = i;
int minMinor = 50 - i;
for (int j = 0; j < 50; j++) {
int major = j;
int minor = 50 - j;
for (int k = 0; k < 30; k++) {
int minBuild = random.nextInt(100);
int build = random.nextInt(100);
for (Version version : new Version[]{new Version2(major, minor), new Version3(major, minor, build)}) {
for (Version minVersion : new Version[]{new Version2(minMajor, minMinor), new Version3(minMajor, minMinor, minBuild)}) {
String javaVmVersion = String.format("prefix-jvmci-%s-suffix", version);
if (!version.isLessThan(minVersion)) {
try {
JVMCIVersionCheck.check(props, minVersion, "1.8", javaVmVersion, false);
} catch (InternalError e) {
throw new AssertionError("Failed " + JVMCIVersionCheckTest.class.getSimpleName() + " with -Dtest.seed=" + seed, e);
}
} else {
try {
JVMCIVersionCheck.check(props, minVersion, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against " + minVersion + " (-Dtest.seed=" + seed + ")");
} catch (InternalError e) {
// pass
}
}
}
}
}
@ -72,8 +89,9 @@ public class JVMCIVersionCheckTest extends GraalCompilerTest {
for (String version : new String[]{"0" + sep + Long.MAX_VALUE, Long.MAX_VALUE + sep + 0}) {
String javaVmVersion = String.format("prefix-jvmci-%s-suffix", version);
try {
JVMCIVersionCheck.check(props, 0, 59, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against 0.59");
Version2 minVersion = new Version2(0, 59);
JVMCIVersionCheck.check(props, minVersion, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against " + minVersion);
} catch (InternalError e) {
// pass
}

@ -0,0 +1,69 @@
/*
* Copyright (c) 2019, 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;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.meta.JavaConstant;
/**
* A context for scoping the lifetime of foreign objects.
*
* The need for this mechanism is best explained with an example. When folding a GETFIELD bytecode
* denoting a {@code final static} non-primitive field, libgraal can create a {@link JavaConstant}
* wrapping a handle to the field's value in the HotSpot heap. This handle must be released before
* HotSpot can reclaim the object it references. Performing a compilation in the scope of a
* {@linkplain HotSpotGraalServices#openLocalCompilationContext local} context ensures the handle is
* released once the compilation completes, allowing the HotSpot GC to subsequently reclaim the
* HotSpot object. When libgraal creates data structures that outlive a single compilation and may
* contain foreign object references (e.g. snippet graphs), it must enter the
* {@linkplain HotSpotGraalServices#enterGlobalCompilationContext global} context. Foreign object
* handles created in the global context are only released once their {@link JavaConstant} wrappers
* are reclaimed by the libgraal GC.
*
* {@link CompilationContext}s have no impact on {@link JavaConstant}s that do not encapsulate a
* foreign object reference.
*
* The object returned by {@link HotSpotGraalServices#enterGlobalCompilationContext} or
* {@link HotSpotGraalServices#openLocalCompilationContext} should be used in a try-with-resources
* statement. Failure to close a context will almost certainly result in foreign objects being
* leaked.
*/
public class CompilationContext implements AutoCloseable {
private final AutoCloseable impl;
CompilationContext(AutoCloseable impl) {
this.impl = impl;
}
@Override
public void close() {
try {
impl.close();
} catch (Exception e) {
GraalError.shouldNotReachHere(e);
}
}
}

@ -26,6 +26,7 @@ package org.graalvm.compiler.hotspot;
import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.fmt;
import static org.graalvm.compiler.hotspot.HotSpotGraalCompiler.str;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
@ -35,9 +36,10 @@ import java.util.TreeSet;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.options.OptionKey;
import jdk.vm.ci.code.CompilationRequest;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@ -85,7 +87,7 @@ class CompilationCounters {
}
}
TTY.flush();
System.exit(-1);
HotSpotGraalServices.exit(-1);
}
}

@ -96,9 +96,14 @@ public class CompilationTask {
return DebugContext.create(retryOptions, description, initialDebug.getGlobalMetrics(), logStream, factories);
}
@Override
protected void exitHostVM(int status) {
HotSpotGraalServices.exit(status);
}
@Override
public String toString() {
return getMethod().format("%H.%n(%p)");
return getMethod().format("%H.%n(%p) @ " + getEntryBCI());
}
@Override

@ -238,7 +238,7 @@ class CompilationWatchDog implements Runnable, AutoCloseable {
TTY.printf("======================= WATCH DOG THREAD =======================%n" +
"%s took %d identical stack traces, which indicates a stuck compilation (id=%d) of %s%n%sExiting VM%n", this,
numberOfIdenticalStackTraces, currentId, fmt(currentMethod), fmt(lastStackTrace));
System.exit(-1);
HotSpotGraalServices.exit(-1);
}
} else if (newStackTrace) {
synchronized (CompilationWatchDog.class) {

@ -200,7 +200,7 @@ public abstract class CompilerConfigurationFactory implements Comparable<Compile
for (CompilerConfigurationFactory candidate : getAllCandidates()) {
System.out.println(" " + candidate.name);
}
System.exit(0);
HotSpotGraalServices.exit(0);
} else if (value != null) {
for (CompilerConfigurationFactory candidate : GraalServices.load(CompilerConfigurationFactory.class)) {
if (candidate.name.equals(value)) {

@ -111,39 +111,41 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler, Cancellable {
@SuppressWarnings("try")
CompilationRequestResult compileMethod(CompilationRequest request, boolean installAsDefault, OptionValues initialOptions) {
if (graalRuntime.isShutdown()) {
return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), true);
}
ResolvedJavaMethod method = request.getMethod();
if (graalRuntime.isBootstrapping()) {
if (DebugOptions.BootstrapInitializeOnly.getValue(initialOptions)) {
return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", DebugOptions.BootstrapInitializeOnly.getName()), true);
try (CompilationContext scope = HotSpotGraalServices.openLocalCompilationContext(request)) {
if (graalRuntime.isShutdown()) {
return HotSpotCompilationRequestResult.failure(String.format("Shutdown entered"), true);
}
if (bootstrapWatchDog != null) {
if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) {
// Drain the compilation queue to expedite completion of the bootstrap
return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true);
ResolvedJavaMethod method = request.getMethod();
if (graalRuntime.isBootstrapping()) {
if (DebugOptions.BootstrapInitializeOnly.getValue(initialOptions)) {
return HotSpotCompilationRequestResult.failure(String.format("Skip compilation because %s is enabled", DebugOptions.BootstrapInitializeOnly.getName()), true);
}
if (bootstrapWatchDog != null) {
if (bootstrapWatchDog.hitCriticalCompilationRateOrTimeout()) {
// Drain the compilation queue to expedite completion of the bootstrap
return HotSpotCompilationRequestResult.failure("hit critical bootstrap compilation rate or timeout", true);
}
}
}
}
HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request;
CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, shouldRetainLocalVariables(hsRequest.getJvmciEnv()), installAsDefault);
OptionValues options = task.filterOptions(initialOptions);
try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId(), options);
BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request);
CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(options);) {
if (compilationCounters != null) {
compilationCounters.countCompilation(method);
HotSpotCompilationRequest hsRequest = (HotSpotCompilationRequest) request;
CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, shouldRetainLocalVariables(hsRequest.getJvmciEnv()), installAsDefault);
OptionValues options = task.filterOptions(initialOptions);
try (CompilationWatchDog w1 = CompilationWatchDog.watch(method, hsRequest.getId(), options);
BootstrapWatchDog.Watch w2 = bootstrapWatchDog == null ? null : bootstrapWatchDog.watch(request);
CompilationAlarm alarm = CompilationAlarm.trackCompilationPeriod(options);) {
if (compilationCounters != null) {
compilationCounters.countCompilation(method);
}
CompilationRequestResult r = null;
try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories(), DebugContext.DEFAULT_LOG_STREAM);
Activation a = debug.activate()) {
r = task.runCompilation(debug);
}
assert r != null;
return r;
}
CompilationRequestResult r = null;
try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories(), DebugContext.DEFAULT_LOG_STREAM);
Activation a = debug.activate()) {
r = task.runCompilation(debug);
}
assert r != null;
return r;
}
}

@ -26,6 +26,9 @@ package org.graalvm.compiler.hotspot;
import jdk.vm.ci.hotspot.HotSpotMetaData;
/**
* JDK 13 version of {@code HotSpotGraalServices}.
*/
public class HotSpotGraalServices {
/**
@ -35,4 +38,17 @@ public class HotSpotGraalServices {
public static byte[] getImplicitExceptionBytes(HotSpotMetaData metaData) {
return metaData.implicitExceptionBytes();
}
public static CompilationContext enterGlobalCompilationContext() {
return null;
}
@SuppressWarnings("unused")
public static CompilationContext openLocalCompilationContext(Object description) {
return null;
}
public static void exit(int status) {
System.exit(status);
}
}

@ -208,6 +208,7 @@ public class HotSpotReplacementsImpl extends ReplacementsImpl {
return super.getSnippet(method, recursiveEntry, args, trackNodeSourcePosition, replaceePosition, options);
}
@SuppressWarnings("try")
private StructuredGraph getEncodedSnippet(ResolvedJavaMethod method, Object[] args, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
@ -219,11 +220,15 @@ public class HotSpotReplacementsImpl extends ReplacementsImpl {
if (getEncodedSnippets() == null) {
throw GraalError.shouldNotReachHere("encoded snippets not found");
}
StructuredGraph graph = getEncodedSnippets().getEncodedSnippet(method, this, args, allowAssumptions, options);
if (graph == null) {
throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)"));
// Snippets graphs can contain foreign object reference and
// outlive a single compilation.
try (CompilationContext scope = HotSpotGraalServices.enterGlobalCompilationContext()) {
StructuredGraph graph = getEncodedSnippets().getEncodedSnippet(method, this, args, allowAssumptions, options);
if (graph == null) {
throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)"));
}
return graph;
}
return graph;
}
} else {
assert registeredSnippets == null || registeredSnippets.contains(method) : "Asking for snippet method that was never registered: " + method.format("%H.%n(%p)");

@ -42,6 +42,7 @@ import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.serviceprovider.GraalServices;
import org.graalvm.compiler.serviceprovider.ServiceProvider;
import jdk.vm.ci.common.NativeImageReinitialize;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.services.Services;
@ -96,7 +97,7 @@ public class HotSpotTTYStreamProvider implements TTYStreamProvider {
* initialization.
*/
class DelayedOutputStream extends OutputStream {
private volatile OutputStream lazy;
@NativeImageReinitialize private volatile OutputStream lazy;
private OutputStream lazy() {
if (lazy == null) {

@ -43,4 +43,3 @@ abstract class IsGraalPredicateBase {
return HotSpotJVMCICompilerFactory.CompilationLevelAdjustment.ByHolder;
}
}

@ -28,6 +28,8 @@ import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Mechanism for checking that the current Java runtime environment supports the minimum JVMCI API
@ -41,8 +43,107 @@ import java.util.Properties;
*/
public final class JVMCIVersionCheck {
private static final int JVMCI8_MIN_MAJOR_VERSION = 19;
private static final int JVMCI8_MIN_MINOR_VERSION = 1;
private static final Version JVMCI8_MIN_VERSION = new Version3(19, 2, 1);
public interface Version {
boolean isLessThan(Version other);
static Version parse(String vmVersion) {
Matcher m = Pattern.compile(".*-jvmci-(\\d+)\\.(\\d+)-b(\\d+).*").matcher(vmVersion);
if (m.matches()) {
try {
int major = Integer.parseInt(m.group(1));
int minor = Integer.parseInt(m.group(2));
int build = Integer.parseInt(m.group(3));
return new Version3(major, minor, build);
} catch (NumberFormatException e) {
// ignore
}
}
m = Pattern.compile(".*-jvmci-(\\d+)(?:\\.|-b)(\\d+).*").matcher(vmVersion);
if (m.matches()) {
try {
int major = Integer.parseInt(m.group(1));
int minor = Integer.parseInt(m.group(2));
return new Version2(major, minor);
} catch (NumberFormatException e) {
// ignore
}
}
return null;
}
}
public static class Version2 implements Version {
private final int major;
private final int minor;
public Version2(int major, int minor) {
this.major = major;
this.minor = minor;
}
@Override
public boolean isLessThan(Version other) {
if (other.getClass() == Version3.class) {
return true;
}
Version2 o = (Version2) other;
if (this.major < o.major) {
return true;
}
if (this.major == o.major && this.minor < o.minor) {
return true;
}
return false;
}
@Override
public String toString() {
if (major >= 19) {
return String.format("%d-b%02d", major, minor);
} else {
return String.format("%d.%d", major, minor);
}
}
}
public static class Version3 implements Version {
private final int major;
private final int minor;
private final int build;
public Version3(int major, int minor, int build) {
this.major = major;
this.minor = minor;
this.build = build;
}
@Override
public boolean isLessThan(Version other) {
if (other.getClass() == Version2.class) {
return false;
}
Version3 o = (Version3) other;
if (this.major < o.major) {
return true;
}
if (this.major == o.major) {
if (this.minor < o.minor) {
return true;
}
if (this.minor == o.minor && this.build < o.build) {
return true;
}
}
return false;
}
@Override
public String toString() {
return String.format("%d.%d-b%02d", major, minor, build);
}
}
private static void failVersionCheck(Map<String, String> props, boolean exit, String reason, Object... args) {
Formatter errorMessage = new Formatter().format(reason, args);
@ -53,9 +154,7 @@ public final class JVMCIVersionCheck {
errorMessage.format("Currently used Java home directory is %s.%n", javaHome);
errorMessage.format("Currently used VM configuration is: %s%n", vmName);
if (props.get("java.specification.version").compareTo("1.9") < 0) {
errorMessage.format("Download the latest JVMCI JDK 8 from " +
"https://www.oracle.com/technetwork/graalvm/downloads/index.html or " +
"https://github.com/graalvm/openjdk8-jvmci-builder/releases");
errorMessage.format("Download the latest JVMCI JDK 8 from https://github.com/graalvm/openjdk8-jvmci-builder/releases");
} else {
errorMessage.format("Download JDK 11 or later.");
}
@ -74,7 +173,6 @@ public final class JVMCIVersionCheck {
private final String javaSpecVersion;
private final String vmVersion;
private int cursor;
private final Map<String, String> props;
private JVMCIVersionCheck(Map<String, String> props, String javaSpecVersion, String vmVersion) {
@ -85,112 +183,28 @@ public final class JVMCIVersionCheck {
static void check(Map<String, String> props, boolean exitOnFailure) {
JVMCIVersionCheck checker = new JVMCIVersionCheck(props, props.get("java.specification.version"), props.get("java.vm.version"));
checker.run(exitOnFailure, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
checker.run(exitOnFailure, JVMCI8_MIN_VERSION);
}
/**
* Entry point for testing.
*/
public static void check(Map<String, String> props,
int jvmci8MinMajorVersion,
int jvmci8MinMinorVersion,
Version minVersion,
String javaSpecVersion,
String javaVmVersion,
boolean exitOnFailure) {
String javaVmVersion, boolean exitOnFailure) {
JVMCIVersionCheck checker = new JVMCIVersionCheck(props, javaSpecVersion, javaVmVersion);
checker.run(exitOnFailure, jvmci8MinMajorVersion, jvmci8MinMinorVersion);
checker.run(exitOnFailure, minVersion);
}
/**
* Parses a positive decimal number at {@link #cursor}.
*
* @return -1 if there is no positive decimal number at {@link #cursor}
*/
private int parseNumber() {
int result = -1;
while (cursor < vmVersion.length()) {
int digit = vmVersion.charAt(cursor) - '0';
if (digit >= 0 && digit <= 9) {
if (result == -1) {
result = digit;
} else {
long r = (long) result * (long) 10;
if ((int) r != r) {
// Overflow
return -1;
}
result = (int) r + digit;
}
cursor++;
} else {
break;
}
}
return result;
}
/**
* Parse {@code "."} or {@code "-b"} at {@link #cursor}.
*
* @return {@code true} iff there was an expected separator at {@link #cursor}
*/
private boolean parseSeparator() {
if (cursor < vmVersion.length()) {
char ch = vmVersion.charAt(cursor);
if (ch == '.') {
cursor++;
return true;
}
if (ch == '-') {
cursor++;
if (cursor < vmVersion.length()) {
if (vmVersion.charAt(cursor) == 'b') {
cursor++;
return true;
}
}
return false;
}
}
return false;
}
private static String getJVMCIVersionString(int major, int minor) {
if (major >= 19) {
return String.format("%d-b%02d", major, minor);
} else {
return String.format("%d.%d", major, minor);
}
}
private void run(boolean exitOnFailure, int jvmci8MinMajorVersion, int jvmci8MinMinorVersion) {
// Don't use regular expressions to minimize Graal startup time
private void run(boolean exitOnFailure, Version minVersion) {
if (javaSpecVersion.compareTo("1.9") < 0) {
cursor = vmVersion.indexOf("-jvmci-");
if (cursor >= 0) {
cursor += "-jvmci-".length();
int major = parseNumber();
if (major == -1) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI major version from java.vm.version property: %s.%n", vmVersion);
return;
}
if (parseSeparator()) {
int minor = parseNumber();
if (minor == -1) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI minor version from java.vm.version property: %s.%n", vmVersion);
return;
}
if (major > jvmci8MinMajorVersion || (major >= jvmci8MinMajorVersion && minor >= jvmci8MinMinorVersion)) {
return;
}
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %s < %s.%n",
getJVMCIVersionString(major, minor), getJVMCIVersionString(jvmci8MinMajorVersion, jvmci8MinMinorVersion));
return;
Version v = Version.parse(vmVersion);
if (v != null) {
if (v.isLessThan(minVersion)) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %s < %s.%n", v, minVersion);
}
return;
}
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI version from java.vm.version property: %s.%n", vmVersion);

@ -182,7 +182,7 @@ import jdk.vm.ci.meta.ResolvedJavaType;
/**
* HotSpot implementation of {@link LoweringProvider}.
*/
public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider {
public abstract class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider implements HotSpotLoweringProvider {
protected final HotSpotGraalRuntimeProvider runtime;
protected final HotSpotRegistersProvider registers;

@ -44,6 +44,7 @@ import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.TypeReference;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
@ -106,6 +107,7 @@ import org.graalvm.compiler.word.WordTypes;
import jdk.internal.vm.compiler.word.LocationIdentity;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.hotspot.VMIntrinsicMethod;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.JavaKind;
@ -429,8 +431,6 @@ public class HotSpotGraphBuilderPlugins {
r.registerMethodSubstitution(ThreadSubstitutions.class, "isInterrupted", Receiver.class, boolean.class);
}
public static final String cbcEncryptName;
public static final String cbcDecryptName;
public static final String aesEncryptName;
public static final String aesDecryptName;
@ -439,15 +439,11 @@ public class HotSpotGraphBuilderPlugins {
static {
if (JavaVersionUtil.JAVA_SPEC <= 8) {
cbcEncryptName = "encrypt";
cbcDecryptName = "decrypt";
aesEncryptName = "encryptBlock";
aesDecryptName = "decryptBlock";
reflectionClass = "sun.reflect.Reflection";
constantPoolClass = "sun.reflect.ConstantPool";
} else {
cbcEncryptName = "implEncrypt";
cbcDecryptName = "implDecrypt";
aesEncryptName = "implEncryptBlock";
aesDecryptName = "implDecryptBlock";
reflectionClass = "jdk.internal.reflect.Reflection";
@ -455,6 +451,19 @@ public class HotSpotGraphBuilderPlugins {
}
}
public static boolean cbcUsesImplNames(GraalHotSpotVMConfig config) {
for (VMIntrinsicMethod intrinsic : config.getStore().getIntrinsics()) {
if ("com/sun/crypto/provider/CipherBlockChaining".equals(intrinsic.declaringClass)) {
if ("encrypt".equals(intrinsic.name)) {
return false;
} else if ("implEncrypt".equals(intrinsic.name)) {
return true;
}
}
}
throw GraalError.shouldNotReachHere();
}
private static void registerAESPlugins(InvocationPlugins plugins, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
if (config.useAESIntrinsics) {
assert config.aescryptEncryptBlockStub != 0L;
@ -464,9 +473,15 @@ public class HotSpotGraphBuilderPlugins {
String arch = config.osArch;
String decryptSuffix = arch.equals("sparc") ? "WithOriginalKey" : "";
Registration r = new Registration(plugins, "com.sun.crypto.provider.CipherBlockChaining", bytecodeProvider);
boolean implNames = cbcUsesImplNames(config);
String cbcEncryptName = implNames ? "implEncrypt" : "encrypt";
String cbcDecryptName = implNames ? "implDecrypt" : "decrypt";
r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcEncryptName, Receiver.class, byte[].class, int.class, int.class, byte[].class, int.class);
r.registerMethodSubstitution(CipherBlockChainingSubstitutions.class, cbcDecryptName, cbcDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, int.class, byte[].class,
int.class);
r = new Registration(plugins, "com.sun.crypto.provider.AESCrypt", bytecodeProvider);
r.registerMethodSubstitution(AESCryptSubstitutions.class, aesEncryptName, Receiver.class, byte[].class, int.class, byte[].class, int.class);
r.registerMethodSubstitution(AESCryptSubstitutions.class, aesDecryptName, aesDecryptName + decryptSuffix, Receiver.class, byte[].class, int.class, byte[].class, int.class);

@ -244,4 +244,3 @@ public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
private static final LocationIdentity JAVA_THREAD_SHOULD_POST_ON_EXCEPTIONS_FLAG_LOCATION = NamedLocationIdentity.mutable("JavaThread::_should_post_on_exceptions_flag");
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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

@ -41,7 +41,6 @@ import org.graalvm.compiler.loop.LoopsData;
import org.graalvm.compiler.loop.phases.LoopTransformations;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.EntryMarkerNode;
import org.graalvm.compiler.nodes.EntryProxyNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
@ -159,11 +158,8 @@ public class OnStackReplacementPhase extends Phase {
LoopEx loop = loops.loop(l);
loop.loopBegin().markOsrLoop();
LoopTransformations.peel(loop);
osr.replaceAtUsages(InputType.Guard, AbstractBeginNode.prevBegin((FixedNode) osr.predecessor()));
for (Node usage : osr.usages().snapshot()) {
EntryProxyNode proxy = (EntryProxyNode) usage;
proxy.replaceAndDelete(proxy.value());
}
osr.prepareDelete();
GraphUtil.removeFixedWithUnusedInputs(osr);
debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement loop peeling result");
} while (true);
@ -228,6 +224,7 @@ public class OnStackReplacementPhase extends Phase {
}
osr.replaceAtUsages(InputType.Guard, osrStart);
osr.replaceAtUsages(InputType.Anchor, osrStart);
}
debug.dump(DebugContext.DETAILED_LEVEL, graph, "OnStackReplacement after replacing entry proxies");
GraphUtil.killCFG(start);

@ -212,14 +212,27 @@ public class NewObjectSnippets implements Snippets {
}
@Snippet
public static Object allocateInstance(@ConstantParameter long size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
@ConstantParameter Register threadRegister, @ConstantParameter boolean constantSize, @ConstantParameter String typeContext,
public static Object allocateInstance(@ConstantParameter long size,
KlassPointer hub,
Word prototypeMarkWord,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean constantSize,
@ConstantParameter String typeContext,
@ConstantParameter Counters counters) {
return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, hub, prototypeMarkWord, fillContents, threadRegister, constantSize, typeContext, counters));
return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, hub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, constantSize, typeContext, counters));
}
public static Object allocateInstanceHelper(long size, KlassPointer hub, Word prototypeMarkWord, boolean fillContents,
Register threadRegister, boolean constantSize, String typeContext, Counters counters) {
public static Object allocateInstanceHelper(long size,
KlassPointer hub,
Word prototypeMarkWord,
boolean fillContents,
boolean emitMemoryBarrier,
Register threadRegister,
boolean constantSize,
String typeContext,
Counters counters) {
Object result;
Word thread = registerAsWord(threadRegister);
Word top = readTlabTop(thread);
@ -228,7 +241,7 @@ public class NewObjectSnippets implements Snippets {
if (useTLAB(INJECTED_VMCONFIG) && probability(FAST_PATH_PROBABILITY, newTop.belowOrEqual(end))) {
writeTlabTop(thread, newTop);
emitPrefetchAllocate(newTop, false);
result = formatObject(hub, size, top, prototypeMarkWord, fillContents, constantSize, counters);
result = formatObject(hub, size, top, prototypeMarkWord, fillContents, emitMemoryBarrier, constantSize, counters);
} else {
Counters theCounters = counters;
if (theCounters != null && theCounters.stub != null) {
@ -255,18 +268,27 @@ public class NewObjectSnippets implements Snippets {
private static native Object newInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub);
@Snippet
public static Object allocateInstancePIC(@ConstantParameter long size, KlassPointer hub, Word prototypeMarkWord, @ConstantParameter boolean fillContents,
@ConstantParameter Register threadRegister, @ConstantParameter boolean constantSize, @ConstantParameter String typeContext,
public static Object allocateInstancePIC(@ConstantParameter long size,
KlassPointer hub,
Word prototypeMarkWord,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean constantSize,
@ConstantParameter String typeContext,
@ConstantParameter Counters counters) {
// Klass must be initialized by the time the first instance is allocated, therefore we can
// just load it from the corresponding cell and avoid the resolution check. We have to use a
// fixed load though, to prevent it from floating above the initialization.
KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, picHub, prototypeMarkWord, fillContents, threadRegister, constantSize, typeContext, counters));
return piCastToSnippetReplaceeStamp(allocateInstanceHelper(size, picHub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, constantSize, typeContext, counters));
}
@Snippet
public static Object allocateInstanceDynamic(Class<?> type, Class<?> classClass, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
public static Object allocateInstanceDynamic(Class<?> type, Class<?> classClass,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter Counters counters) {
if (probability(SLOW_PATH_PROBABILITY, type == null)) {
DeoptimizeNode.deopt(None, RuntimeConstraint);
@ -277,10 +299,15 @@ public class NewObjectSnippets implements Snippets {
DeoptimizeNode.deopt(None, RuntimeConstraint);
}
return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(type, fillContents, threadRegister, counters, nonNullType));
return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(type, fillContents, emitMemoryBarrier, threadRegister, counters, nonNullType));
}
private static Object allocateInstanceDynamicHelper(Class<?> type, boolean fillContents, Register threadRegister, Counters counters, Class<?> nonNullType) {
private static Object allocateInstanceDynamicHelper(Class<?> type,
boolean fillContents,
boolean emitMemoryBarrier,
Register threadRegister,
Counters counters,
Class<?> nonNullType) {
KlassPointer hub = ClassGetHubNode.readClass(nonNullType);
if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor());
@ -299,7 +326,7 @@ public class NewObjectSnippets implements Snippets {
* FIXME(je,ds): we should actually pass typeContext instead of "" but late
* binding of parameters is not yet supported by the GraphBuilderPlugin system.
*/
return allocateInstanceHelper(layoutHelper, nonNullHub, prototypeMarkWord, fillContents, threadRegister, false, "", counters);
return allocateInstanceHelper(layoutHelper, nonNullHub, prototypeMarkWord, fillContents, emitMemoryBarrier, threadRegister, false, "", counters);
}
} else {
DeoptimizeNode.deopt(None, RuntimeConstraint);
@ -320,6 +347,7 @@ public class NewObjectSnippets implements Snippets {
@ConstantParameter int headerSize,
@ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ -328,7 +356,7 @@ public class NewObjectSnippets implements Snippets {
// Primitive array types are eagerly pre-resolved. We can use a floating load.
KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
emitMemoryBarrier, threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
}
@Snippet
@ -338,6 +366,7 @@ public class NewObjectSnippets implements Snippets {
@ConstantParameter int headerSize,
@ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ -346,7 +375,7 @@ public class NewObjectSnippets implements Snippets {
// Array type would be resolved by dominating resolution.
KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
emitMemoryBarrier, threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
}
@Snippet
@ -356,6 +385,7 @@ public class NewObjectSnippets implements Snippets {
@ConstantParameter int headerSize,
@ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ -367,7 +397,7 @@ public class NewObjectSnippets implements Snippets {
headerSize,
log2ElementSize,
fillContents,
threadRegister,
emitMemoryBarrier, threadRegister,
maybeUnroll,
typeContext,
useBulkZeroing,
@ -384,8 +414,18 @@ public class NewObjectSnippets implements Snippets {
return config.areNullAllocationStubsAvailable();
}
private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, Register threadRegister,
boolean maybeUnroll, String typeContext, boolean useBulkZeroing, Counters counters) {
private static Object allocateArrayImpl(KlassPointer hub,
int length,
Word prototypeMarkWord,
int headerSize,
int log2ElementSize,
boolean fillContents,
boolean emitMemoryBarrier,
Register threadRegister,
boolean maybeUnroll,
String typeContext,
boolean useBulkZeroing,
Counters counters) {
Object result;
long allocationSize = arrayAllocationSize(length, headerSize, log2ElementSize);
Word thread = registerAsWord(threadRegister);
@ -400,7 +440,7 @@ public class NewObjectSnippets implements Snippets {
if (theCounters != null && theCounters.arrayLoopInit != null) {
theCounters.arrayLoopInit.inc();
}
result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, useBulkZeroing, counters);
result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, emitMemoryBarrier, maybeUnroll, useBulkZeroing, counters);
} else {
result = newArrayStub(hub, length);
}
@ -461,19 +501,29 @@ public class NewObjectSnippets implements Snippets {
Class<?> voidClass,
int length,
@ConstantParameter boolean fillContents,
@ConstantParameter boolean emitMemoryBarrier,
@ConstantParameter Register threadRegister,
@ConstantParameter JavaKind knownElementKind,
@ConstantParameter int knownLayoutHelper,
@ConstantParameter boolean useBulkZeroing,
Word prototypeMarkWord,
@ConstantParameter Counters counters) {
Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, threadRegister, knownElementKind,
Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, emitMemoryBarrier, threadRegister, knownElementKind,
knownLayoutHelper, useBulkZeroing, prototypeMarkWord, counters);
return result;
}
private static Object allocateArrayDynamicImpl(Class<?> elementType, Class<?> voidClass, int length, boolean fillContents, Register threadRegister, JavaKind knownElementKind,
int knownLayoutHelper, boolean useBulkZeroing, Word prototypeMarkWord, Counters counters) {
private static Object allocateArrayDynamicImpl(Class<?> elementType,
Class<?> voidClass,
int length,
boolean fillContents,
boolean emitMemoryBarrier,
Register threadRegister,
JavaKind knownElementKind,
int knownLayoutHelper,
boolean useBulkZeroing,
Word prototypeMarkWord,
Counters counters) {
/*
* We only need the dynamic check for void when we have no static information from
* knownElementKind.
@ -516,7 +566,7 @@ public class NewObjectSnippets implements Snippets {
int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, false, "dynamic type", useBulkZeroing, counters);
emitMemoryBarrier, threadRegister, false, "dynamic type", useBulkZeroing, counters);
return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
}
@ -650,7 +700,14 @@ public class NewObjectSnippets implements Snippets {
/**
* Formats some allocated memory with an object header and zeroes out the rest.
*/
private static Object formatObject(KlassPointer hub, long size, Word memory, Word compileTimePrototypeMarkWord, boolean fillContents, boolean constantSize, Counters counters) {
private static Object formatObject(KlassPointer hub,
long size,
Word memory,
Word compileTimePrototypeMarkWord,
boolean fillContents,
boolean emitMemoryBarrier,
boolean constantSize,
Counters counters) {
Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
initializeObjectHeader(memory, prototypeMarkWord, hub);
if (fillContents) {
@ -658,7 +715,9 @@ public class NewObjectSnippets implements Snippets {
} else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
fillWithGarbage(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, counters);
}
MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
if (emitMemoryBarrier) {
MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
}
return memory.toObjectNonNull();
}
@ -677,8 +736,17 @@ public class NewObjectSnippets implements Snippets {
/**
* Formats some allocated memory with an object header and zeroes out the rest.
*/
private static Object formatArray(KlassPointer hub, long allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
boolean useBulkZeroing, Counters counters) {
private static Object formatArray(KlassPointer hub,
long allocationSize,
int length,
int headerSize,
Word memory,
Word prototypeMarkWord,
boolean fillContents,
boolean emitMemoryBarrier,
boolean maybeUnroll,
boolean useBulkZeroing,
Counters counters) {
memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, LocationIdentity.init());
/*
* store hub last as the concurrent garbage collectors assume length is valid if hub field
@ -690,7 +758,9 @@ public class NewObjectSnippets implements Snippets {
} else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, counters);
}
MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
if (emitMemoryBarrier) {
MembarNode.memoryBarrier(MemoryBarriers.STORE_STORE, LocationIdentity.init());
}
return memory.toObjectNonNull();
}
@ -756,6 +826,7 @@ public class NewObjectSnippets implements Snippets {
args.add("hub", hub);
args.add("prototypeMarkWord", type.prototypeMarkWord());
args.addConst("fillContents", newInstanceNode.fillContents());
args.addConst("emitMemoryBarrier", newInstanceNode.emitMemoryBarrier());
args.addConst("threadRegister", registers.getThreadRegister());
args.addConst("constantSize", true);
args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? type.toJavaName(false) : "");
@ -799,6 +870,7 @@ public class NewObjectSnippets implements Snippets {
args.addConst("headerSize", headerSize);
args.addConst("log2ElementSize", log2ElementSize);
args.addConst("fillContents", newArrayNode.fillContents());
args.addConst("emitMemoryBarrier", newArrayNode.emitMemoryBarrier());
args.addConst("threadRegister", registers.getThreadRegister());
args.addConst("maybeUnroll", length.isConstant());
args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
@ -816,6 +888,7 @@ public class NewObjectSnippets implements Snippets {
assert classClass != null;
args.add("classClass", classClass);
args.addConst("fillContents", newInstanceNode.fillContents());
args.addConst("emitMemoryBarrier", newInstanceNode.emitMemoryBarrier());
args.addConst("threadRegister", registers.getThreadRegister());
args.addConst("counters", counters);
@ -833,6 +906,7 @@ public class NewObjectSnippets implements Snippets {
ValueNode length = newArrayNode.length();
args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
args.addConst("fillContents", newArrayNode.fillContents());
args.addConst("emitMemoryBarrier", newArrayNode.emitMemoryBarrier());
args.addConst("threadRegister", registers.getThreadRegister());
/*
* We use Kind.Illegal as a marker value instead of null because constant snippet

@ -391,7 +391,6 @@ import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode;
import org.graalvm.compiler.nodes.extended.LoadHubNode;
import org.graalvm.compiler.nodes.extended.MembarNode;
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.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
@ -624,7 +623,6 @@ public class BytecodeParser implements GraphBuilderContext {
}
static class IntrinsicScope extends InliningScope {
StateSplit returnStateSplit;
ArrayList<StateSplit> invalidStateUsers;
IntrinsicScope(BytecodeParser parser) {
@ -635,6 +633,7 @@ public class BytecodeParser implements GraphBuilderContext {
super(parser, callee, args);
}
@SuppressWarnings("unlikely-arg-type")
@Override
public void close() {
IntrinsicContext intrinsic = parser.intrinsicContext;
@ -1405,7 +1404,7 @@ public class BytecodeParser implements GraphBuilderContext {
if (profile == null || profile.getNotRecordedProbability() > 0.0) {
return null;
} else {
return append(new ValueAnchorNode(null));
return BeginNode.prevBegin(lastInstr);
}
}
@ -4794,6 +4793,9 @@ public class BytecodeParser implements GraphBuilderContext {
}
}
private static final int SWITCH_DEOPT_UNSEEN = -2;
private static final int SWITCH_DEOPT_SEEN = -1;
private void genSwitch(BytecodeSwitch bs) {
int bci = bci();
ValueNode value = frameState.pop(JavaKind.Int);
@ -4811,20 +4813,16 @@ public class BytecodeParser implements GraphBuilderContext {
ArrayList<BciBlock> actualSuccessors = new ArrayList<>();
int[] keys = new int[nofCases];
int[] keySuccessors = new int[nofCasesPlusDefault];
int deoptSuccessorIndex = -1;
int deoptSuccessorIndex = SWITCH_DEOPT_UNSEEN;
int nextSuccessorIndex = 0;
boolean constantValue = value.isConstant();
for (int i = 0; i < nofCasesPlusDefault; i++) {
if (i < nofCases) {
keys[i] = bs.keyAt(i);
}
if (!constantValue && isNeverExecutedCode(keyProbabilities[i])) {
if (deoptSuccessorIndex < 0) {
deoptSuccessorIndex = nextSuccessorIndex++;
actualSuccessors.add(null);
}
keySuccessors[i] = deoptSuccessorIndex;
deoptSuccessorIndex = SWITCH_DEOPT_SEEN;
keySuccessors[i] = SWITCH_DEOPT_SEEN;
} else {
int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget();
SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
@ -4859,20 +4857,31 @@ public class BytecodeParser implements GraphBuilderContext {
*
* The following code rewires deoptimization stub to existing resolved branch target if
* the target is connected by more than 1 cases.
*
* If this operation rewires every deoptimization seen to an existing branch, care is
* taken that we do not spawn a branch that will never be taken.
*/
if (deoptSuccessorIndex >= 0) {
int[] connectedCases = new int[nextSuccessorIndex];
if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) {
int[] connectedCases = new int[nextSuccessorIndex + 1];
for (int i = 0; i < nofCasesPlusDefault; i++) {
connectedCases[keySuccessors[i]]++;
connectedCases[keySuccessors[i] + 1]++;
}
for (int i = 0; i < nofCasesPlusDefault; i++) {
if (keySuccessors[i] == deoptSuccessorIndex) {
if (keySuccessors[i] == SWITCH_DEOPT_SEEN) {
int targetBci = i < nofCases ? bs.targetAt(i) : bs.defaultTarget();
SuccessorInfo info = bciToBlockSuccessorIndex.get(targetBci);
int rewiredIndex = info.actualIndex;
if (rewiredIndex >= 0 && connectedCases[rewiredIndex] > 1) {
if (rewiredIndex >= 0 && connectedCases[rewiredIndex + 1] > 1) {
// Rewire
keySuccessors[i] = info.actualIndex;
} else {
if (deoptSuccessorIndex == SWITCH_DEOPT_SEEN) {
// Spawn deopt successor if needed.
deoptSuccessorIndex = nextSuccessorIndex++;
actualSuccessors.add(null);
}
keySuccessors[i] = deoptSuccessorIndex;
}
}
}

@ -528,8 +528,8 @@ public class AArch64Move {
break;
case Object:
if (input.isNull()) {
if (crb.mustReplaceWithNullRegister(input)) {
masm.mov(64, dst, crb.nullRegister);
if (crb.mustReplaceWithUncompressedNullRegister(input)) {
masm.mov(64, dst, crb.uncompressedNullRegister);
} else {
masm.mov(dst, 0);
}
@ -725,7 +725,7 @@ public class AArch64Move {
@Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
Register nullRegister = crb.nullRegister;
Register nullRegister = crb.uncompressedNullRegister;
if (!nullRegister.equals(Register.None)) {
emitConversion(asRegister(result), asRegister(input), nullRegister, masm);
}

@ -645,4 +645,3 @@ public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction {
return ((AMD64) tool.target().arch).getFeatures().contains(cpuFeature);
}
}

@ -213,7 +213,7 @@ public class AMD64ControlFlow {
masm.cmpq(keyRegister, (AMD64Address) crb.asLongConstRef(jc));
break;
case Object:
AMD64Move.const2reg(crb, masm, asRegister(scratch), jc);
AMD64Move.const2reg(crb, masm, asRegister(scratch), jc, AMD64Kind.QWORD);
masm.cmpptr(keyRegister, asRegister(scratch));
break;
default:

@ -156,7 +156,7 @@ public class AMD64Move {
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
if (isRegister(result)) {
const2reg(crb, masm, asRegister(result), input);
const2reg(crb, masm, asRegister(result), input, (AMD64Kind) result.getPlatformKind());
} else {
assert isStackSlot(result);
const2stack(crb, masm, result, input);
@ -557,7 +557,7 @@ public class AMD64Move {
}
} else if (isJavaConstant(input)) {
if (isRegister(result)) {
const2reg(crb, masm, asRegister(result), asJavaConstant(input));
const2reg(crb, masm, asRegister(result), asJavaConstant(input), moveKind);
} else if (isStackSlot(result)) {
const2stack(crb, masm, result, asJavaConstant(input));
} else {
@ -645,7 +645,7 @@ public class AMD64Move {
}
}
public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, JavaConstant input) {
public static void const2reg(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, JavaConstant input, AMD64Kind moveKind) {
/*
* Note: we use the kind of the input operand (and not the kind of the result operand)
* because they don't match in all cases. For example, an object constant can be loaded to a
@ -691,20 +691,34 @@ public class AMD64Move {
}
break;
case Object:
assert moveKind != null : "a nun-null moveKind is required for loading an object constant";
// Do not optimize with an XOR as this instruction may be between
// a CMP and a Jcc in which case the XOR will modify the condition
// flags and interfere with the Jcc.
if (input.isNull()) {
if (crb.mustReplaceWithNullRegister(input)) {
masm.movq(result, crb.nullRegister);
if (moveKind == AMD64Kind.QWORD && crb.mustReplaceWithUncompressedNullRegister(input)) {
masm.movq(result, crb.uncompressedNullRegister);
} else {
// Upper bits will be zeroed so this also works for narrow oops
masm.movslq(result, 0);
}
} else if (crb.target.inlineObjects) {
crb.recordInlineDataInCode(input);
masm.movq(result, 0xDEADDEADDEADDEADL, true);
} else {
masm.movq(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0));
if (crb.target.inlineObjects) {
crb.recordInlineDataInCode(input);
if (moveKind == AMD64Kind.DWORD) {
// Support for narrow oops
masm.movl(result, 0xDEADDEAD, true);
} else {
masm.movq(result, 0xDEADDEADDEADDEADL, true);
}
} else {
if (moveKind == AMD64Kind.DWORD) {
// Support for narrow oops
masm.movl(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0));
} else {
masm.movq(result, (AMD64Address) crb.recordDataReferenceInCode(input, 0));
}
}
}
break;
default:
@ -752,13 +766,13 @@ public class AMD64Move {
break;
case Object:
if (input.isNull()) {
if (crb.mustReplaceWithNullRegister(input)) {
masm.movq(dest, crb.nullRegister);
if (crb.mustReplaceWithUncompressedNullRegister(input)) {
masm.movq(dest, crb.uncompressedNullRegister);
return;
}
imm = 0;
} else {
throw GraalError.shouldNotReachHere("Non-null object constants must be in register");
throw GraalError.shouldNotReachHere("Non-null object constants must be in a register");
}
break;
default:
@ -941,7 +955,7 @@ public class AMD64Move {
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
Register nullRegister = crb.nullRegister;
Register nullRegister = crb.uncompressedNullRegister;
if (!nullRegister.equals(Register.None)) {
emitConversion(asRegister(result), asRegister(input), nullRegister, masm);
}

@ -34,6 +34,7 @@ import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.lir.framemap.FrameMap;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterSaveLayout;
import jdk.vm.ci.meta.JavaConstant;
@ -66,7 +67,7 @@ public final class AMD64ZapRegistersOp extends AMD64LIRInstruction implements Sa
for (int i = 0; i < zappedRegisters.length; i++) {
Register reg = zappedRegisters[i];
if (reg != null) {
AMD64Move.const2reg(crb, masm, reg, zapValues[i]);
AMD64Move.const2reg(crb, masm, reg, zapValues[i], AMD64Kind.QWORD);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, 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
@ -35,6 +35,7 @@ import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRRIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexRVMOp;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.asm.amd64.AVXKind;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
@ -42,6 +43,7 @@ import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.meta.AllocatableValue;
public class AMD64VectorBinary {
@ -102,6 +104,38 @@ public class AMD64VectorBinary {
}
}
public static final class AVXBinaryConstFloatOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<AVXBinaryConstFloatOp> TYPE = LIRInstructionClass.create(AVXBinaryConstFloatOp.class);
@Opcode private final VexRVMOp opcode;
private final AVXKind.AVXSize size;
@Def({REG}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue x;
protected ConstantValue y;
public AVXBinaryConstFloatOp(VexRVMOp opcode, AVXKind.AVXSize size, AllocatableValue result, AllocatableValue x, ConstantValue y) {
super(TYPE);
assert y.getPlatformKind() == AMD64Kind.SINGLE || y.getPlatformKind() == AMD64Kind.DOUBLE;
this.opcode = opcode;
this.size = size;
this.result = result;
this.x = x;
this.y = y;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
if (y.getPlatformKind() == AMD64Kind.SINGLE) {
opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asFloatConstRef(y.getJavaConstant()));
} else {
assert y.getPlatformKind() == AMD64Kind.DOUBLE;
opcode.emit(masm, size, asRegister(result), asRegister(x), (AMD64Address) crb.asDoubleConstRef(y.getJavaConstant()));
}
}
}
public static final class AVXBinaryMemoryOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<AVXBinaryMemoryOp> TYPE = LIRInstructionClass.create(AVXBinaryMemoryOp.class);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -99,7 +99,7 @@ public class ConstantStackCastTest extends LIRTest {
}
@Test
public void runByte() throws Throwable {
public void runByte() {
runTest("testByte", (byte) 0);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -254,7 +254,7 @@ public abstract class LIRTest extends JTTTest {
@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
@java.lang.annotation.Target(ElementType.METHOD)
public static @interface LIRIntrinsic {
public @interface LIRIntrinsic {
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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,7 +54,7 @@ public class LIRTestTest extends LIRTest {
}
@Test
public void runInt() throws Throwable {
public void runInt() {
runTest("testGetOutput", Integer.MIN_VALUE, 0, supply(() -> new int[3]));
runTest("testGetOutput", -1, Integer.MAX_VALUE, supply(() -> new int[3]));
runTest("testGetOutput", 0, 42, supply(() -> new int[3]));

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2019, 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
@ -98,7 +98,7 @@ public class StackMoveTest extends LIRTest {
}
@Test
public void runInt() throws Throwable {
public void runInt() {
runTest("testInt", Integer.MIN_VALUE, supply(() -> new int[4]));
runTest("testInt", -1, supply(() -> new int[4]));
runTest("testInt", 0, supply(() -> new int[4]));
@ -125,7 +125,7 @@ public class StackMoveTest extends LIRTest {
}
@Test
public void runLong() throws Throwable {
public void runLong() {
runTest("testLong", Long.MIN_VALUE, supply(() -> new long[3]));
runTest("testLong", -1L, supply(() -> new long[3]));
runTest("testLong", 0L, supply(() -> new long[3]));
@ -152,7 +152,7 @@ public class StackMoveTest extends LIRTest {
}
@Test
public void runFloat() throws Throwable {
public void runFloat() {
runTest("testFloat", Float.MIN_VALUE, supply(() -> new float[3]));
runTest("testFloat", -1f, supply(() -> new float[3]));
runTest("testFloat", -0.1f, supply(() -> new float[3]));
@ -217,7 +217,7 @@ public class StackMoveTest extends LIRTest {
}
@Test
public void runShort() throws Throwable {
public void runShort() {
runTest("testShort", Short.MIN_VALUE, supply(() -> new short[3]));
runTest("testShort", (short) -1, supply(() -> new short[3]));
runTest("testShort", (short) 0, supply(() -> new short[3]));
@ -251,7 +251,7 @@ public class StackMoveTest extends LIRTest {
}
@Test
public void runByte() throws Throwable {
public void runByte() {
runTest("testByte", Byte.MIN_VALUE, supply(() -> new byte[3]));
runTest("testByte", (byte) -1, supply(() -> new byte[3]));
runTest("testByte", (byte) 0, supply(() -> new byte[3]));

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -139,7 +139,7 @@ public class StackStoreLoadTest extends LIRTest {
}
@Test
public void runByte() throws Throwable {
public void runByte() {
runTest("testByte", Byte.MIN_VALUE, supply(() -> new byte[3]));
runTest("testByte", (byte) -1, supply(() -> new byte[3]));
runTest("testByte", (byte) 0, supply(() -> new byte[3]));

@ -25,7 +25,7 @@
package org.graalvm.compiler.lir;
import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
import static jdk.vm.ci.code.ValueUtil.asRegister;
@ -242,7 +242,7 @@ public final class LIRVerifier {
if ((isVariable(value) && flags.contains(OperandFlag.REG)) ||
(isRegister(value) && flags.contains(OperandFlag.REG)) ||
(isStackSlotValue(value) && flags.contains(OperandFlag.STACK)) ||
(isJavaConstant(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
(isConstantValue(value) && flags.contains(OperandFlag.CONST) && mode != OperandMode.DEF) ||
(isIllegal(value) && flags.contains(OperandFlag.ILLEGAL))) {
return;
}

@ -35,6 +35,7 @@ import java.util.EnumSet;
import jdk.internal.vm.compiler.collections.EconomicSet;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
@ -154,7 +155,7 @@ public class StandardOp {
@Override
public void emitCode(CompilationResultBuilder crb) {
if (align) {
crb.asm.align(crb.target.wordSize * 2);
crb.asm.align(GraalOptions.LoopHeaderAlignment.getValue(crb.getOptions()));
}
crb.asm.bind(label);
}

@ -127,7 +127,7 @@ public class CompilationResultBuilder {
public final Assembler asm;
public final DataBuilder dataBuilder;
public final CompilationResult compilationResult;
public final Register nullRegister;
public final Register uncompressedNullRegister;
public final TargetDescription target;
public final CodeCacheProvider codeCache;
public final ForeignCallsProvider foreignCalls;
@ -171,17 +171,44 @@ public class CompilationResultBuilder {
*/
private boolean conservativeLabelOffsets = false;
public final boolean mustReplaceWithNullRegister(JavaConstant nullConstant) {
return !nullRegister.equals(Register.None) && JavaConstant.NULL_POINTER.equals(nullConstant);
public final boolean mustReplaceWithUncompressedNullRegister(JavaConstant nullConstant) {
return !uncompressedNullRegister.equals(Register.None) && JavaConstant.NULL_POINTER.equals(nullConstant);
}
public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, FrameContext frameContext,
OptionValues options, DebugContext debug, CompilationResult compilationResult, Register nullRegister) {
this(codeCache, foreignCalls, frameMap, asm, dataBuilder, frameContext, options, debug, compilationResult, nullRegister, EconomicMap.create(Equivalence.DEFAULT));
public CompilationResultBuilder(CodeCacheProvider codeCache,
ForeignCallsProvider foreignCalls,
FrameMap frameMap,
Assembler asm,
DataBuilder dataBuilder,
FrameContext frameContext,
OptionValues options,
DebugContext debug,
CompilationResult compilationResult,
Register uncompressedNullRegister) {
this(codeCache,
foreignCalls,
frameMap,
asm,
dataBuilder,
frameContext,
options,
debug,
compilationResult,
uncompressedNullRegister,
EconomicMap.create(Equivalence.DEFAULT));
}
public CompilationResultBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder, FrameContext frameContext,
OptionValues options, DebugContext debug, CompilationResult compilationResult, Register nullRegister, EconomicMap<Constant, Data> dataCache) {
public CompilationResultBuilder(CodeCacheProvider codeCache,
ForeignCallsProvider foreignCalls,
FrameMap frameMap,
Assembler asm,
DataBuilder dataBuilder,
FrameContext frameContext,
OptionValues options,
DebugContext debug,
CompilationResult compilationResult,
Register uncompressedNullRegister,
EconomicMap<Constant, Data> dataCache) {
this.target = codeCache.getTarget();
this.codeCache = codeCache;
this.foreignCalls = foreignCalls;
@ -189,7 +216,7 @@ public class CompilationResultBuilder {
this.asm = asm;
this.dataBuilder = dataBuilder;
this.compilationResult = compilationResult;
this.nullRegister = nullRegister;
this.uncompressedNullRegister = uncompressedNullRegister;
this.frameContext = frameContext;
this.options = options;
this.debug = debug;

@ -52,8 +52,8 @@ public interface CompilationResultBuilderFactory {
@Override
public CompilationResultBuilder createBuilder(CodeCacheProvider codeCache, ForeignCallsProvider foreignCalls, FrameMap frameMap, Assembler asm, DataBuilder dataBuilder,
FrameContext frameContext, OptionValues options, DebugContext debug, CompilationResult compilationResult, Register nullRegister) {
return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, dataBuilder, frameContext, options, debug, compilationResult, nullRegister);
FrameContext frameContext, OptionValues options, DebugContext debug, CompilationResult compilationResult, Register uncompressedNullRegister) {
return new CompilationResultBuilder(codeCache, foreignCalls, frameMap, asm, dataBuilder, frameContext, options, debug, compilationResult, uncompressedNullRegister);
}
};
}

@ -60,9 +60,9 @@ import org.graalvm.compiler.lir.StandardOp;
import org.graalvm.compiler.lir.StandardOp.BlockEndOp;
import org.graalvm.compiler.lir.StandardOp.LabelOp;
import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
import org.graalvm.compiler.lir.hashing.Hasher;
import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.hashing.Hasher;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType;
@ -229,11 +229,31 @@ public abstract class LIRGenerator implements LIRGeneratorTool {
append(moveFactory.createMove(dst, src));
}
@Override
public Variable emitReadRegister(Register register, ValueKind<?> kind) {
return emitMove(register.asValue(kind));
}
@Override
public void emitWriteRegister(Register dst, Value src, ValueKind<?> kind) {
emitMove(dst.asValue(kind), src);
}
@Override
public void emitMoveConstant(AllocatableValue dst, Constant src) {
append(moveFactory.createLoad(dst, src));
}
@Override
public boolean canInlineConstant(Constant constant) {
return moveFactory.canInlineConstant(constant);
}
@Override
public boolean mayEmbedConstantLoad(Constant constant) {
return moveFactory.mayEmbedConstantLoad(constant);
}
@Override
public Value emitConstant(LIRKind kind, Constant constant) {
if (moveFactory.canInlineConstant(constant)) {

@ -64,15 +64,23 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
*/
interface MoveFactory {
/**
* Checks whether the loading of the supplied constant can be deferred until usage.
*/
@SuppressWarnings("unused")
default boolean mayEmbedConstantLoad(Constant constant) {
return false;
}
/**
* Checks whether the supplied constant can be used without loading it into a register for
* most operations, i.e., for commonly used arithmetic, logical, and comparison operations.
*
* @param c The constant to check.
* @param constant The constant to check.
* @return True if the constant can be used directly, false if the constant needs to be in a
* register.
*/
boolean canInlineConstant(Constant c);
boolean canInlineConstant(Constant constant);
/**
* @param constant The constant that might be moved to a stack slot.
@ -130,6 +138,10 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
BlockScope getBlockScope(AbstractBlockBase<?> block);
boolean canInlineConstant(Constant constant);
boolean mayEmbedConstantLoad(Constant constant);
Value emitConstant(LIRKind kind, Constant constant);
Value emitJavaConstant(JavaConstant constant);
@ -192,6 +204,10 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
void emitMove(AllocatableValue dst, Value src);
Variable emitReadRegister(Register register, ValueKind<?> kind);
void emitWriteRegister(Register dst, Value src, ValueKind<?> wordStamp);
void emitMoveConstant(AllocatableValue dst, Constant src);
Variable emitAddress(AllocatableValue stackslot);

@ -26,7 +26,7 @@
package org.graalvm.compiler.lir.ssa;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
import java.util.BitSet;
@ -137,7 +137,7 @@ final class SSAVerifier {
}
private static boolean shouldProcess(Value value) {
return !value.equals(Value.ILLEGAL) && !isJavaConstant(value) && !isRegister(value) && !isStackSlotValue(value);
return !value.equals(Value.ILLEGAL) && !isConstantValue(value) && !isRegister(value) && !isStackSlotValue(value);
}
}

@ -26,7 +26,9 @@ package org.graalvm.compiler.loop.test;
import java.util.ListIterator;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.iterators.NodeIterable;
@ -216,6 +218,25 @@ public class LoopPartialUnrollTest extends GraalCompilerTest {
test("testSignExtensionSnippet", 9L);
}
public static Object objectPhi(int n) {
Integer v = Integer.valueOf(200);
GraalDirectives.blackhole(v); // Prevents PEA
Integer r = 1;
for (int i = 0; iterationCount(100, i < n); i++) {
GraalDirectives.blackhole(r); // Create a phi of two loop invariants
r = v;
}
return r;
}
@Test
public void testObjectPhi() {
OptionValues options = new OptionValues(getInitialOptions(), GraalOptions.LoopPeeling, false);
test(options, "objectPhi", 1);
}
@Override
protected Suites createSuites(OptionValues opts) {
Suites suites = super.createSuites(opts).copy();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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
@ -344,7 +344,7 @@ public class LoopEx {
}
}
}
LoopFragment.computeNodes(branchNodes, branch.graph(), blocks, exits);
LoopFragment.computeNodes(branchNodes, branch.graph(), this, blocks, exits);
}
public EconomicMap<Node, InductionVariable> getInductionVariables() {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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
@ -25,12 +25,11 @@
package org.graalvm.compiler.loop;
import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Deque;
import java.util.Iterator;
import jdk.internal.vm.compiler.collections.EconomicMap;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
import org.graalvm.compiler.graph.Node;
@ -42,18 +41,15 @@ import org.graalvm.compiler.nodes.EndNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.GuardNode;
import org.graalvm.compiler.nodes.GuardPhiNode;
import org.graalvm.compiler.nodes.GuardProxyNode;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.LoopBeginNode;
import org.graalvm.compiler.nodes.LoopExitNode;
import org.graalvm.compiler.nodes.MergeNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.PhiNode;
import org.graalvm.compiler.nodes.ProxyNode;
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.VirtualState;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
@ -199,17 +195,7 @@ public abstract class LoopFragment {
}
}
protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks) {
return computeNodes(graph, blocks, Collections.emptyList());
}
protected static NodeBitMap computeNodes(Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
final NodeBitMap nodes = graph.createNodeBitMap();
computeNodes(nodes, graph, blocks, earlyExits);
return nodes;
}
protected static void computeNodes(NodeBitMap nodes, Graph graph, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
protected static void computeNodes(NodeBitMap nodes, Graph graph, LoopEx loop, Iterable<AbstractBeginNode> blocks, Iterable<AbstractBeginNode> earlyExits) {
for (AbstractBeginNode b : blocks) {
if (b.isDeleted()) {
continue;
@ -261,11 +247,11 @@ public abstract class LoopFragment {
for (Node n : b.getBlockNodes()) {
if (n instanceof CommitAllocationNode) {
for (VirtualObjectNode obj : ((CommitAllocationNode) n).getVirtualObjects()) {
markFloating(worklist, obj, nodes, nonLoopNodes);
markFloating(worklist, loop, obj, nodes, nonLoopNodes);
}
}
if (n instanceof MonitorEnterNode) {
markFloating(worklist, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
markFloating(worklist, loop, ((MonitorEnterNode) n).getMonitorId(), nodes, nonLoopNodes);
}
if (n instanceof AbstractMergeNode) {
/*
@ -274,12 +260,12 @@ public abstract class LoopFragment {
*/
for (PhiNode phi : ((AbstractMergeNode) n).phis()) {
for (Node usage : phi.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
markFloating(worklist, loop, usage, nodes, nonLoopNodes);
}
}
}
for (Node usage : n.usages()) {
markFloating(worklist, usage, nodes, nonLoopNodes);
markFloating(worklist, loop, usage, nodes, nonLoopNodes);
}
}
}
@ -331,10 +317,14 @@ public abstract class LoopFragment {
workList.push(entry);
}
private static void markFloating(Deque<WorkListEntry> workList, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) {
private static void markFloating(Deque<WorkListEntry> workList, LoopEx loop, Node start, NodeBitMap loopNodes, NodeBitMap nonLoopNodes) {
if (isLoopNode(start, loopNodes, nonLoopNodes).isKnown()) {
return;
}
LoopBeginNode loopBeginNode = loop.loopBegin();
ControlFlowGraph cfg = loop.loopsData().getCFG();
pushWorkList(workList, start, loopNodes);
while (!workList.isEmpty()) {
WorkListEntry currentEntry = workList.peek();
@ -352,13 +342,27 @@ public abstract class LoopFragment {
workList.pop();
boolean isLoopNode = currentEntry.isLoopNode;
Node current = currentEntry.n;
if (!isLoopNode && current instanceof GuardNode) {
/*
* (gd) this is only OK if we are not going to make loop transforms based on
* this
*/
assert !((GuardNode) current).graph().hasValueProxies();
isLoopNode = true;
if (!isLoopNode && current instanceof GuardNode && !current.hasUsages()) {
GuardNode guard = (GuardNode) current;
if (isLoopNode(guard.getCondition(), loopNodes, nonLoopNodes) != TriState.FALSE) {
ValueNode anchor = guard.getAnchor().asNode();
TriState isAnchorInLoop = isLoopNode(anchor, loopNodes, nonLoopNodes);
if (isAnchorInLoop != TriState.FALSE) {
if (!(anchor instanceof LoopExitNode && ((LoopExitNode) anchor).loopBegin() == loopBeginNode)) {
/*
* (gd) this is wrong in general, it's completely avoidable while we
* are doing loop transforms using ValueProxies. If it happens after
* it could still cause problem.
*/
assert !((GuardNode) current).graph().hasValueProxies();
isLoopNode = true;
}
} else if (AbstractControlFlowGraph.strictlyDominates(cfg.blockFor(anchor), cfg.blockFor(loopBeginNode))) {
// The anchor is above the loop. The no-usage guard can potentially be
// scheduled inside the loop.
isLoopNode = true;
}
}
}
if (isLoopNode) {
loopNodes.mark(current);
@ -467,14 +471,7 @@ public abstract class LoopFragment {
final ValueNode replaceWith;
ValueNode newVpn = prim(newEarlyExitIsLoopExit ? vpn : vpn.value());
if (newVpn != null) {
PhiNode phi;
if (vpn instanceof ValueProxyNode) {
phi = graph.addWithoutUnique(new ValuePhiNode(vpn.stamp(NodeView.DEFAULT), merge));
} else if (vpn instanceof GuardProxyNode) {
phi = graph.addWithoutUnique(new GuardPhiNode(merge));
} else {
throw GraalError.shouldNotReachHere();
}
PhiNode phi = vpn.createPhi(merge);
phi.addInput(vpn);
phi.addInput(newVpn);
replaceWith = phi;

@ -169,12 +169,13 @@ public class LoopFragmentInside extends LoopFragment {
LoopBeginNode mainLoopBegin = loop.loopBegin();
ArrayList<ValueNode> backedgeValues = new ArrayList<>();
for (PhiNode mainPhiNode : mainLoopBegin.phis()) {
ValueNode duplicatedNode = getDuplicatedNode(mainPhiNode.valueAt(1));
ValueNode originalNode = mainPhiNode.valueAt(1);
ValueNode duplicatedNode = getDuplicatedNode(originalNode);
if (duplicatedNode == null) {
if (mainLoopBegin.isPhiAtMerge(mainPhiNode.valueAt(1))) {
duplicatedNode = ((PhiNode) (mainPhiNode.valueAt(1))).valueAt(1);
if (mainLoopBegin.isPhiAtMerge(originalNode)) {
duplicatedNode = ((PhiNode) (originalNode)).valueAt(1);
} else {
assert mainPhiNode.valueAt(1).isConstant() : mainPhiNode.valueAt(1);
assert originalNode.isConstant() || loop.isOutsideLoop(originalNode) : "Not duplicated node " + originalNode;
}
}
backedgeValues.add(duplicatedNode);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, 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
@ -64,7 +64,9 @@ public class LoopFragmentWhole extends LoopFragment {
public NodeBitMap nodes() {
if (nodes == null) {
Loop<Block> loop = loop().loop();
nodes = LoopFragment.computeNodes(graph(), LoopFragment.toHirBlocks(loop.getBlocks()), LoopFragment.toHirBlocks(loop.getLoopExits()));
NodeBitMap loopNodes = graph().createNodeBitMap();
LoopFragment.computeNodes(loopNodes, graph(), loop(), LoopFragment.toHirBlocks(loop.getBlocks()), LoopFragment.toHirBlocks(loop.getLoopExits()));
nodes = loopNodes;
}
return nodes;
}
@ -110,7 +112,6 @@ public class LoopFragmentWhole extends LoopFragment {
@Override
public void insertBefore(LoopEx loop) {
// TODO Auto-generated method stub
// nothing to do
}
}

@ -59,21 +59,20 @@ public abstract class AbstractBeginNode extends FixedWithNextNode implements LIR
Node next = from;
while (next != null) {
if (next instanceof AbstractBeginNode) {
AbstractBeginNode begin = (AbstractBeginNode) next;
return begin;
return (AbstractBeginNode) next;
}
next = next.predecessor();
}
return null;
}
private void evacuateGuards(FixedNode evacuateFrom) {
private void evacuateAnchored(FixedNode evacuateFrom) {
if (!hasNoUsages()) {
AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
assert prevBegin != null;
for (Node anchored : anchored().snapshot()) {
anchored.replaceFirstInput(this, prevBegin);
}
replaceAtUsages(InputType.Anchor, prevBegin);
replaceAtUsages(InputType.Guard, prevBegin);
assert anchored().isEmpty() : anchored().snapshot();
}
}
@ -82,7 +81,7 @@ public abstract class AbstractBeginNode extends FixedWithNextNode implements LIR
}
public void prepareDelete(FixedNode evacuateFrom) {
evacuateGuards(evacuateFrom);
evacuateAnchored(evacuateFrom);
}
@Override

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2019, 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
@ -38,11 +38,14 @@ import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeMap;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.lir.ConstantValue;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@ -143,14 +146,32 @@ public final class ConstantNode extends FloatingNode implements LIRLowerable, Ar
@Override
public void generate(NodeLIRBuilderTool gen) {
LIRKind kind = gen.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT));
LIRGeneratorTool lirTool = gen.getLIRGeneratorTool();
LIRKind kind = lirTool.getLIRKind(stamp(NodeView.DEFAULT));
if (onlyUsedInVirtualState()) {
gen.setResult(this, new ConstantValue(kind, value));
} else if (lirTool.canInlineConstant(value) || (lirTool.mayEmbedConstantLoad(value) && hasExactlyOneUsage() && onlyUsedInCurrentBlock())) {
gen.setResult(this, new ConstantValue(lirTool.toRegisterKind(kind), value));
} else {
gen.setResult(this, gen.getLIRGeneratorTool().emitConstant(kind, value));
}
}
/**
* Expecting false for loop invariant.
*/
private boolean onlyUsedInCurrentBlock() {
assert graph().getLastSchedule() != null;
NodeMap<Block> nodeBlockMap = graph().getLastSchedule().getNodeToBlockMap();
Block currentBlock = nodeBlockMap.get(this);
for (Node usage : usages()) {
if (currentBlock != nodeBlockMap.get(usage)) {
return false;
}
}
return true;
}
private boolean onlyUsedInVirtualState() {
for (Node n : this.usages()) {
if (n instanceof VirtualState) {

@ -30,7 +30,9 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@ -51,4 +53,24 @@ public final class EntryMarkerNode extends BeginStateSplitNode implements Iterab
public void generate(NodeLIRBuilderTool gen) {
throw new GraalError("OnStackReplacementNode should not survive");
}
@Override
public NodeIterable<Node> anchored() {
return super.anchored().filter(n -> {
if (n instanceof EntryProxyNode) {
EntryProxyNode proxyNode = (EntryProxyNode) n;
return proxyNode.proxyPoint != this;
}
return true;
});
}
@Override
public void prepareDelete(FixedNode evacuateFrom) {
for (Node usage : usages().filter(EntryProxyNode.class).snapshot()) {
EntryProxyNode proxy = (EntryProxyNode) usage;
proxy.replaceAndDelete(proxy.value());
}
super.prepareDelete(evacuateFrom);
}
}

@ -30,19 +30,22 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.nodes.spi.SwitchFoldable;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.SpeculationLog;
@NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}", allowedUsageTypes = Guard, size = SIZE_2, cycles = CYCLES_2)
public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType {
public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType, SwitchFoldable {
public static final NodeClass<FixedGuardNode> TYPE = NodeClass.create(FixedGuardNode.class);
public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
@ -115,4 +118,92 @@ public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowe
public boolean canDeoptimize() {
return true;
}
@Override
public Node getNextSwitchFoldableBranch() {
return next();
}
@Override
public boolean isInSwitch(ValueNode switchValue) {
return hasNoUsages() && isNegated() && SwitchFoldable.maybeIsInSwitch(condition()) && SwitchFoldable.sameSwitchValue(condition(), switchValue);
}
@Override
public void cutOffCascadeNode() {
/* nop */
}
@Override
public void cutOffLowestCascadeNode() {
setNext(null);
}
@Override
public boolean isDefaultSuccessor(AbstractBeginNode beginNode) {
return beginNode.next() == next();
}
@Override
public AbstractBeginNode getDefault() {
FixedNode defaultNode = next();
setNext(null);
return BeginNode.begin(defaultNode);
}
@Override
public ValueNode switchValue() {
if (SwitchFoldable.maybeIsInSwitch(condition())) {
return ((IntegerEqualsNode) condition()).getX();
}
return null;
}
@Override
public boolean isNonInitializedProfile() {
// @formatter:off
// Checkstyle: stop
/*
* These nodes can appear in non initialized cascades. Though they are technically profiled
* nodes, their presence does not really prevent us from constructing a uniform distribution
* for the new switch, while keeping these to probability 0. Furthermore, these can be the
* result of the pattern:
* if (c) {
* CompilerDirectives.transferToInterpreter();
* }
* Since we cannot differentiate this case from, say, a guard created because profiling
* determined that the branch was never taken, and given what we saw before, we will
* consider all fixedGuards as nodes with no profiles for switch folding purposes.
*/
// Checkstyle: resume
// @formatter:on
return true;
}
@Override
public int intKeyAt(int i) {
assert i == 0;
return ((IntegerEqualsNode) condition()).getY().asJavaConstant().asInt();
}
@Override
public double keyProbability(int i) {
return 0;
}
@Override
public AbstractBeginNode keySuccessor(int i) {
DeoptimizeNode deopt = new DeoptimizeNode(getAction(), getReason(), getSpeculation());
deopt.setNodeSourcePosition(getNodeSourcePosition());
AbstractBeginNode begin = new BeginNode();
// Link the two nodes, but do not add them to the graph yet, so we do not need to remove
// them on an abort.
begin.next = deopt;
return begin;
}
@Override
public double defaultProbability() {
return 1.0d;
}
}

@ -319,7 +319,7 @@ public class GraphDecoder {
public static final NodeClass<ProxyPlaceholder> TYPE = NodeClass.create(ProxyPlaceholder.class);
@Input ValueNode value;
@Input(InputType.Unchecked) Node proxyPoint;
@Input(InputType.Association) Node proxyPoint;
public ProxyPlaceholder(ValueNode value, MergeNode proxyPoint) {
super(TYPE, value.stamp(NodeView.DEFAULT));
@ -884,14 +884,7 @@ public class GraphDecoder {
if (!merge.isPhiAtMerge(existing)) {
/* Now we have two different values, so we need to create a phi node. */
PhiNode phi;
if (proxy instanceof ValueProxyNode) {
phi = graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(NodeView.DEFAULT), merge));
} else if (proxy instanceof GuardProxyNode) {
phi = graph.addWithoutUnique(new GuardPhiNode(merge));
} else {
throw GraalError.shouldNotReachHere();
}
PhiNode phi = proxy.createPhi(merge);
/* Add the inputs from all previous exits. */
for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
phi.addInput(existing);
@ -1336,6 +1329,11 @@ public class GraphDecoder {
* @param methodScope The current method.
*/
protected void cleanupGraph(MethodScope methodScope) {
for (MergeNode merge : graph.getNodes(MergeNode.TYPE)) {
for (ProxyPlaceholder placeholder : merge.usages().filter(ProxyPlaceholder.class).snapshot()) {
placeholder.replaceAndDelete(placeholder.value);
}
}
assert verifyEdges();
}

@ -61,6 +61,11 @@ public final class GuardProxyNode extends ProxyNode implements GuardingNode, Pro
return (value == null ? null : value.asNode());
}
@Override
public PhiNode createPhi(AbstractMergeNode merge) {
return graph().addWithoutUnique(new GuardPhiNode(merge));
}
@Override
public Node getOriginalNode() {
return (value == null ? null : value.asNode());

@ -42,6 +42,7 @@ import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
import org.graalvm.compiler.core.common.calc.Condition;
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.core.common.type.StampFactory;
import org.graalvm.compiler.debug.CounterKey;
@ -71,8 +72,10 @@ import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.nodes.spi.SwitchFoldable;
import org.graalvm.compiler.nodes.util.GraphUtil;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
@ -87,7 +90,7 @@ import jdk.vm.ci.meta.TriState;
* of a comparison.
*/
@NodeInfo(cycles = CYCLES_1, size = SIZE_2, sizeRationale = "2 jmps")
public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable {
public final class IfNode extends ControlSplitNode implements Simplifiable, LIRLowerable, SwitchFoldable {
public static final NodeClass<IfNode> TYPE = NodeClass.create(IfNode.class);
private static final CounterKey CORRECTED_PROBABILITIES = DebugContext.counter("CorrectedProbabilities");
@ -297,6 +300,10 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL
return;
}
if (switchTransformationOptimization(tool)) {
return;
}
if (falseSuccessor().hasNoUsages() && (!(falseSuccessor() instanceof LoopExitNode)) && falseSuccessor().next() instanceof IfNode &&
!(((IfNode) falseSuccessor().next()).falseSuccessor() instanceof LoopExitNode)) {
AbstractBeginNode intermediateBegin = falseSuccessor();
@ -454,6 +461,70 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL
return true;
}
// SwitchFoldable implementation.
@Override
public Node getNextSwitchFoldableBranch() {
return falseSuccessor();
}
@Override
public boolean isInSwitch(ValueNode switchValue) {
return SwitchFoldable.maybeIsInSwitch(condition()) && SwitchFoldable.sameSwitchValue(condition(), switchValue);
}
@Override
public void cutOffCascadeNode() {
setTrueSuccessor(null);
}
@Override
public void cutOffLowestCascadeNode() {
setFalseSuccessor(null);
setTrueSuccessor(null);
}
@Override
public AbstractBeginNode getDefault() {
return falseSuccessor();
}
@Override
public ValueNode switchValue() {
if (SwitchFoldable.maybeIsInSwitch(condition())) {
return ((IntegerEqualsNode) condition()).getX();
}
return null;
}
@Override
public boolean isNonInitializedProfile() {
return getTrueSuccessorProbability() == 0.5d;
}
@Override
public int intKeyAt(int i) {
assert i == 0;
return ((IntegerEqualsNode) condition()).getY().asJavaConstant().asInt();
}
@Override
public double keyProbability(int i) {
assert i == 0;
return getTrueSuccessorProbability();
}
@Override
public AbstractBeginNode keySuccessor(int i) {
assert i == 0;
return trueSuccessor();
}
@Override
public double defaultProbability() {
return 1.0d - getTrueSuccessorProbability();
}
/**
* Try to optimize this as if it were a {@link ConditionalNode}.
*/
@ -606,6 +677,50 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL
}
}
}
} else if (y instanceof PrimitiveConstant && ((PrimitiveConstant) y).asLong() < 0 && falseSuccessor().next() instanceof IfNode) {
IfNode ifNode2 = (IfNode) falseSuccessor().next();
AbstractBeginNode falseSucc = ifNode2.falseSuccessor();
AbstractBeginNode trueSucc = ifNode2.trueSuccessor();
IntegerBelowNode below = null;
if (ifNode2.condition() instanceof IntegerLessThanNode) {
ValueNode x = lessThan.getX();
IntegerLessThanNode lessThan2 = (IntegerLessThanNode) ifNode2.condition();
/*
* Convert x >= -C1 && x < C2, represented as !(x < -C1) && x < C2, into an
* unsigned compare. This condition is equivalent to x + C1 |<| C1 + C2 if C1 +
* C2 does not overflow.
*/
Constant c2 = lessThan2.getY().stamp(view).asConstant();
if (lessThan2.getX() == x && c2 instanceof PrimitiveConstant && ((PrimitiveConstant) c2).asLong() > 0 &&
x.stamp(view).isCompatible(lessThan.getY().stamp(view)) &&
x.stamp(view).isCompatible(lessThan2.getY().stamp(view)) &&
sameDestination(trueSuccessor(), ifNode2.falseSuccessor)) {
long newLimitValue = -((PrimitiveConstant) y).asLong() + ((PrimitiveConstant) c2).asLong();
// Make sure the limit fits into the target type without overflow.
if (newLimitValue > 0 && newLimitValue <= CodeUtil.maxValue(PrimitiveStamp.getBits(x.stamp(view)))) {
ConstantNode newLimit = ConstantNode.forIntegerStamp(x.stamp(view), newLimitValue, graph());
ConstantNode c1 = ConstantNode.forIntegerStamp(x.stamp(view), -((PrimitiveConstant) y).asLong(), graph());
ValueNode addNode = graph().addOrUniqueWithInputs(AddNode.create(x, c1, view));
below = graph().unique(new IntegerBelowNode(addNode, newLimit));
}
}
}
if (below != null) {
try (DebugCloseable position = ifNode2.withNodeSourcePosition()) {
ifNode2.setTrueSuccessor(null);
ifNode2.setFalseSuccessor(null);
IfNode newIfNode = graph().add(new IfNode(below, trueSucc, falseSucc, trueSuccessorProbability));
// Remove the < -C1 test.
tool.deleteBranch(trueSuccessor);
graph().removeSplit(this, falseSuccessor);
// Replace the second test with the new one.
ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
ifNode2.safeDelete();
return true;
}
}
}
}
return false;
@ -1268,8 +1383,7 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL
private MergeNode insertMerge(AbstractBeginNode begin, FrameState stateAfter) {
MergeNode merge = graph().add(new MergeNode());
if (!begin.anchored().isEmpty()) {
Object before = null;
before = begin.anchored().snapshot();
Object before = begin.anchored().snapshot();
begin.replaceAtUsages(InputType.Guard, merge);
begin.replaceAtUsages(InputType.Anchor, merge);
assert begin.anchored().isEmpty() : before + " " + begin.anchored().snapshot();

@ -75,4 +75,6 @@ public abstract class ProxyNode extends FloatingNode implements ValueNumberable
public static GuardProxyNode forGuard(GuardingNode value, LoopExitNode exit, StructuredGraph graph) {
return graph.unique(new GuardProxyNode(value, exit));
}
public abstract PhiNode createPhi(AbstractMergeNode merge);
}

Some files were not shown because too many files have changed in this diff Show More