diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk index a889e79026..1763f31c06 100644 --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -450,21 +450,17 @@ jdk.internal.vm.compiler_ADD_JAVAC_FLAGS += -parameters -XDstringConcat=inline \ jdk.internal.vm.compiler_EXCLUDES += \ jdk.internal.vm.compiler.collections.test \ - org.graalvm.compiler.processor \ - org.graalvm.compiler.core.match.processor \ - org.graalvm.compiler.nodeinfo.processor \ - org.graalvm.compiler.options.processor \ - org.graalvm.compiler.serviceprovider.processor \ - org.graalvm.compiler.replacements.processor \ - org.graalvm.compiler.replacements.jdk9.test \ + jdk.tools.jaotc.test \ org.graalvm.compiler.api.directives.test \ org.graalvm.compiler.api.test \ org.graalvm.compiler.asm.aarch64.test \ org.graalvm.compiler.asm.amd64.test \ org.graalvm.compiler.asm.sparc.test \ org.graalvm.compiler.asm.test \ + org.graalvm.compiler.core.aarch64.test \ org.graalvm.compiler.core.amd64.test \ - org.graalvm.compiler.core.sparc.test \ + org.graalvm.compiler.core.jdk9.test \ + org.graalvm.compiler.core.match.processor \ org.graalvm.compiler.core.test \ org.graalvm.compiler.debug.test \ org.graalvm.compiler.graph.test \ @@ -477,10 +473,18 @@ jdk.internal.vm.compiler_EXCLUDES += \ org.graalvm.compiler.lir.test \ org.graalvm.compiler.loop.test \ org.graalvm.compiler.microbenchmarks \ + org.graalvm.compiler.nodeinfo.processor \ org.graalvm.compiler.nodes.test \ + org.graalvm.compiler.options.processor \ org.graalvm.compiler.options.test \ org.graalvm.compiler.phases.common.test \ + org.graalvm.compiler.processor \ + org.graalvm.compiler.replacements.jdk12.test \ + org.graalvm.compiler.replacements.jdk9.test \ + org.graalvm.compiler.replacements.jdk9_11.test \ + org.graalvm.compiler.replacements.processor \ org.graalvm.compiler.replacements.test \ + org.graalvm.compiler.serviceprovider.processor \ org.graalvm.compiler.test \ org.graalvm.compiler.virtual.bench \ org.graalvm.micro.benchmarks \ diff --git a/make/test/JtregGraalUnit.gmk b/make/test/JtregGraalUnit.gmk index d31a54726a..9b44c795d3 100644 --- a/make/test/JtregGraalUnit.gmk +++ b/make/test/JtregGraalUnit.gmk @@ -59,6 +59,7 @@ ifeq ($(INCLUDE_GRAAL), true) -Xlint:none \ -processorpath $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar \ --add-exports jdk.unsupported/sun.misc=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \ ### Copy 3rd party libs $(eval $(call SetupCopyFiles, COPY_GRAALUNIT_LIBS, \ @@ -81,6 +82,7 @@ ifeq ($(INCLUDE_GRAAL), true) $(SRC_DIR)/org.graalvm.compiler.asm.test/src \ $(SRC_DIR)/org.graalvm.compiler.core.amd64.test/src \ $(SRC_DIR)/org.graalvm.compiler.core.test/src \ + $(SRC_DIR)/org.graalvm.compiler.core.jdk9.test/src \ $(SRC_DIR)/org.graalvm.compiler.debug.test/src \ $(SRC_DIR)/org.graalvm.compiler.graph.test/src \ $(SRC_DIR)/org.graalvm.compiler.hotspot.amd64.test/src \ @@ -92,6 +94,9 @@ ifeq ($(INCLUDE_GRAAL), true) $(SRC_DIR)/org.graalvm.compiler.nodes.test/src \ $(SRC_DIR)/org.graalvm.compiler.options.test/src \ $(SRC_DIR)/org.graalvm.compiler.phases.common.test/src \ + $(SRC_DIR)/org.graalvm.compiler.replacements.jdk12.test/src \ + $(SRC_DIR)/org.graalvm.compiler.replacements.jdk9.test/src \ + $(SRC_DIR)/org.graalvm.compiler.replacements.jdk9_11.test/src \ $(SRC_DIR)/org.graalvm.compiler.replacements.test/src \ $(SRC_DIR)/org.graalvm.compiler.test/src \ $(SRC_DIR)/org.graalvm.util.test/src \ diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java index 52f7770934..84abc3edeb 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java @@ -33,8 +33,8 @@ import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; -import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -167,7 +167,7 @@ final class AOTBackend { void printCompiledMethod(HotSpotResolvedJavaMethod resolvedMethod, CompilationResult compResult) { // This is really not installing the method. - InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, resolvedMethod, null, compResult), null, null); + InstalledCode installedCode = codeCache.addCode(resolvedMethod, HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, resolvedMethod, null, compResult, graalOptions), null, null); String disassembly = codeCache.disassemble(installedCode); if (disassembly != null) { main.printer.printlnDebug(disassembly); diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java index cd409bb630..1161b8e3fd 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTCompilationTask.java @@ -32,8 +32,8 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.GraalCompilerOptions; import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.debug.DebugContext.Activation; +import org.graalvm.compiler.debug.TTY; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; import org.graalvm.compiler.serviceprovider.GraalServices; @@ -143,7 +143,7 @@ final class AOTCompilationTask implements Runnable, Comparable { aotBackend.printCompiledMethod((HotSpotResolvedJavaMethod) method, compResult); } - result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend())); + result = new CompiledMethodInfo(compResult, new AOTHotSpotResolvedJavaMethod((HotSpotResolvedJavaMethod) method, aotBackend.getBackend(), graalOptions)); } private String getMethodDescription() { diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java index 4471dc9827..d29ed7113c 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTHotSpotResolvedJavaMethod.java @@ -28,6 +28,8 @@ package jdk.tools.jaotc; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; +import org.graalvm.compiler.options.OptionValues; + import jdk.vm.ci.hotspot.HotSpotCompiledCode; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; @@ -35,10 +37,12 @@ final class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo { private final HotSpotResolvedJavaMethod method; private final Backend backend; + private final OptionValues options; - AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend) { + AOTHotSpotResolvedJavaMethod(HotSpotResolvedJavaMethod method, Backend backend, OptionValues options) { this.method = method; this.backend = backend; + this.options = options; } @Override @@ -54,7 +58,7 @@ final class AOTHotSpotResolvedJavaMethod implements JavaMethodInfo { @Override public HotSpotCompiledCode compiledCode(CompilationResult result) { - return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), method, null, result); + return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), method, null, result, options); } } diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java index 531e1e2f90..394beb0de9 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTStub.java @@ -29,6 +29,7 @@ import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.target.Backend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; import org.graalvm.compiler.hotspot.stubs.Stub; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.hotspot.HotSpotCompiledCode; @@ -36,10 +37,12 @@ final class AOTStub implements JavaMethodInfo { private final Stub stub; private final Backend backend; + private OptionValues options; - AOTStub(Stub stub, Backend backend) { + AOTStub(Stub stub, Backend backend, OptionValues options) { this.stub = stub; this.backend = backend; + this.options = options; } @Override @@ -54,7 +57,7 @@ final class AOTStub implements JavaMethodInfo { @Override public HotSpotCompiledCode compiledCode(CompilationResult result) { - return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), null, null, result); + return HotSpotCompiledCodeBuilder.createCompiledCode(backend.getCodeCache(), null, null, result, options); } } diff --git a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java index 09c31f7fef..5dfbf69cc1 100644 --- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java +++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataBuilder.java @@ -30,16 +30,15 @@ import java.util.HashMap; import java.util.List; import java.util.Map.Entry; -import jdk.tools.jaotc.binformat.BinaryContainer; -import jdk.tools.jaotc.binformat.ByteContainer; -import jdk.tools.jaotc.binformat.HeaderContainer; - import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.hotspot.HotSpotHostBackend; import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; import org.graalvm.compiler.hotspot.stubs.Stub; +import jdk.tools.jaotc.binformat.BinaryContainer; +import jdk.tools.jaotc.binformat.ByteContainer; +import jdk.tools.jaotc.binformat.HeaderContainer; import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.hotspot.VMField; @@ -190,7 +189,7 @@ final class DataBuilder { for (Stub stub : foreignCallsProvider.getStubs()) { try (DebugContext.Scope scope = debug.scope("CompileStubs")) { CompilationResult result = stub.getCompilationResult(debug, backend); - CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend)); + CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend, debug.getOptions())); stubs.add(cm); } catch (Throwable e) { throw debug.handle(e); diff --git a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java index ea53556ce0..047981465a 100644 --- a/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java +++ b/src/jdk.internal.vm.compiler.management/share/classes/org.graalvm.compiler.hotspot.management/src/org/graalvm/compiler/hotspot/management/HotSpotGraalManagement.java @@ -150,10 +150,16 @@ public final class HotSpotGraalManagement implements HotSpotGraalManagementRegis */ synchronized void poll() { if (platformMBeanServer == null) { - ArrayList servers = MBeanServerFactory.findMBeanServer(null); - if (!servers.isEmpty()) { - platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); - process(); + try { + ArrayList servers = MBeanServerFactory.findMBeanServer(null); + if (!servers.isEmpty()) { + platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + process(); + } + } catch (SecurityException e) { + // Without permission to find or create the MBeanServer, + // we cannot process any Graal mbeans. + deferred = null; } } else { process(); diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java index 113e3476e3..4beea31edd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapImplTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import java.util.Arrays; @@ -117,7 +133,7 @@ public class EconomicMapImplTest { Assert.assertTrue(set.add(newInteger(0))); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) private static Integer newInteger(int value) { return new Integer(value); } diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java index ad373edc35..10fe8d009c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapLargeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import java.util.Arrays; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java index 5e7b759374..0ba859ab76 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicMapTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import java.util.LinkedHashMap; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java index 68329ff47d..e6cc8a8053 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EconomicSetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import java.util.ArrayList; @@ -145,7 +161,7 @@ public class EconomicSetTest { Assert.assertEquals(newInteger(9), finalList.get(0)); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) private static Integer newInteger(int value) { return new Integer(value); } diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java index 7d15cf7e65..faa5321e71 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/EquivalenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import jdk.internal.vm.compiler.collections.Equivalence; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java index af4f3eb6bf..23324e78ef 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections.test/src/jdk/internal/vm/compiler/collections/test/PairTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections.test; import jdk.internal.vm.compiler.collections.Pair; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java index a3fc1edc7f..c7563fe421 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; import java.util.Iterator; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java index 0149027272..59560a250a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicMapImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; import java.util.Iterator; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java index e5c87267e1..2ab53ed67a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/EconomicSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; import java.util.Iterator; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java index 526d26a0d5..6ffa9b765c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Equivalence.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java index 26f6982a32..3b65bd068b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/MapCursor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java index da4e9da9de..6390889591 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/Pair.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; import java.util.Objects; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java index 7629a2b76f..9f309b9404 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java index 35590198a3..23d721dd8a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableEconomicSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java index 087b6ec176..e89dddc9fd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/UnmodifiableMapCursor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java index 7d089c936e..061262bd1c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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,4 +35,20 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.collections; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java index 21011446ec..8513a2e735 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/ComparableWord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java index 52aab7a139..471bcbafb0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/LocationIdentity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; // JaCoCo Exclude diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java index 459fefae92..1f748c2c6a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/Pointer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** @@ -959,7 +975,8 @@ public interface Pointer extends UnsignedWord, PointerBase { void writeObject(WordBase offset, Object val); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -967,17 +984,19 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ int compareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -985,17 +1004,19 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ long compareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1003,17 +1024,19 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ T compareAndSwapWord(WordBase offset, T expectedValue, T newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1021,17 +1044,19 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ Object compareAndSwapObject(WordBase offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1039,8 +1064,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1050,7 +1075,8 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapInt(WordBase offset, int expectedValue, int newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1058,8 +1084,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1069,7 +1095,8 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapLong(WordBase offset, long expectedValue, long newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1077,8 +1104,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1088,7 +1115,8 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapWord(WordBase offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. *

* The offset is always treated as a {@link SignedWord} value. However, the static type is @@ -1096,8 +1124,8 @@ public interface Pointer extends UnsignedWord, PointerBase { * knows that the highest-order bit of the unsigned value is never used). * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1206,68 +1234,77 @@ public interface Pointer extends UnsignedWord, PointerBase { void writeObject(int offset, Object val); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ int compareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ long compareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ T compareAndSwapWord(int offset, T expectedValue, T newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location - * @return The value after the atomic exchange + * @return The value that was read for comparison, which is {@code expectedValue} if the + * exchange was performed. * * @since 1.0 */ Object compareAndSwapObject(int offset, Object expectedValue, Object newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1277,12 +1314,13 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapInt(int offset, int expectedValue, int newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1292,12 +1330,13 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapLong(int offset, long expectedValue, long newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. @@ -1307,12 +1346,13 @@ public interface Pointer extends UnsignedWord, PointerBase { boolean logicCompareAndSwapWord(int offset, WordBase expectedValue, WordBase newValue, LocationIdentity locationIdentity); /** - * Atomically exchanges memory at address {@code (this + offset)}. Both the base address and + * In a single atomic step, compares the memory at address {@code (this + offset)} to the + * expected value, and if equal, exchanges it for the new value. Both the base address and * offset are in bytes. * * @param offset the signed offset for the memory access - * @param expectedValue the expected value of the atomic exchange - * @param newValue the new value of the atomic exchange + * @param expectedValue the expected current value at the memory address + * @param newValue the new value for the atomic exchange * @param locationIdentity the identity of the memory location * @return {@code true} if successful. False return indicates that the actual value was not * equal to the expected value. diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java index baa6478da0..3f2fb7ca69 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/PointerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java index 98b8c86f46..04e0548d80 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/SignedWord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java index 1bbbd5b7a4..7010f69fa1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/UnsignedWord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java index 24ee4fc7ba..92f4ca932f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java index ed0a271e6b..5209488873 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/WordFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; import jdk.internal.vm.compiler.word.impl.WordBoxFactory; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java index a3350fae8c..9b976646ff 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordBoxFactory.java @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word.impl; import jdk.internal.vm.compiler.word.WordBase; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java index 9c59b2067e..0655e9b93c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOpcode.java @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word.impl; /** diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java index 08988b70fc..8a5d2594b3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/impl/WordFactoryOperation.java @@ -22,6 +22,22 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word.impl; import java.lang.annotation.ElementType; diff --git a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java index da12985d47..434fe35614 100644 --- a/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java +++ b/src/jdk.internal.vm.compiler/share/classes/jdk.internal.vm.compiler.word/src/jdk/internal/vm/compiler/word/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -33,4 +33,20 @@ */ + + + + + + + + + + + + + + + + package jdk.internal.vm.compiler.word; \ No newline at end of file diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java index 973f8811e1..a8ccae24c9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java @@ -2775,7 +2775,8 @@ public abstract class AArch64Assembler extends Assembler { WFE(0x2), WFI(0x3), SEV(0x4), - SEVL(0x5); + SEVL(0x5), + CSDB(0x14); private final int encoding; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java index 0f5d891c05..ce8ed45295 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java @@ -1475,6 +1475,14 @@ public class AArch64MacroAssembler extends AArch64Assembler { super.hint(SystemHint.NOP); } + /** + * Consumption of Speculative Data Barrier. This is a memory barrier that controls speculative + * execution and data value prediction. + */ + public void csdb() { + super.hint(SystemHint.CSDB); + } + /** * Same as {@link #nop()}. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java index 85ff283fc3..511ab38484 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java @@ -43,6 +43,7 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NEG; import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp.NOT; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.B0; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.Z0; +import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.EVEXPrefixConfig.Z1; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.BYTE; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.DWORD; import static org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize.PD; @@ -1023,7 +1024,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src) { assert assertion.check((AMD64) asm.target.arch, size, dst, null, src); assert op != 0x1A || op != 0x5A; - asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w); + asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src); } @@ -1084,7 +1085,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address src) { assert assertion.check((AMD64) asm.target.arch, size, dst, null, null); - asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w); + asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src, 0); } @@ -1123,14 +1124,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, AMD64Address dst, Register src) { assert assertion.check((AMD64) asm.target.arch, size, src, null, null); - asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w); + asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w, false); asm.emitByte(opReverse); asm.emitOperandHelper(src, dst, 0); } public void emitReverse(AMD64Assembler asm, AVXSize size, Register dst, Register src) { assert assertion.check((AMD64) asm.target.arch, size, src, null, dst); - asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w); + asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w, false); asm.emitByte(opReverse); asm.emitModRM(src, dst); } @@ -1158,7 +1159,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, dst, null, src); - asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w); + asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src); asm.emitByte(imm8); @@ -1166,7 +1167,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address src, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, dst, null, null); - asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w); + asm.vexPrefix(dst, Register.None, src, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src, 1); asm.emitByte(imm8); @@ -1193,7 +1194,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, src, null, dst); - asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w); + asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(src, dst); asm.emitByte(imm8); @@ -1201,7 +1202,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, AMD64Address dst, Register src, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, src, null, null); - asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w); + asm.vexPrefix(src, Register.None, dst, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(src, dst, 1); asm.emitByte(imm8); @@ -1224,7 +1225,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register mask, Register src1, Register src2) { assert assertion.check((AMD64) asm.target.arch, size, dst, mask, src1, src2); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(mask.encoding() << 4); @@ -1232,7 +1233,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register mask, Register src1, AMD64Address src2) { assert assertion.check((AMD64) asm.target.arch, size, dst, mask, src1, null); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0); asm.emitByte(mask.encoding() << 4); @@ -1320,20 +1321,20 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src2); } public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0); } } - public static final class VexGeneralPurposeRVMOp extends VexOp { + public static final class VexGeneralPurposeRVMOp extends VexRVMOp { // @formatter:off public static final VexGeneralPurposeRVMOp ANDN = new VexGeneralPurposeRVMOp("ANDN", P_, M_0F38, WIG, 0xF2, VEXOpAssertion.BMI1); public static final VexGeneralPurposeRVMOp MULX = new VexGeneralPurposeRVMOp("MULX", P_F2, M_0F38, WIG, 0xF6, VEXOpAssertion.BMI2); @@ -1345,18 +1346,20 @@ public class AMD64Assembler extends AMD64BaseAssembler { super(opcode, pp, mmmmm, w, op, assertion); } + @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src1, src2, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); asm.emitByte(op); asm.emitModRM(dst, src2); } + @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src1, null, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 0); } @@ -1378,7 +1381,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src2, src1, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; - asm.vexPrefix(dst, src2, src1, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1); + asm.vexPrefix(dst, src2, src1, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); asm.emitByte(op); asm.emitModRM(dst, src1); } @@ -1386,12 +1389,42 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address src1, Register src2) { assert assertion.check((AMD64) asm.target.arch, LZ, dst, src2, null, null); assert size == AVXSize.DWORD || size == AVXSize.QWORD; - asm.vexPrefix(dst, src2, src1, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1); + asm.vexPrefix(dst, src2, src1, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); asm.emitByte(op); asm.emitOperandHelper(dst, src1, 0); } } + public static final class VexGeneralPurposeRMOp extends VexRMOp { + // @formatter:off + public static final VexGeneralPurposeRMOp BLSI = new VexGeneralPurposeRMOp("BLSI", P_, M_0F38, WIG, 0xF3, 3, VEXOpAssertion.BMI1); + public static final VexGeneralPurposeRMOp BLSMSK = new VexGeneralPurposeRMOp("BLSMSK", P_, M_0F38, WIG, 0xF3, 2, VEXOpAssertion.BMI1); + public static final VexGeneralPurposeRMOp BLSR = new VexGeneralPurposeRMOp("BLSR", P_, M_0F38, WIG, 0xF3, 1, VEXOpAssertion.BMI1); + // @formatter:on + private final int ext; + + private VexGeneralPurposeRMOp(String opcode, int pp, int mmmmm, int w, int op, int ext, VEXOpAssertion assertion) { + super(opcode, pp, mmmmm, w, op, assertion); + this.ext = ext; + } + + @Override + public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src) { + assert assertion.check((AMD64) asm.target.arch, size, dst, null, null); + asm.vexPrefix(AMD64.cpuRegisters[ext], dst, src, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); + asm.emitByte(op); + asm.emitModRM(ext, src); + } + + @Override + public void emit(AMD64Assembler asm, AVXSize size, Register dst, AMD64Address src) { + assert assertion.check((AMD64) asm.target.arch, size, dst, null, null); + asm.vexPrefix(AMD64.cpuRegisters[ext], dst, src, size, pp, mmmmm, size == AVXSize.DWORD ? W0 : W1, false); + asm.emitByte(op); + asm.emitOperandHelper(ext, src, 0); + } + } + /** * VEX-encoded shift instructions with an operand order of either RVM or VMI. */ @@ -1419,7 +1452,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { @Override public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, null, dst, src); - asm.vexPrefix(null, dst, src, size, pp, mmmmm, w); + asm.vexPrefix(null, dst, src, size, pp, mmmmm, w, false); asm.emitByte(immOp); asm.emitModRM(r, src); asm.emitByte(imm8); @@ -1447,14 +1480,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register mask, AMD64Address src) { assert assertion.check((AMD64) asm.target.arch, size, dst, mask, null); - asm.vexPrefix(dst, mask, src, size, pp, mmmmm, w); + asm.vexPrefix(dst, mask, src, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src, 0); } public void emit(AMD64Assembler asm, AVXSize size, AMD64Address dst, Register mask, Register src) { assert assertion.check((AMD64) asm.target.arch, size, src, mask, null); - asm.vexPrefix(src, mask, dst, size, pp, mmmmm, w); + asm.vexPrefix(src, mask, dst, size, pp, mmmmm, w, false); asm.emitByte(opReverse); asm.emitOperandHelper(src, dst, 0); } @@ -1482,7 +1515,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2); assert (imm8 & 0xFF) == imm8; - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(imm8); @@ -1491,7 +1524,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, int imm8) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null); assert (imm8 & 0xFF) == imm8; - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 1); asm.emitByte(imm8); @@ -1595,7 +1628,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, Register src2, Predicate p) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, src2); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitModRM(dst, src2); asm.emitByte(p.imm8); @@ -1603,7 +1636,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public void emit(AMD64Assembler asm, AVXSize size, Register dst, Register src1, AMD64Address src2, Predicate p) { assert assertion.check((AMD64) asm.target.arch, size, dst, src1, null); - asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w); + asm.vexPrefix(dst, src1, src2, size, pp, mmmmm, w, false); asm.emitByte(op); asm.emitOperandHelper(dst, src2, 1); asm.emitByte(p.imm8); @@ -1943,14 +1976,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void movapd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F, false); emitByte(0x28); emitModRM(dst, src); } public final void movaps(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PS, P_0F, false); emitByte(0x28); emitModRM(dst, src); @@ -1964,7 +1997,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void movb(AMD64Address dst, Register src) { - assert src.getRegisterCategory().equals(CPU) : "must have byte register"; + assert inRC(CPU, src) : "must have byte register"; prefixb(dst, src); emitByte(0x88); emitOperandHelper(src, dst, 0); @@ -2027,14 +2060,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { * {@link AMD64MacroAssembler#movflt(Register, Register)}. */ public final void movlpd(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0x12); emitOperandHelper(dst, src, 0); } public final void movlhps(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, src, src, PS, P_0F, false); emitByte(0x16); emitModRM(dst, src); @@ -2044,28 +2077,39 @@ public class AMD64Assembler extends AMD64BaseAssembler { movq(dst, src, false); } - public final void movq(Register dst, AMD64Address src, boolean wide) { - if (dst.getRegisterCategory().equals(XMM)) { + public final void movq(Register dst, AMD64Address src, boolean force4BytesDisplacement) { + if (inRC(XMM, dst)) { + // Insn: MOVQ xmm, r/m64 + // Code: F3 0F 7E /r + // An alternative instruction would be 66 REX.W 0F 6E /r. We prefer the REX.W free + // format, because it would allow us to emit 2-bytes-prefixed vex-encoding instruction + // when applicable. simdPrefix(dst, Register.None, src, SS, P_0F, false); emitByte(0x7E); - emitOperandHelper(dst, src, wide, 0); + emitOperandHelper(dst, src, force4BytesDisplacement, 0); } else { // gpr version of movq prefixq(src, dst); emitByte(0x8B); - emitOperandHelper(dst, src, wide, 0); + emitOperandHelper(dst, src, force4BytesDisplacement, 0); } } public final void movq(Register dst, Register src) { + assert inRC(CPU, dst) && inRC(CPU, src); prefixq(dst, src); emitByte(0x8B); emitModRM(dst, src); } public final void movq(AMD64Address dst, Register src) { - if (src.getRegisterCategory().equals(XMM)) { - simdPrefix(src, Register.None, dst, PD, P_0F, true); + if (inRC(XMM, src)) { + // Insn: MOVQ r/m64, xmm + // Code: 66 0F D6 /r + // An alternative instruction would be 66 REX.W 0F 7E /r. We prefer the REX.W free + // format, because it would allow us to emit 2-bytes-prefixed vex-encoding instruction + // when applicable. + simdPrefix(src, Register.None, dst, PD, P_0F, false); emitByte(0xD6); emitOperandHelper(src, dst, 0); } else { @@ -2426,6 +2470,18 @@ public class AMD64Assembler extends AMD64BaseAssembler { OR.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32); } + // Insn: VPACKUSWB xmm1, xmm2, xmm3/m128 + // ----- + // Insn: VPACKUSWB xmm1, xmm1, xmm2 + + public final void packuswb(Register dst, Register src) { + assert inRC(XMM, dst) && inRC(XMM, src); + // Code: VEX.NDS.128.66.0F.WIG 67 /r + simdPrefix(dst, dst, src, PD, P_0F, false); + emitByte(0x67); + emitModRM(dst, src); + } + public final void pop(Register dst) { prefix(dst); emitByte(0x58 + encode(dst)); @@ -2437,7 +2493,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void ptest(Register dst, Register src) { assert supports(CPUFeature.SSE4_1); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F38, false); emitByte(0x17); emitModRM(dst, src); @@ -2445,7 +2501,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pcmpeqb(Register dst, Register src) { assert supports(CPUFeature.SSE2); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0x74); emitModRM(dst, src); @@ -2453,15 +2509,23 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pcmpeqw(Register dst, Register src) { assert supports(CPUFeature.SSE2); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0x75); emitModRM(dst, src); } + public final void pcmpeqd(Register dst, Register src) { + assert supports(CPUFeature.SSE2); + assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + simdPrefix(dst, dst, src, PD, P_0F, false); + emitByte(0x76); + emitModRM(dst, src); + } + public final void pcmpestri(Register dst, AMD64Address src, int imm8) { assert supports(CPUFeature.SSE4_2); - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); simdPrefix(dst, Register.None, src, PD, P_0F3A, false); emitByte(0x61); emitOperandHelper(dst, src, 0); @@ -2470,7 +2534,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pcmpestri(Register dst, Register src, int imm8) { assert supports(CPUFeature.SSE4_2); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F3A, false); emitByte(0x61); emitModRM(dst, src); @@ -2479,21 +2543,30 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pmovmskb(Register dst, Register src) { assert supports(CPUFeature.SSE2); - assert dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(XMM); + assert inRC(CPU, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F, false); emitByte(0xD7); emitModRM(dst, src); } + // Insn: VPMOVZXBW xmm1, xmm2/m64 + public final void pmovzxbw(Register dst, AMD64Address src) { - assert supports(CPUFeature.SSE4_2); - assert dst.getRegisterCategory().equals(XMM); - // XXX legacy_mode should be: _legacy_mode_bw + assert supports(CPUFeature.SSE4_1); + assert inRC(XMM, dst); simdPrefix(dst, Register.None, src, PD, P_0F38, false); emitByte(0x30); emitOperandHelper(dst, src, 0); } + public final void pmovzxbw(Register dst, Register src) { + assert supports(CPUFeature.SSE4_1); + assert inRC(XMM, dst) && inRC(XMM, src); + simdPrefix(dst, Register.None, src, PD, P_0F38, false); + emitByte(0x30); + emitModRM(dst, src); + } + public final void push(Register src) { prefix(src); emitByte(0x50 + encode(src)); @@ -2504,21 +2577,21 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void paddd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xFE); emitModRM(dst, src); } public final void paddq(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xD4); emitModRM(dst, src); } public final void pextrw(Register dst, Register src, int imm8) { - assert dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(XMM); + assert inRC(CPU, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F, false); emitByte(0xC5); emitModRM(dst, src); @@ -2526,7 +2599,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void pinsrw(Register dst, Register src, int imm8) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(CPU); + assert inRC(XMM, dst) && inRC(CPU, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xC4); emitModRM(dst, src); @@ -2534,21 +2607,21 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void por(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xEB); emitModRM(dst, src); } public final void pand(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xDB); emitModRM(dst, src); } public final void pxor(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xEF); emitModRM(dst, src); @@ -2556,7 +2629,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pslld(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); // XMM6 is for /6 encoding: 66 0F 72 /6 ib simdPrefix(AMD64.xmm6, dst, dst, PD, P_0F, false); emitByte(0x72); @@ -2565,7 +2638,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void psllq(Register dst, Register shift) { - assert dst.getRegisterCategory().equals(XMM) && shift.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, shift); simdPrefix(dst, dst, shift, PD, P_0F, false); emitByte(0xF3); emitModRM(dst, shift); @@ -2573,7 +2646,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void psllq(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); // XMM6 is for /6 encoding: 66 0F 73 /6 ib simdPrefix(AMD64.xmm6, dst, dst, PD, P_0F, false); emitByte(0x73); @@ -2583,7 +2656,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void psrad(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); // XMM4 is for /4 encoding: 66 0F 72 /4 ib simdPrefix(AMD64.xmm4, dst, dst, PD, P_0F, false); emitByte(0x72); @@ -2593,7 +2666,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void psrld(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); // XMM2 is for /2 encoding: 66 0F 72 /2 ib simdPrefix(AMD64.xmm2, dst, dst, PD, P_0F, false); emitByte(0x72); @@ -2603,7 +2676,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void psrlq(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); // XMM2 is for /2 encoding: 66 0F 73 /2 ib simdPrefix(AMD64.xmm2, dst, dst, PD, P_0F, false); emitByte(0x73); @@ -2613,7 +2686,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void psrldq(Register dst, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); simdPrefix(AMD64.xmm3, dst, dst, PD, P_0F, false); emitByte(0x73); emitModRM(3, dst); @@ -2622,7 +2695,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pshufb(Register dst, Register src) { assert supports(CPUFeature.SSSE3); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F38, false); emitByte(0x00); emitModRM(dst, src); @@ -2631,7 +2704,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pshuflw(Register dst, Register src, int imm8) { assert supports(CPUFeature.SSE2); assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, SD, P_0F, false); emitByte(0x70); emitModRM(dst, src); @@ -2640,7 +2713,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void pshufd(Register dst, Register src, int imm8) { assert isUByte(imm8) : "invalid value"; - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F, false); emitByte(0x70); emitModRM(dst, src); @@ -2648,14 +2721,22 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void psubd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0xFA); emitModRM(dst, src); } + public final void punpcklbw(Register dst, Register src) { + assert supports(CPUFeature.SSE2); + assert inRC(XMM, dst) && inRC(XMM, src); + simdPrefix(dst, dst, src, PD, P_0F, false); + emitByte(0x60); + emitModRM(dst, src); + } + public final void rcpps(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PS, P_0F, false); emitByte(0x53); emitModRM(dst, src); @@ -2703,6 +2784,12 @@ public class AMD64Assembler extends AMD64BaseAssembler { emitModRM(4, dst); } + // Insn: SHLX r32a, r/m32, r32b + + public final void shlxl(Register dst, Register src1, Register src2) { + VexGeneralPurposeRMVOp.SHLX.emit(this, AVXSize.DWORD, dst, src1, src2); + } + public final void shrl(Register dst, int imm8) { assert isShiftCount(imm8 >> 1) : "illegal shift count"; prefix(dst); @@ -2769,14 +2856,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void unpckhpd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0x15); emitModRM(dst, src); } public final void unpcklpd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, dst, src, PD, P_0F, false); emitByte(0x14); emitModRM(dst, src); @@ -2887,7 +2974,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void cvtdq2pd(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, SS, P_0F, false); emitByte(0xE6); emitModRM(dst, src); @@ -2902,14 +2989,14 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void cvttpd2dq(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, PD, P_0F, false); emitByte(0xE6); emitModRM(dst, src); } public final void decq(Register dst) { - // Use two-byte form (one-byte from is a REX prefix in 64-bit mode) + // Use two-byte form (one-byte form is a REX prefix in 64-bit mode) prefixq(dst); emitByte(0xFF); emitModRM(1, dst); @@ -2970,9 +3057,9 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void movdq(Register dst, Register src) { - if (dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(CPU)) { + if (inRC(XMM, dst) && inRC(CPU, src)) { AMD64RMOp.MOVQ.emit(this, QWORD, dst, src); - } else if (src.getRegisterCategory().equals(XMM) && dst.getRegisterCategory().equals(CPU)) { + } else if (inRC(XMM, src) && inRC(CPU, dst)) { AMD64MROp.MOVQ.emit(this, QWORD, dst, src); } else { throw new InternalError("should not reach here"); @@ -2980,9 +3067,9 @@ public class AMD64Assembler extends AMD64BaseAssembler { } public final void movdl(Register dst, Register src) { - if (dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(CPU)) { + if (inRC(XMM, dst) && inRC(CPU, src)) { AMD64RMOp.MOVD.emit(this, DWORD, dst, src); - } else if (src.getRegisterCategory().equals(XMM) && dst.getRegisterCategory().equals(CPU)) { + } else if (inRC(XMM, src) && inRC(CPU, dst)) { AMD64MROp.MOVD.emit(this, DWORD, dst, src); } else { throw new InternalError("should not reach here"); @@ -2995,26 +3082,36 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void movddup(Register dst, Register src) { assert supports(CPUFeature.SSE3); - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, SD, P_0F, false); emitByte(0x12); emitModRM(dst, src); } public final void movdqu(Register dst, AMD64Address src) { - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); simdPrefix(dst, Register.None, src, SS, P_0F, false); emitByte(0x6F); emitOperandHelper(dst, src, 0); } public final void movdqu(Register dst, Register src) { - assert dst.getRegisterCategory().equals(XMM) && src.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst) && inRC(XMM, src); simdPrefix(dst, Register.None, src, SS, P_0F, false); emitByte(0x6F); emitModRM(dst, src); } + // Insn: VMOVDQU xmm2/m128, xmm1 + + public final void movdqu(AMD64Address dst, Register src) { + assert inRC(XMM, src); + // Code: VEX.128.F3.0F.WIG 7F /r + simdPrefix(src, Register.None, dst, SS, P_0F, false); + emitByte(0x7F); + emitOperandHelper(src, dst, 0); + } + public final void movslq(AMD64Address dst, int imm32) { prefixq(dst); emitByte(0xC7); @@ -3195,8 +3292,7 @@ public class AMD64Assembler extends AMD64BaseAssembler { protected final void patchJumpTarget(int branch, int branchTarget) { int op = getByte(branch); assert op == 0xE8 // call - || - op == 0x00 // jump table entry + || op == 0x00 // jump table entry || op == 0xE9 // jmp || op == 0xEB // short jmp || (op & 0xF0) == 0x70 // short jcc @@ -3457,46 +3553,73 @@ public class AMD64Assembler extends AMD64BaseAssembler { VexMoveOp.VMOVDQU.emit(this, AVXSize.YMM, dst, src); } + public final void vmovdqu(AMD64Address dst, Register src) { + assert inRC(XMM, src); + VexMoveOp.VMOVDQU.emit(this, AVXSize.YMM, dst, src); + } + public final void vpmovzxbw(Register dst, AMD64Address src) { + assert supports(CPUFeature.AVX2); VexRMOp.VPMOVZXBW.emit(this, AVXSize.YMM, dst, src); } public final void vzeroupper() { - emitVEX(L128, P_, M_0F, W0, 0, 0); + emitVEX(L128, P_, M_0F, W0, 0, 0, true); emitByte(0x77); } + // Insn: KORTESTD k1, k2 + // This instruction produces ZF or CF flags - public final void kortestq(Register src1, Register src2) { + public final void kortestd(Register src1, Register src2) { assert supports(CPUFeature.AVX512BW); - assert src1.getRegisterCategory().equals(MASK) && src2.getRegisterCategory().equals(MASK); - vexPrefix(src1, Register.None, src2, AVXSize.XMM, P_, M_0F, W1); + assert inRC(MASK, src1) && inRC(MASK, src2); + // Code: VEX.L0.66.0F.W1 98 /r + vexPrefix(src1, Register.None, src2, AVXSize.XMM, P_66, M_0F, W1, true); emitByte(0x98); emitModRM(src1, src2); } - public final void kmovq(Register dst, Register src) { - assert supports(CPUFeature.AVX512BW); - assert dst.getRegisterCategory().equals(MASK) || dst.getRegisterCategory().equals(CPU); - assert src.getRegisterCategory().equals(MASK) || src.getRegisterCategory().equals(CPU); - assert !(dst.getRegisterCategory().equals(CPU) && src.getRegisterCategory().equals(CPU)); + // Insn: KORTESTQ k1, k2 - if (dst.getRegisterCategory().equals(MASK)) { - if (src.getRegisterCategory().equals(MASK)) { - // kmovq(KRegister dst, KRegister src) - vexPrefix(dst, Register.None, src, AVXSize.XMM, P_, M_0F, W1); + // This instruction produces ZF or CF flags + public final void kortestq(Register src1, Register src2) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, src1) && inRC(MASK, src2); + // Code: VEX.L0.0F.W1 98 /r + vexPrefix(src1, Register.None, src2, AVXSize.XMM, P_, M_0F, W1, true); + emitByte(0x98); + emitModRM(src1, src2); + } + + public final void kmovd(Register dst, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, dst) || inRC(CPU, dst); + assert inRC(MASK, src) || inRC(CPU, src); + assert !(inRC(CPU, dst) && inRC(CPU, src)); + + if (inRC(MASK, dst)) { + if (inRC(MASK, src)) { + // kmovd(KRegister dst, KRegister src): + // Insn: KMOVD k1, k2/m32 + // Code: VEX.L0.66.0F.W1 90 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_66, M_0F, W1, true); emitByte(0x90); emitModRM(dst, src); } else { - // kmovq(KRegister dst, Register src) - vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W1); + // kmovd(KRegister dst, Register src) + // Insn: KMOVD k1, r32 + // Code: VEX.L0.F2.0F.W0 92 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W0, true); emitByte(0x92); emitModRM(dst, src); } } else { - if (src.getRegisterCategory().equals(MASK)) { - // kmovq(Register dst, KRegister src) - vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W1); + if (inRC(MASK, src)) { + // kmovd(Register dst, KRegister src) + // Insn: KMOVD r32, k1 + // Code: VEX.L0.F2.0F.W0 93 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W0, true); emitByte(0x93); emitModRM(dst, src); } else { @@ -3505,17 +3628,67 @@ public class AMD64Assembler extends AMD64BaseAssembler { } } + public final void kmovq(Register dst, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, dst) || inRC(CPU, dst); + assert inRC(MASK, src) || inRC(CPU, src); + assert !(inRC(CPU, dst) && inRC(CPU, src)); + + if (inRC(MASK, dst)) { + if (inRC(MASK, src)) { + // kmovq(KRegister dst, KRegister src): + // Insn: KMOVQ k1, k2/m64 + // Code: VEX.L0.0F.W1 90 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_, M_0F, W1, true); + emitByte(0x90); + emitModRM(dst, src); + } else { + // kmovq(KRegister dst, Register src) + // Insn: KMOVQ k1, r64 + // Code: VEX.L0.F2.0F.W1 92 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W1, true); + emitByte(0x92); + emitModRM(dst, src); + } + } else { + if (inRC(MASK, src)) { + // kmovq(Register dst, KRegister src) + // Insn: KMOVQ r64, k1 + // Code: VEX.L0.F2.0F.W1 93 /r + vexPrefix(dst, Register.None, src, AVXSize.XMM, P_F2, M_0F, W1, true); + emitByte(0x93); + emitModRM(dst, src); + } else { + throw GraalError.shouldNotReachHere(); + } + } + } + + // Insn: KTESTD k1, k2 + + public final void ktestd(Register src1, Register src2) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, src1) && inRC(MASK, src2); + // Code: VEX.L0.66.0F.W1 99 /r + vexPrefix(src1, Register.None, src2, AVXSize.XMM, P_66, M_0F, W1, true); + emitByte(0x99); + emitModRM(src1, src2); + } + public final void evmovdqu64(Register dst, AMD64Address src) { assert supports(CPUFeature.AVX512F); - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); evexPrefix(dst, Register.None, Register.None, src, AVXSize.ZMM, P_F3, M_0F, W1, Z0, B0); emitByte(0x6F); emitEVEXOperandHelper(dst, src, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); } + // Insn: VPMOVZXBW zmm1, m256 + public final void evpmovzxbw(Register dst, AMD64Address src) { assert supports(CPUFeature.AVX512BW); - assert dst.getRegisterCategory().equals(XMM); + assert inRC(XMM, dst); + // Code: EVEX.512.66.0F38.WIG 30 /r evexPrefix(dst, Register.None, Register.None, src, AVXSize.ZMM, P_66, M_0F38, WIG, Z0, B0); emitByte(0x30); emitEVEXOperandHelper(dst, src, 0, EVEXTuple.HVM.getDisp8ScalingFactor(AVXSize.ZMM)); @@ -3523,9 +3696,137 @@ public class AMD64Assembler extends AMD64BaseAssembler { public final void evpcmpeqb(Register kdst, Register nds, AMD64Address src) { assert supports(CPUFeature.AVX512BW); - assert kdst.getRegisterCategory().equals(MASK) && nds.getRegisterCategory().equals(XMM); + assert inRC(MASK, kdst) && inRC(XMM, nds); evexPrefix(kdst, Register.None, nds, src, AVXSize.ZMM, P_66, M_0F, WIG, Z0, B0); emitByte(0x74); emitEVEXOperandHelper(kdst, src, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); } + + // Insn: VMOVDQU16 zmm1 {k1}{z}, zmm2/m512 + // ----- + // Insn: VMOVDQU16 zmm1, m512 + + public final void evmovdqu16(Register dst, AMD64Address src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(XMM, dst); + // Code: EVEX.512.F2.0F.W1 6F /r + evexPrefix(dst, Register.None, Register.None, src, AVXSize.ZMM, P_F2, M_0F, W1, Z0, B0); + emitByte(0x6F); + emitEVEXOperandHelper(dst, src, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VMOVDQU16 zmm1, k1:z, m512 + + public final void evmovdqu16(Register dst, Register mask, AMD64Address src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(XMM, dst) && inRC(MASK, mask); + // Code: EVEX.512.F2.0F.W1 6F /r + evexPrefix(dst, mask, Register.None, src, AVXSize.ZMM, P_F2, M_0F, W1, Z1, B0); + emitByte(0x6F); + emitEVEXOperandHelper(dst, src, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VMOVDQU16 zmm2/m512 {k1}{z}, zmm1 + // ----- + // Insn: VMOVDQU16 m512, zmm1 + + public final void evmovdqu16(AMD64Address dst, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(XMM, src); + // Code: EVEX.512.F2.0F.W1 7F /r + evexPrefix(src, Register.None, Register.None, dst, AVXSize.ZMM, P_F2, M_0F, W1, Z0, B0); + emitByte(0x7F); + emitEVEXOperandHelper(src, dst, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VMOVDQU16 m512, k1, zmm1 + + public final void evmovdqu16(AMD64Address dst, Register mask, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, mask) && inRC(XMM, src); + // Code: EVEX.512.F2.0F.W1 7F /r + evexPrefix(src, mask, Register.None, dst, AVXSize.ZMM, P_F2, M_0F, W1, Z0, B0); + emitByte(0x7F); + emitEVEXOperandHelper(src, dst, 0, EVEXTuple.FVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VPBROADCASTW zmm1 {k1}{z}, reg + // ----- + // Insn: VPBROADCASTW zmm1, reg + + public final void evpbroadcastw(Register dst, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(XMM, dst) && inRC(CPU, src); + // Code: EVEX.512.66.0F38.W0 7B /r + evexPrefix(dst, Register.None, Register.None, src, AVXSize.ZMM, P_66, M_0F38, W0, Z0, B0); + emitByte(0x7B); + emitModRM(dst, src); + } + + // Insn: VPCMPUW k1 {k2}, zmm2, zmm3/m512, imm8 + // ----- + // Insn: VPCMPUW k1, zmm2, zmm3, imm8 + + public final void evpcmpuw(Register kdst, Register nds, Register src, int vcc) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, kdst) && inRC(XMM, nds) && inRC(XMM, src); + // Code: EVEX.NDS.512.66.0F3A.W1 3E /r ib + evexPrefix(kdst, Register.None, nds, src, AVXSize.ZMM, P_66, M_0F3A, W1, Z0, B0); + emitByte(0x3E); + emitModRM(kdst, src); + emitByte(vcc); + } + + // Insn: VPCMPUW k1 {k2}, zmm2, zmm3/m512, imm8 + // ----- + // Insn: VPCMPUW k1, k2, zmm2, zmm3, imm8 + + public final void evpcmpuw(Register kdst, Register mask, Register nds, Register src, int vcc) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, kdst) && inRC(MASK, mask); + assert inRC(XMM, nds) && inRC(XMM, src); + // Code: EVEX.NDS.512.66.0F3A.W1 3E /r ib + evexPrefix(kdst, mask, nds, src, AVXSize.ZMM, P_66, M_0F3A, W1, Z0, B0); + emitByte(0x3E); + emitModRM(kdst, src); + emitByte(vcc); + } + + // Insn: VPMOVWB ymm1/m256 {k1}{z}, zmm2 + // ----- + // Insn: VPMOVWB m256, zmm2 + + public final void evpmovwb(AMD64Address dst, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(XMM, src); + // Code: EVEX.512.F3.0F38.W0 30 /r + evexPrefix(src, Register.None, Register.None, dst, AVXSize.ZMM, P_F3, M_0F38, W0, Z0, B0); + emitByte(0x30); + emitEVEXOperandHelper(src, dst, 0, EVEXTuple.HVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VPMOVWB m256, k1, zmm2 + + public final void evpmovwb(AMD64Address dst, Register mask, Register src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, mask) && inRC(XMM, src); + // Code: EVEX.512.F3.0F38.W0 30 /r + evexPrefix(src, mask, Register.None, dst, AVXSize.ZMM, P_F3, M_0F38, W0, Z0, B0); + emitByte(0x30); + emitEVEXOperandHelper(src, dst, 0, EVEXTuple.HVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + + // Insn: VPMOVZXBW zmm1 {k1}{z}, ymm2/m256 + // ----- + // Insn: VPMOVZXBW zmm1, k1, m256 + + public final void evpmovzxbw(Register dst, Register mask, AMD64Address src) { + assert supports(CPUFeature.AVX512BW); + assert inRC(MASK, mask) && inRC(XMM, dst); + // Code: EVEX.512.66.0F38.WIG 30 /r + evexPrefix(dst, mask, Register.None, src, AVXSize.ZMM, P_66, M_0F38, WIG, Z0, B0); + emitByte(0x30); + emitEVEXOperandHelper(dst, src, 0, EVEXTuple.HVM.getDisp8ScalingFactor(AVXSize.ZMM)); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java index e7ac25a746..ae520e770b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64BaseAssembler.java @@ -59,6 +59,7 @@ import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.Register.RegisterCategory; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.PlatformKind; @@ -269,8 +270,12 @@ public abstract class AMD64BaseAssembler extends Assembler { return ((AMD64) target.arch).getFeatures().contains(feature); } + protected static boolean inRC(RegisterCategory rc, Register r) { + return r.getRegisterCategory().equals(rc); + } + protected static int encode(Register r) { - assert r.encoding >= 0 && (r.getRegisterCategory().equals(XMM) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding; + assert r.encoding >= 0 && (inRC(XMM, r) ? r.encoding < 32 : r.encoding < 16) : "encoding out of range: " + r.encoding; return r.encoding & 0x7; } @@ -296,6 +301,10 @@ public abstract class AMD64BaseAssembler extends Assembler { private static final int REXWRB = 0x4D; private static final int REXWRX = 0x4E; private static final int REXWRXB = 0x4F; + + private static final int VEX2 = 0xC5; + private static final int VEX3 = 0xC4; + private static final int EVEX = 0x62; } protected final void rexw() { @@ -797,12 +806,17 @@ public abstract class AMD64BaseAssembler extends Assembler { @Override public void simdPrefix(Register reg, Register nds, AMD64Address rm, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) { - emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0); + assert reg.encoding < 16 : "encoding out of range: " + reg.encoding; + assert nds.encoding < 16 : "encoding out of range: " + nds.encoding; + emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(reg, rm), nds.isValid() ? nds.encoding : 0, true); } @Override public void simdPrefix(Register dst, Register nds, Register src, int sizePrefix, int opcodeEscapePrefix, boolean isRexW) { - emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0); + assert dst.encoding < 16 : "encoding out of range: " + dst.encoding; + assert src.encoding < 16 : "encoding out of range: " + src.encoding; + assert nds.encoding < 16 : "encoding out of range: " + nds.encoding; + emitVEX(L128, sizePrefixToPP(sizePrefix), opcodeEscapePrefixToMMMMM(opcodeEscapePrefix), isRexW ? W1 : W0, getRXB(dst, src), nds.isValid() ? nds.encoding : 0, true); } } @@ -822,6 +836,46 @@ public abstract class AMD64BaseAssembler extends Assembler { simdEncoder.simdPrefix(dst, nds, src, size.sizePrefix, opcodeEscapePrefix, isRexW); } + // @formatter:off + // + // Instruction Format and VEX illustrated below (optional []): + // + // #of bytes: 2,3 1 1 1 1,2,4 1 + // [Prefixes] VEX OpCode ModR/M [SIB] [Disp8*N] [Immediate] + // [Disp16,32] + // + // VEX: 0xC4 | P1 | P2 + // + // 7 6 5 4 3 2 1 0 + // P1 R X B m m m m m P[ 7:0] + // P2 W v v v v L p p P[15:8] + // + // VEX: 0xC5 | B1 + // + // 7 6 5 4 3 2 1 0 + // P1 R v v v v L p p P[7:0] + // + // Figure. Bit Field Layout of the VEX Prefix + // + // Table. VEX Prefix Bit Field Functional Grouping + // + // Notation Bit field Group Position Comment + // ---------- ------------------------- -------- ------------------- + // VEX.RXB Next-8 register specifier P[7:5] Combine with ModR/M.reg, ModR/M.rm (base, index/vidx). + // VEX.R REX.R inverse P[7] Combine with EVEX.R and ModR/M.reg. + // VEX.X REX.X inverse P[6] Combine with EVEX.B and ModR/M.rm, when SIB/VSIB absent. + // VEX.B REX.B inverse P[5] + // VEX.mmmmmm 0F, 0F_38, 0F_3A encoding P[4:0] b01/0x0F, b10/0F_38, b11/0F_3A (all other reserved) + // + // VEX.W Opcode specific P[15] + // VEX.vvvv A register specifier P[14:11] In inverse form, b1111 if not used. + // P[6:3] + // VEX.L Vector length/RC P[10] b0/scalar or 128b vec, b1/256b vec. + // P[2] + // VEX.pp Compressed legacy prefix P[9:8] b00/None, b01/0x66, b10/0xF3, b11/0xF2 + // P[1:0] + // @formatter:on + /** * Low-level function to encode and emit the VEX prefix. *

@@ -846,8 +900,8 @@ public abstract class AMD64BaseAssembler extends Assembler { * This function automatically chooses the 2 or 3 byte encoding, based on the XBW flags and the * m-mmmm field. */ - protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv) { - assert ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support"; + protected final void emitVEX(int l, int pp, int mmmmm, int w, int rxb, int vvvv, boolean checkAVX) { + assert !checkAVX || ((AMD64) target.arch).getFeatures().contains(CPUFeature.AVX) : "emitting VEX prefix on a CPU without AVX support"; assert l == L128 || l == L256 : "invalid value for VEX.L"; assert pp == P_ || pp == P_66 || pp == P_F3 || pp == P_F2 : "invalid value for VEX.pp"; @@ -867,7 +921,7 @@ public abstract class AMD64BaseAssembler extends Assembler { byte2 |= l << 2; byte2 |= pp; - emitByte(0xC5); + emitByte(Prefix.VEX2); emitByte(byte2); } else { // 3 byte encoding @@ -881,7 +935,7 @@ public abstract class AMD64BaseAssembler extends Assembler { byte3 |= l << 2; byte3 |= pp; - emitByte(0xC4); + emitByte(Prefix.VEX3); emitByte(byte2); emitByte(byte3); } @@ -900,12 +954,12 @@ public abstract class AMD64BaseAssembler extends Assembler { } } - public final void vexPrefix(Register dst, Register nds, Register src, AVXSize size, int pp, int mmmmm, int w) { - emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0); + public final void vexPrefix(Register dst, Register nds, Register src, AVXSize size, int pp, int mmmmm, int w, boolean checkAVX) { + emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX); } - public final void vexPrefix(Register dst, Register nds, AMD64Address src, AVXSize size, int pp, int mmmmm, int w) { - emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0); + public final void vexPrefix(Register dst, Register nds, AMD64Address src, AVXSize size, int pp, int mmmmm, int w, boolean checkAVX) { + emitVEX(getLFlag(size), pp, mmmmm, w, getRXB(dst, src), nds.isValid() ? nds.encoding() : 0, checkAVX); } protected static final class EVEXPrefixConfig { @@ -986,6 +1040,51 @@ public abstract class AMD64BaseAssembler extends Assembler { } } + // @formatter:off + // + // Instruction Format and EVEX illustrated below (optional []): + // + // #of bytes: 4 1 1 1 1,2,4 1 + // [Prefixes] EVEX OpCode ModR/M [SIB] [Disp8*N] [Immediate] + // [Disp16,32] + // + // The EVEX prefix is a 4-byte prefix, with the first two bytes derived from unused encoding + // form of the 32-bit-mode-only BOUND instruction. The layout of the EVEX prefix is shown in + // the figure below. The first byte must be 0x62, followed by three pay-load bytes, denoted + // as P1, P2, and P3 individually or collectively as P[23:0] (see below). + // + // EVEX: 0x62 | P1 | P2 | P3 + // + // 7 6 5 4 3 2 1 0 + // P1 R X B R' 0 0 m m P[ 7: 0] + // P2 W v v v v 1 p p P[15: 8] + // P3 z L' L b V' a a a P[23:16] + // + // Figure. Bit Field Layout of the EVEX Prefix + // + // Table. EVEX Prefix Bit Field Functional Grouping + // + // Notation Bit field Group Position Comment + // --------- -------------------------- -------- ----------------------- + // EVEX.RXB Next-8 register specifier P[7:5] Combine with ModR/M.reg, ModR/M.rm (base, index/vidx). + // EVEX.X High-16 register specifier P[6] Combine with EVEX.B and ModR/M.rm, when SIB/VSIB absent. + // EVEX.R' High-16 register specifier P[4] Combine with EVEX.R and ModR/M.reg. + // -- Reserved P[3:2] Must be 0. + // EVEX.mm Compressed legacy escape P[1:0] Identical to low two bits of VEX.mmmmm. + // + // EVEX.W Osize promotion/Opcode ext P[15] + // EVEX.vvvv NDS register specifier P[14:11] Same as VEX.vvvv. + // -- Fixed Value P[10] Must be 1. + // EVEX.pp Compressed legacy prefix P[9:8] Identical to VEX.pp. + // + // EVEX.z Zeroing/Merging P[23] + // EVEX.L'L Vector length/RC P[22:21] + // EVEX.b Broadcast/RC/SAE Context P[20] + // EVEX.V' High-16 NDS/VIDX register P[19] Combine with EVEX.vvvv or VSIB when present. + // EVEX.aaa Embedded opmask register P[18:16] + // + // @formatter:on + /** * Low-level function to encode and emit the EVEX prefix. *

@@ -1021,13 +1120,13 @@ public abstract class AMD64BaseAssembler extends Assembler { assert (rxb & 0x07) == rxb : "invalid value for EVEX.RXB"; assert (reg & 0x1F) == reg : "invalid value for EVEX.R'"; - assert (vvvvv & 0x1F) == vvvvv : "invalid value for EVEX.vvvvv"; + assert (vvvvv & 0x1F) == vvvvv : "invalid value for EVEX.V'vvvv"; assert z == Z0 || z == Z1 : "invalid value for EVEX.z"; assert b == B0 || b == B1 : "invalid value for EVEX.b"; assert (aaa & 0x07) == aaa : "invalid value for EVEX.aaa"; - emitByte(0x62); + emitByte(Prefix.EVEX); int p1 = 0; p1 |= ((rxb ^ 0x07) & 0x07) << 5; p1 |= reg < 16 ? 0x10 : 0; @@ -1037,7 +1136,7 @@ public abstract class AMD64BaseAssembler extends Assembler { int p2 = 0; p2 |= w << 7; p2 |= ((vvvvv ^ 0x0F) & 0x0F) << 3; - p2 |= 0x4; + p2 |= 0x04; p2 |= pp; emitByte(p2); @@ -1050,6 +1149,11 @@ public abstract class AMD64BaseAssembler extends Assembler { emitByte(p3); } + /** + * Get RXB bits for register-register instructions in EVEX-encoding, where ModRM.rm contains a + * register index. The R bit extends the ModRM.reg field and the X and B bits extends the + * ModRM.rm field. + */ private static int getRXBForEVEX(Register reg, Register rm) { int rxb = (reg == null ? 0 : reg.encoding & 0x08) >> 1; rxb |= (rm == null ? 0 : rm.encoding & 0x018) >> 3; @@ -1060,7 +1164,7 @@ public abstract class AMD64BaseAssembler extends Assembler { * Helper method for emitting EVEX prefix in the form of RRRR. */ protected final void evexPrefix(Register dst, Register mask, Register nds, Register src, AVXSize size, int pp, int mm, int w, int z, int b) { - assert !mask.isValid() || mask.getRegisterCategory().equals(MASK); + assert !mask.isValid() || inRC(MASK, mask); emitEVEX(getLFlag(size), pp, mm, w, getRXBForEVEX(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0); } @@ -1071,7 +1175,7 @@ public abstract class AMD64BaseAssembler extends Assembler { * {@link #emitEVEXOperandHelper(Register, AMD64Address, int, int)}. */ protected final void evexPrefix(Register dst, Register mask, Register nds, AMD64Address src, AVXSize size, int pp, int mm, int w, int z, int b) { - assert !mask.isValid() || mask.getRegisterCategory().equals(MASK); + assert !mask.isValid() || inRC(MASK, mask); emitEVEX(getLFlag(size), pp, mm, w, getRXB(dst, src), dst.encoding, nds.isValid() ? nds.encoding() : 0, z, b, mask.isValid() ? mask.encoding : 0); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java index 819d8ba8e3..8757d47848 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64MacroAssembler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,8 @@ package org.graalvm.compiler.asm.amd64; +import static jdk.vm.ci.amd64.AMD64.rbp; +import static jdk.vm.ci.amd64.AMD64.rsp; import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseIncDec; import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearUpper; import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll; @@ -82,6 +84,20 @@ public class AMD64MacroAssembler extends AMD64Assembler { } } + public final void enter(int frameSize) { + if (NumUtil.isUShort(frameSize)) { + // Can use enter instruction only for frame size that fits in 16 bits. + emitByte(0xC8); + emitShort(frameSize); + emitByte(0x00); + } else { + // Fall back to manual sequence. + push(rbp); + movq(rbp, rsp); + decrementq(rsp, frameSize); + } + } + public void incrementq(Register reg, int value) { if (value == Integer.MIN_VALUE) { addq(reg, value); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java index fd54276875..5c21814e3a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java @@ -191,6 +191,10 @@ public class CompilationResult { private StackSlot customStackArea = null; + /** + * A customized name that is unrelated to {@link #compilationId}. Can be null if + * {@link #compilationId} fully describes the compilation. + */ private final String name; private final CompilationIdentifier compilationId; @@ -228,7 +232,7 @@ public class CompilationResult { private boolean isImmutablePIC; public CompilationResult(CompilationIdentifier compilationId) { - this(compilationId, compilationId.toString(CompilationIdentifier.Verbosity.NAME), false); + this(compilationId, null, false); } public CompilationResult(CompilationIdentifier compilationId, String name) { @@ -677,6 +681,10 @@ public class CompilationResult { return unmodifiableList(sourceMapping); } + /** + * Gets the name for this compilation result. This will only be non-null when it provides a + * value unrelated to {@link #getCompilationId()}. + */ public String getName() { return name; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64AddSubShiftTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64AddSubShiftTest.java new file mode 100644 index 0000000000..56f90fc6b7 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64AddSubShiftTest.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Arm Limited and 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.test; + +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; +import org.junit.Assert; +import org.junit.Test; + +public class AArch64AddSubShiftTest extends AArch64MatchRuleTest { + /** + * addSubShift match rule test for add operation with int type. + */ + private static int addLeftShiftInt(int input) { + int output = (input << 5) + input; + output += output << -5; + output += output << 32; + return output; + } + + private static int addRightShiftInt(int input) { + int output = (input >> 5) + input; + output += output >> -5; + output += output >> 32; + return output; + } + + private static int addUnsignedRightShiftInt(int input) { + int output = (input >>> 5) + input; + output += output >>> -5; + output += output >>> 32; + return output; + } + + private static int addShiftInt(int input) { + return addLeftShiftInt(input) + addRightShiftInt(input) + addUnsignedRightShiftInt(input); + } + + /** + * Check whether the addSubShift match rule in AArch64NodeMatchRules does work for add operation + * with int type and check if the expected LIR instructions show up. + */ + @Test + public void testAddShiftInt() { + int expected = addShiftInt(123); + + Result result = executeActual(getResolvedJavaMethod("addShiftInt"), null, 123); + int actual = (int) result.returnValue; + Assert.assertEquals(expected, actual); + + checkLIR(AArch64ArithmeticOp.AddSubShiftOp.class, 6); + } + + /** + * addSubShift match rule test for add operation with long type. + */ + private static long addLeftShiftLong(long input) { + long output = (input << 5) + input; + output += output << -5; + output += output << 64; + return output; + } + + private static long addRightShiftLong(long input) { + long output = (input >> 5) + input; + output += output >> -5; + output += output >> 64; + return output; + } + + private static long addUnsignedRightShiftLong(long input) { + long output = (input >>> 5) + input; + output += output >>> -5; + output += output >>> 64; + return output; + } + + private static long addShiftLong(long input) { + return addLeftShiftLong(input) + addRightShiftLong(input) + addUnsignedRightShiftLong(input); + } + + /** + * Check whether the addSubShift match rule in AArch64NodeMatchRules does work for add operation + * with long type and check if the expected LIR instructions show up. + */ + @Test + public void testAddShiftLong() { + long expected = addShiftLong(1234567); + + Result result = executeActual(getResolvedJavaMethod("addShiftLong"), null, (long) 1234567); + long actual = (long) result.returnValue; + Assert.assertEquals(expected, actual); + + checkLIR(AArch64ArithmeticOp.AddSubShiftOp.class, 6); + } + + /** + * addSubShift match rule test for sub operation with int type. + */ + private static int subLeftShiftInt(int input0, int input1) { + return input0 - (input1 << 5); + } + + private static int subRightShiftInt(int input0, int input1) { + return input0 - (input1 >> 5); + } + + private static int subUnsignedRightShiftInt(int input0, int input1) { + return input0 - (input1 >>> 5); + } + + private static int subShiftInt(int input0, int input1) { + return subLeftShiftInt(input0, input1) + subRightShiftInt(input0, input1) + subUnsignedRightShiftInt(input0, input1); + } + + /** + * Check whether the addSubShift match rule in AArch64NodeMatchRules does work for sub operation + * with int type and check if the expected LIR instructions show up. + */ + @Test + public void testSubShiftInt() { + int expected = subShiftInt(123, 456); + + Result result = executeActual(getResolvedJavaMethod("subShiftInt"), null, 123, 456); + int actual = (int) result.returnValue; + Assert.assertEquals(expected, actual); + + checkLIR(AArch64ArithmeticOp.AddSubShiftOp.class, 3); + } + + /** + * addSubShift match rule test for sub operation with long type. + */ + private static long subLeftShiftLong(long input0, long input1) { + return input0 - (input1 << 5); + } + + private static long subRightShiftLong(long input0, long input1) { + return input0 - (input1 >> 5); + } + + private static long subUnsignedRightShiftLong(long input0, long input1) { + return input0 - (input1 >>> 5); + } + + private static long subShiftLong(long input0, long input1) { + return subLeftShiftLong(input0, input1) + subRightShiftLong(input0, input1) + subUnsignedRightShiftLong(input0, input1); + } + + /** + * Check whether the addSubShift match rule in AArch64NodeMatchRules does work for sub operation + * with long type and check if the expected LIR instructions show up. + */ + @Test + public void testSubShiftLong() { + long expected = subShiftLong(1234567, 123); + + Result result = executeActual(getResolvedJavaMethod("subShiftLong"), null, (long) 1234567, (long) 123); + long actual = (long) result.returnValue; + Assert.assertEquals(expected, actual); + + checkLIR(AArch64ArithmeticOp.AddSubShiftOp.class, 3); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MatchRuleTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MatchRuleTest.java new file mode 100644 index 0000000000..9579911305 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test/AArch64MatchRuleTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Arm Limited and 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.test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.code.TargetDescription; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.lir.LIR; +import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; +import org.graalvm.compiler.lir.gen.LIRGenerationResult; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase; +import org.graalvm.compiler.options.OptionValues; +import org.junit.Assert; +import org.junit.Before; + +import static org.junit.Assume.assumeTrue; + +public abstract class AArch64MatchRuleTest extends GraalCompilerTest { + private LIR lir; + + @Before + public void checkAArch64() { + assumeTrue("skipping AArch64 specific test", getTarget().arch instanceof AArch64); + } + + @Override + protected LIRSuites createLIRSuites(OptionValues options) { + LIRSuites suites = super.createLIRSuites(options); + suites.getPreAllocationOptimizationStage().appendPhase(new CheckPhase()); + return suites; + } + + private class CheckPhase extends LIRPhase { + @Override + protected void run(TargetDescription target, LIRGenerationResult lirGenRes, + PreAllocationOptimizationPhase.PreAllocationOptimizationContext context) { + lir = lirGenRes.getLIR(); + } + } + + protected void checkLIR(Class op, int expected) { + int actualOpNum = 0; + for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) { + if (ins.getClass() == op) { + actualOpNum++; + } + } + Assert.assertEquals(expected, actualOpNum); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java index 880246d9ba..df7deb02ce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java @@ -201,6 +201,16 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem return result; } + public Value emitAddSubShift(AArch64ArithmeticOp op, Value a, Value b, AArch64MacroAssembler.ShiftType shiftType, int shiftAmount) { + assert isNumericInteger(a.getPlatformKind()); + assert isNumericInteger(b.getPlatformKind()); + Variable result = getLIRGen().newVariable(LIRKind.combine(a, b)); + AllocatableValue x = moveSp(asAllocatable(a)); + AllocatableValue y = moveSp(asAllocatable(b)); + getLIRGen().append(new AArch64ArithmeticOp.AddSubShiftOp(op, result, x, y, shiftType, shiftAmount)); + return result; + } + private static PlatformKind getFloatConvertResultKind(FloatConvert op) { switch (op) { case F2I: diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java index 224fcfdf5a..e3cc4ace03 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java @@ -61,6 +61,7 @@ import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp; import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndWriteOp; import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp; import org.graalvm.compiler.lir.aarch64.AArch64PauseOp; +import org.graalvm.compiler.lir.aarch64.AArch64SpeculativeBarrier; import org.graalvm.compiler.lir.gen.LIRGenerationResult; import org.graalvm.compiler.lir.gen.LIRGenerator; import org.graalvm.compiler.phases.util.Providers; @@ -465,9 +466,9 @@ public abstract class AArch64LIRGenerator extends LIRGenerator { } @Override - public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers) { Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD)); - append(new AArch64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); + append(new AArch64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length), directPointers)); return result; } @@ -513,4 +514,9 @@ public abstract class AArch64LIRGenerator extends LIRGenerator { } public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args); + + @Override + public void emitSpeculationFence() { + append(new AArch64SpeculativeBarrier()); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java index e0395ffe50..251e2c3982 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64MoveFactory.java @@ -34,6 +34,7 @@ import org.graalvm.compiler.core.common.type.DataPointerConstant; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRInstruction; import org.graalvm.compiler.lir.aarch64.AArch64AddressValue; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; import org.graalvm.compiler.lir.aarch64.AArch64Move; import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadAddressOp; import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory; @@ -69,7 +70,7 @@ public class AArch64MoveFactory implements MoveFactory { } @Override - public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + public AArch64LIRInstruction createLoad(AllocatableValue dst, Constant src) { if (src instanceof JavaConstant) { JavaConstant javaConstant = (JavaConstant) src; if (canInlineConstant(javaConstant)) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java index 96ec6edd96..13d0979eb5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64NodeMatchRules.java @@ -25,11 +25,22 @@ package org.graalvm.compiler.core.aarch64; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.core.gen.NodeMatchRules; +import org.graalvm.compiler.core.match.ComplexMatchResult; +import org.graalvm.compiler.core.match.MatchRule; import org.graalvm.compiler.lir.LIRFrameState; +import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.DeoptimizingNode; import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; +import org.graalvm.compiler.nodes.calc.BinaryNode; +import org.graalvm.compiler.nodes.calc.LeftShiftNode; +import org.graalvm.compiler.nodes.calc.RightShiftNode; +import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; import org.graalvm.compiler.nodes.memory.Access; import jdk.vm.ci.aarch64.AArch64Kind; @@ -51,6 +62,36 @@ public class AArch64NodeMatchRules extends NodeMatchRules { return (AArch64Kind) gen.getLIRKind(access.asNode().stamp(NodeView.DEFAULT)).getPlatformKind(); } + private ComplexMatchResult emitAddSubShift(AArch64ArithmeticOp op, ValueNode value, BinaryNode shift) { + assert shift.getY() instanceof ConstantNode; + int shiftAmount = shift.getY().asJavaConstant().asInt(); + + if (shift instanceof LeftShiftNode) { + return builder -> getArithmeticLIRGenerator().emitAddSubShift(op, operand(value), operand(shift.getX()), + AArch64MacroAssembler.ShiftType.LSL, shiftAmount); + } else if (shift instanceof RightShiftNode) { + return builder -> getArithmeticLIRGenerator().emitAddSubShift(op, operand(value), operand(shift.getX()), + AArch64MacroAssembler.ShiftType.ASR, shiftAmount); + } else { + assert shift instanceof UnsignedRightShiftNode; + return builder -> getArithmeticLIRGenerator().emitAddSubShift(op, operand(value), operand(shift.getX()), + AArch64MacroAssembler.ShiftType.LSR, shiftAmount); + } + } + + @MatchRule("(Add=binary a (LeftShift=shift b Constant))") + @MatchRule("(Add=binary a (RightShift=shift b Constant))") + @MatchRule("(Add=binary a (UnsignedRightShift=shift b Constant))") + @MatchRule("(Sub=binary a (LeftShift=shift b Constant))") + @MatchRule("(Sub=binary a (RightShift=shift b Constant))") + @MatchRule("(Sub=binary a (UnsignedRightShift=shift b Constant))") + public ComplexMatchResult addSubShift(BinaryNode binary, ValueNode a, BinaryNode shift) { + if (binary instanceof AddNode) { + return emitAddSubShift(AArch64ArithmeticOp.ADD, a, shift); + } + return emitAddSubShift(AArch64ArithmeticOp.SUB, a, shift); + } + @Override public AArch64LIRGenerator getLIRGeneratorTool() { return (AArch64LIRGenerator) gen; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java index 63f5c9cd65..d24eafb042 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64ArithmeticLIRGenerator.java @@ -84,7 +84,10 @@ import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift; import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexGeneralPurposeRVMOp; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.VexGeneralPurposeRMOp; import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AVXKind.AVXSize; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.core.common.calc.FloatConvert; @@ -106,6 +109,8 @@ import org.graalvm.compiler.lir.amd64.AMD64MulDivOp; import org.graalvm.compiler.lir.amd64.AMD64ShiftOp; import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp; import org.graalvm.compiler.lir.amd64.AMD64Unary; +import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary; +import org.graalvm.compiler.lir.amd64.vector.AMD64VectorUnary; import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; import org.graalvm.compiler.lir.gen.LIRGenerator; @@ -931,6 +936,57 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen return result; } + @Override + public Value emitLogicalAndNot(Value value1, Value value2) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value1, value2)); + + if (value1.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64VectorBinary.AVXBinaryOp(VexGeneralPurposeRVMOp.ANDN, AVXSize.QWORD, result, asAllocatable(value1), asAllocatable(value2))); + } else { + getLIRGen().append(new AMD64VectorBinary.AVXBinaryOp(VexGeneralPurposeRVMOp.ANDN, AVXSize.DWORD, result, asAllocatable(value1), asAllocatable(value2))); + } + return result; + } + + @Override + public Value emitLowestSetIsolatedBit(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value)); + + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSI, AVXSize.QWORD, result, asAllocatable(value))); + } else { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSI, AVXSize.DWORD, result, asAllocatable(value))); + } + + return result; + } + + @Override + public Value emitGetMaskUpToLowestSetBit(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value)); + + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSMSK, AVXSize.QWORD, result, asAllocatable(value))); + } else { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSMSK, AVXSize.DWORD, result, asAllocatable(value))); + } + + return result; + } + + @Override + public Value emitResetLowestSetBit(Value value) { + Variable result = getLIRGen().newVariable(LIRKind.combine(value)); + + if (value.getPlatformKind() == AMD64Kind.QWORD) { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSR, AVXSize.QWORD, result, asAllocatable(value))); + } else { + getLIRGen().append(new AMD64VectorUnary.AVXUnaryOp(VexGeneralPurposeRMOp.BLSR, AVXSize.DWORD, result, asAllocatable(value))); + } + + return result; + } + @Override public Value emitMathAbs(Value input) { Variable result = getLIRGen().newVariable(LIRKind.combine(input)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java index 494e5bd744..821ecc2d88 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java @@ -87,7 +87,8 @@ import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp; import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp; import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp; import org.graalvm.compiler.lir.amd64.AMD64PauseOp; -import org.graalvm.compiler.lir.amd64.AMD64StringIndexOfOp; +import org.graalvm.compiler.lir.amd64.AMD64StringLatin1InflateOp; +import org.graalvm.compiler.lir.amd64.AMD64StringUTF16CompressOp; import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp; import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp; import org.graalvm.compiler.lir.gen.LIRGenerationResult; @@ -262,8 +263,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { public void emitCompareAndSwapBranch(ValueKind kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) { - assert kind.equals(expectedValue.getValueKind()); - assert kind.equals(newValue.getValueKind()); + assert kind.getPlatformKind().getSizeInBytes() <= expectedValue.getValueKind().getPlatformKind().getSizeInBytes(); + assert kind.getPlatformKind().getSizeInBytes() <= newValue.getValueKind().getPlatformKind().getSizeInBytes(); assert condition == Condition.EQ || condition == Condition.NE; AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind(); RegisterValue raxValue = AMD64.rax.asValue(kind); @@ -542,9 +543,9 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { } @Override - public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers) { Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); - append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length))); + append(new AMD64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length), constantLength, directPointers, getMaxVectorSize())); return result; } @@ -555,22 +556,56 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { return 4096; } + /** + * Return the maximum size of vector registers used in SSE/AVX instructions. + */ + protected int getMaxVectorSize() { + // default for "unlimited" + return -1; + } + @Override - public Variable emitStringIndexOf(Value source, Value sourceCount, Value target, Value targetCount, int constantTargetCount) { - Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); - RegisterValue cnt1 = AMD64.rdx.asValue(sourceCount.getValueKind()); - emitMove(cnt1, sourceCount); - RegisterValue cnt2 = AMD64.rax.asValue(targetCount.getValueKind()); - emitMove(cnt2, targetCount); - append(new AMD64StringIndexOfOp(this, result, source, target, cnt1, cnt2, AMD64.rcx.asValue(), AMD64.xmm0.asValue(), constantTargetCount, getVMPageSize())); + public Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value arrayPointer, Value arrayLength, Value... searchValues) { + Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD)); + Value[] allocatableSearchValues = new Value[searchValues.length]; + for (int i = 0; i < searchValues.length; i++) { + allocatableSearchValues[i] = asAllocatable(searchValues[i]); + } + append(new AMD64ArrayIndexOfOp(kind, findTwoConsecutive, getVMPageSize(), getMaxVectorSize(), this, result, asAllocatable(arrayPointer), asAllocatable(arrayLength), allocatableSearchValues)); return result; } @Override - public Variable emitArrayIndexOf(JavaKind kind, Value arrayPointer, Value arrayLength, Value charValue) { - Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); - append(new AMD64ArrayIndexOfOp(kind, getVMPageSize(), this, result, asAllocatable(arrayPointer), asAllocatable(arrayLength), asAllocatable(charValue))); - return result; + public void emitStringLatin1Inflate(Value src, Value dst, Value len) { + RegisterValue rsrc = AMD64.rsi.asValue(src.getValueKind()); + RegisterValue rdst = AMD64.rdi.asValue(dst.getValueKind()); + RegisterValue rlen = AMD64.rdx.asValue(len.getValueKind()); + + emitMove(rsrc, src); + emitMove(rdst, dst); + emitMove(rlen, len); + + append(new AMD64StringLatin1InflateOp(this, rsrc, rdst, rlen)); + } + + @Override + public Variable emitStringUTF16Compress(Value src, Value dst, Value len) { + RegisterValue rsrc = AMD64.rsi.asValue(src.getValueKind()); + RegisterValue rdst = AMD64.rdi.asValue(dst.getValueKind()); + RegisterValue rlen = AMD64.rdx.asValue(len.getValueKind()); + + emitMove(rsrc, src); + emitMove(rdst, dst); + emitMove(rlen, len); + + LIRKind reskind = LIRKind.value(AMD64Kind.DWORD); + RegisterValue rres = AMD64.rax.asValue(reskind); + + append(new AMD64StringUTF16CompressOp(this, rres, rsrc, rdst, rlen)); + + Variable res = newVariable(reskind); + emitMove(res, rres); + return res; } @Override @@ -614,7 +649,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator { return new AMD64ZapStackOp(zappedStack, zapValues); } - public void emitLFence() { + @Override + public void emitSpeculationFence() { append(new AMD64LFenceOp()); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java index 84488dc600..335fff4386 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeLIRBuilder.java @@ -25,8 +25,6 @@ package org.graalvm.compiler.core.amd64; -import static org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder.Options.MitigateSpeculativeExecutionAttacks; - import org.graalvm.compiler.core.gen.NodeLIRBuilder; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.lir.LIRFrameState; @@ -41,11 +39,6 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op; -import org.graalvm.compiler.nodes.cfg.Block; -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 jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.meta.AllocatableValue; @@ -53,13 +46,6 @@ import jdk.vm.ci.meta.Value; public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { - public static class Options { - // @formatter:off - @Option(help = "AMD64: Emit lfence instructions at the beginning of basic blocks", type = OptionType.Expert) - public static final OptionKey MitigateSpeculativeExecutionAttacks = new OptionKey<>(false); - // @formatter:on - } - public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) { super(graph, gen, nodeMatchRules); } @@ -137,21 +123,4 @@ public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { public AMD64LIRGenerator getLIRGeneratorTool() { return (AMD64LIRGenerator) gen; } - - @Override - public void doBlockPrologue(Block block, OptionValues options) { - if (MitigateSpeculativeExecutionAttacks.getValue(options)) { - boolean hasControlSplitPredecessor = false; - for (Block b : block.getPredecessors()) { - if (b.getSuccessorCount() > 1) { - hasControlSplitPredecessor = true; - break; - } - } - boolean isStartBlock = block.getPredecessorCount() == 0; - if (hasControlSplitPredecessor || isStartBlock) { - getLIRGeneratorTool().emitLFence(); - } - } - } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java index db1c94582f..cc89bd4b5f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java @@ -78,9 +78,12 @@ import org.graalvm.compiler.nodes.memory.LIRLowerableAccess; import org.graalvm.compiler.nodes.memory.WriteNode; import org.graalvm.compiler.nodes.util.GraphUtil; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PlatformKind; import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.ValueKind; @@ -272,6 +275,81 @@ public class AMD64NodeMatchRules extends NodeMatchRules { return getArithmeticLIRGenerator().emitLoad(to, address, state); } + private boolean supports(CPUFeature feature) { + return ((AMD64) getLIRGeneratorTool().target().arch).getFeatures().contains(feature); + } + + @MatchRule("(And (Not a) b)") + public ComplexMatchResult logicalAndNot(ValueNode a, ValueNode b) { + if (!supports(CPUFeature.BMI1)) { + return null; + } + return builder -> getArithmeticLIRGenerator().emitLogicalAndNot(operand(a), operand(b)); + } + + @MatchRule("(And a (Negate a))") + public ComplexMatchResult lowestSetIsolatedBit(ValueNode a) { + if (!supports(CPUFeature.BMI1)) { + return null; + } + return builder -> getArithmeticLIRGenerator().emitLowestSetIsolatedBit(operand(a)); + } + + @MatchRule("(Xor a (Add a b))") + public ComplexMatchResult getMaskUpToLowestSetBit(ValueNode a, ValueNode b) { + if (!supports(CPUFeature.BMI1)) { + return null; + } + + // Make sure that the pattern matches a subtraction by one. + if (!b.isJavaConstant()) { + return null; + } + + JavaConstant bCst = b.asJavaConstant(); + long bValue; + if (bCst.getJavaKind() == JavaKind.Int) { + bValue = bCst.asInt(); + } else if (bCst.getJavaKind() == JavaKind.Long) { + bValue = bCst.asLong(); + } else { + return null; + } + + if (bValue == -1) { + return builder -> getArithmeticLIRGenerator().emitGetMaskUpToLowestSetBit(operand(a)); + } else { + return null; + } + } + + @MatchRule("(And a (Add a b))") + public ComplexMatchResult resetLowestSetBit(ValueNode a, ValueNode b) { + if (!supports(CPUFeature.BMI1)) { + return null; + } + // Make sure that the pattern matches a subtraction by one. + if (!b.isJavaConstant()) { + return null; + } + + JavaConstant bCst = b.asJavaConstant(); + long bValue; + if (bCst.getJavaKind() == JavaKind.Int) { + bValue = bCst.asInt(); + } else if (bCst.getJavaKind() == JavaKind.Long) { + bValue = bCst.asLong(); + } else { + return null; + } + + if (bValue == -1) { + return builder -> getArithmeticLIRGenerator().emitResetLowestSetBit(operand(a)); + } else { + return null; + } + } + @MatchRule("(If (IntegerTest Read=access value))") @MatchRule("(If (IntegerTest FloatingRead=access value))") public ComplexMatchResult integerTestBranchMemory(IfNode root, LIRLowerableAccess access, ValueNode value) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java index 030836217b..1b5f5706eb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/NumUtil.java @@ -215,14 +215,14 @@ public class NumUtil { } public static long maxUnsigned(long a, long b) { - if (Long.compareUnsigned(a, b) > 0) { + if (Long.compareUnsigned(a, b) < 0) { return b; } return a; } public static long minUnsigned(long a, long b) { - if (Long.compareUnsigned(a, b) > 0) { + if (Long.compareUnsigned(a, b) < 0) { return a; } return b; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpeculativeExecutionAttacksMitigations.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpeculativeExecutionAttacksMitigations.java new file mode 100644 index 0000000000..beab3b14f9 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/SpeculativeExecutionAttacksMitigations.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.core.common; + +import org.graalvm.compiler.options.EnumOptionKey; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionType; + +public enum SpeculativeExecutionAttacksMitigations { + None, + AllTargets, + GuardTargets, + NonDeoptGuardTargets; + + public static class Options { + // @formatter:off + @Option(help = "Select a strategy to mitigate speculative execution attacks (e.g., SPECTRE)", type = OptionType.User) + public static final EnumOptionKey MitigateSpeculativeExecutionAttacks = new EnumOptionKey<>(None); + @Option(help = "Use index masking after bounds check to mitigate speculative execution attacks", type = OptionType.User) + public static final OptionKey UseIndexMasking = new OptionKey<>(false); + // @formatter:on + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java index e7363d2546..739fc2426f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/BiDirectionalTraceBuilder.java @@ -63,7 +63,7 @@ public final class BiDirectionalTraceBuilder { } private static int compare(AbstractBlockBase a, AbstractBlockBase b) { - return Double.compare(b.probability(), a.probability()); + return Double.compare(b.getRelativeFrequency(), a.getRelativeFrequency()); } private boolean processed(AbstractBlockBase b) { @@ -132,7 +132,7 @@ public final class BiDirectionalTraceBuilder { } private void addBlockToTrace(DebugContext debug, AbstractBlockBase block) { - debug.log("add %s (prob: %f)", block, block.probability()); + debug.log("add %s (freq: %f)", block, block.getRelativeFrequency()); processed.set(block.getId()); } @@ -142,7 +142,7 @@ public final class BiDirectionalTraceBuilder { private AbstractBlockBase selectPredecessor(AbstractBlockBase block) { AbstractBlockBase next = null; for (AbstractBlockBase pred : block.getPredecessors()) { - if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.probability() > next.probability())) { + if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.getRelativeFrequency() > next.getRelativeFrequency())) { next = pred; } } @@ -160,7 +160,7 @@ public final class BiDirectionalTraceBuilder { private AbstractBlockBase selectSuccessor(AbstractBlockBase block) { AbstractBlockBase next = null; for (AbstractBlockBase succ : block.getSuccessors()) { - if (!processed(succ) && (next == null || succ.probability() > next.probability())) { + if (!processed(succ) && (next == null || succ.getRelativeFrequency() > next.getRelativeFrequency())) { next = succ; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java index b9001234b1..2c35be2d2f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/ComputeBlockOrder.java @@ -143,11 +143,11 @@ public final class ComputeBlockOrder { double unscheduledSum = 0.0; for (T pred : mostLikelySuccessor.getPredecessors()) { if (pred.getLinearScanNumber() == -1) { - unscheduledSum += pred.probability(); + unscheduledSum += pred.getRelativeFrequency(); } } - if (unscheduledSum > block.probability() / PENALTY_VERSUS_UNSCHEDULED) { + if (unscheduledSum > block.getRelativeFrequency() / PENALTY_VERSUS_UNSCHEDULED) { // Add this merge only after at least one additional predecessor gets scheduled. visitedBlocks.clear(mostLikelySuccessor.getId()); return null; @@ -212,8 +212,8 @@ public final class ComputeBlockOrder { private static > T findAndMarkMostLikelySuccessor(T block, BitSet visitedBlocks) { T result = null; for (T successor : block.getSuccessors()) { - assert successor.probability() >= 0.0 : "Probabilities must be positive"; - if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.probability() >= result.probability())) { + assert successor.getRelativeFrequency() >= 0.0 : "Relative frequencies must be positive"; + if (!visitedBlocks.get(successor.getId()) && successor.getLoopDepth() >= block.getLoopDepth() && (result == null || successor.getRelativeFrequency() >= result.getRelativeFrequency())) { result = successor; } } @@ -261,7 +261,7 @@ public final class ComputeBlockOrder { public int compare(T a, T b) { // Loop blocks before any loop exit block. The only exception are blocks that are // (almost) impossible to reach. - if (a.probability() > EPSILON && b.probability() > EPSILON) { + if (a.getRelativeFrequency() > EPSILON && b.getRelativeFrequency() > EPSILON) { int diff = b.getLoopDepth() - a.getLoopDepth(); if (diff != 0) { return diff; @@ -269,7 +269,7 @@ public final class ComputeBlockOrder { } // Blocks with high probability before blocks with low probability. - if (a.probability() > b.probability()) { + if (a.getRelativeFrequency() > b.getRelativeFrequency()) { return -1; } else { return 1; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java index 5c17c79d87..27b595d0dd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/TraceStatisticsPrinter.java @@ -59,13 +59,13 @@ public final class TraceStatisticsPrinter { double max = Double.NEGATIVE_INFINITY; double min = Double.POSITIVE_INFINITY; for (AbstractBlockBase block : t) { - double probability = block.probability(); - total += probability; - if (probability < min) { - min = probability; + double frequency = block.getRelativeFrequency(); + total += frequency; + if (frequency < min) { + min = frequency; } - if (probability > max) { - max = probability; + if (frequency > max) { + max = frequency; } } printLine(debug, i, total, min, max, t.length); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java index 032288433a..e85fa44294 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/UniDirectionalTraceBuilder.java @@ -65,7 +65,7 @@ public final class UniDirectionalTraceBuilder { } private static int compare(AbstractBlockBase a, AbstractBlockBase b) { - return Double.compare(b.probability(), a.probability()); + return Double.compare(b.getRelativeFrequency(), a.getRelativeFrequency()); } private boolean processed(AbstractBlockBase b) { @@ -110,7 +110,7 @@ public final class UniDirectionalTraceBuilder { int blockNumber = 0; try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) { for (AbstractBlockBase block = traceStart; block != null; block = selectNext(block)) { - debug.log("add %s (prob: %f)", block, block.probability()); + debug.log("add %s (freq: %f)", block, block.getRelativeFrequency()); processed.set(block.getId()); trace.add(block); unblock(block); @@ -149,7 +149,7 @@ public final class UniDirectionalTraceBuilder { private AbstractBlockBase selectNext(AbstractBlockBase block) { AbstractBlockBase next = null; for (AbstractBlockBase successor : block.getSuccessors()) { - if (!processed(successor) && (next == null || successor.probability() > next.probability())) { + if (!processed(successor) && (next == null || successor.getRelativeFrequency() > next.getRelativeFrequency())) { next = successor; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java index 9ce0af7759..58dd15001b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/cfg/AbstractBlockBase.java @@ -163,7 +163,7 @@ public abstract class AbstractBlockBase> { public abstract T getPostdominator(); - public abstract double probability(); + public abstract double getRelativeFrequency(); public abstract T getDominator(int distance); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java index a28f2ee89b..fdc267fcf3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java @@ -41,6 +41,4 @@ public interface CodeGenProviders { ForeignCallsProvider getForeignCalls(); ConstantReflectionProvider getConstantReflection(); - - ArrayOffsetProvider getArrayOffsetProvider(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java index 2f5841b43f..36c702b6aa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/AbstractPointerStamp.java @@ -142,10 +142,13 @@ public abstract class AbstractPointerStamp extends Stamp { @Override public Constant asConstant() { if (alwaysNull) { - return JavaConstant.NULL_POINTER; - } else { - return null; + return nullConstant(); } + return super.asConstant(); + } + + public JavaConstant nullConstant() { + return JavaConstant.NULL_POINTER; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/test/ea/AtomicVirtualizationTests.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/test/ea/AtomicVirtualizationTests.java new file mode 100644 index 0000000000..2037319775 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.jdk9.test/src/org/graalvm/compiler/core/test/ea/AtomicVirtualizationTests.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2018, 2018, 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.jdk9.test.ea; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; +import org.graalvm.compiler.core.test.ea.EATestBase; + +import org.junit.Test; + +import jdk.vm.ci.meta.JavaConstant; + +public class AtomicVirtualizationTests extends EATestBase { + private static final TestObject OBJ1 = new TestObject(1); + private static final TestObject OBJ2 = new TestObject(2); + private static TestObject obj6 = new TestObject(6); + private static TestObject obj7 = new TestObject(7); + private static TestObject obj8 = new TestObject(8); + + private static final class TestObject { + final int id; + + private TestObject(int id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TestObject that = (TestObject) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + return "TestObject{id=" + id + '}'; + } + } + + // c = constant (heap-allocated); v = virtual; u = unknown (heap-allocated) + + public static boolean cvvNoMatchCAS() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndSet(new TestObject(3), new TestObject(4)); + } + + @Test + public void testcvvNoMatchCAS() { + testAtomicVirtualization("cvvNoMatchCAS", JavaConstant.INT_0); + } + + public static Object cvvNoMatchCAE() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndExchange(new TestObject(3), new TestObject(4)); + } + + @Test + public void testcvvNoMatchCAE() { + testAtomicVirtualization("cvvNoMatchCAE", JavaConstant.NULL_POINTER); + } + + public static boolean ccvNoMatchCAS() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndSet(OBJ1, new TestObject(3)); + } + + @Test + public void testccvNoMatchCAS() { + testAtomicVirtualization("ccvNoMatchCAS", JavaConstant.INT_0); + } + + public static Object ccvNoMatchCAE() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndExchange(OBJ1, new TestObject(3)); + } + + @Test + public void testccvNoMatchCAE() { + testAtomicVirtualization("ccvNoMatchCAE", JavaConstant.NULL_POINTER); + } + + public static boolean cccNoMatchCAS() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndSet(OBJ1, OBJ2); + } + + @Test + public void testcccNoMatchCAS() { + testAtomicVirtualization("cccNoMatchCAS", JavaConstant.INT_0); + } + + public static Object cccNoMatchCAE() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndExchange(OBJ1, OBJ2); + } + + @Test + public void testcccNoMatchCAE() { + testAtomicVirtualization("cccNoMatchCAE", JavaConstant.NULL_POINTER); + } + + public static boolean ccvCAS() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndSet(null, new TestObject(3)); + } + + @Test + public void testccvCAS() { + testAtomicVirtualization("ccvCAS", JavaConstant.INT_1); + } + + public static Object ccvCAE() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndExchange(null, new TestObject(3)); + } + + @Test + public void testccvCAE() { + testAtomicVirtualization("ccvCAE", null, 0); + } + + public static boolean cccCAS() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndSet(null, OBJ2); + } + + @Test + public void testcccCAS() { + testAtomicVirtualization("cccCAS", JavaConstant.INT_1); + } + + public static Object cccCAE() { + AtomicReference a = new AtomicReference<>(null); + return a.compareAndExchange(null, OBJ2); + } + + @Test + public void testcccCAE() { + testAtomicVirtualization("cccCAE", null); + } + + public static boolean vvvNoMatchCAS() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndSet(new TestObject(4), new TestObject(5)); + } + + @Test + public void testvvvNoMatchCAS() { + testAtomicVirtualization("vvvNoMatchCAS", JavaConstant.INT_0); + } + + public static Object vvvNoMatchCAE() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndExchange(new TestObject(4), new TestObject(5)); + } + + @Test + public void testvvvNoMatchCAE() { + testAtomicVirtualization("vvvNoMatchCAE", null, 1); + } + + public static boolean vcvNoMatchCAS() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndSet(OBJ1, new TestObject(4)); + } + + @Test + public void testvcvNoMatchCAS() { + testAtomicVirtualization("vcvNoMatchCAS", JavaConstant.INT_0); + } + + public static Object vcvNoMatchCAE() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndExchange(OBJ1, new TestObject(4)); + } + + @Test + public void testvcvNoMatchCAE() { + testAtomicVirtualization("vcvNoMatchCAE", null, 1); + } + + public static boolean vccNoMatchCAS() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndSet(OBJ1, OBJ2); + } + + @Test + public void testvccNoMatchCAS() { + testAtomicVirtualization("vccNoMatchCAS", JavaConstant.INT_0); + } + + public static Object vccNoMatchCAE() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndExchange(OBJ1, OBJ2); + } + + @Test + public void testvccNoMatchCAE() { + testAtomicVirtualization("vccNoMatchCAE", null, 1); + } + + public static boolean uvvCAS() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndSet(new TestObject(3), new TestObject(4)); + } + + @Test + public void testuvvCAS() { + testAtomicVirtualization("uvvCAS", JavaConstant.INT_0); + } + + public static Object uvvCAE() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndExchange(new TestObject(3), new TestObject(4)); + } + + @Test + public void testuvvCAE() { + testAtomicVirtualization("uvvCAE", null); + } + + public static boolean uuvCAS() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndSet(obj7, new TestObject(3)); + } + + @Test + public void testuuvCAS() { + testAtomicVirtualization("uuvCAS", null, 2); + } + + public static Object uuvCAE() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndExchange(obj7, new TestObject(3)); + } + + @Test + public void testuuvCAE() { + testAtomicVirtualization("uuvCAE", null, 2); + } + + public static boolean uuuCAS() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndSet(obj7, obj8); + } + + @Test + public void testuuuCAS() { + testAtomicVirtualization("uuuCAS", null); + } + + public static Object uuuCAE() { + AtomicReference a = new AtomicReference<>(obj6); + return a.compareAndExchange(obj7, obj8); + } + + @Test + public void testuuuCAE() { + testAtomicVirtualization("uuuCAE", null); + } + + public static boolean vuvCAS() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndSet(obj6, new TestObject(4)); + } + + @Test + public void testvuvCAS() { + testAtomicVirtualization("vuvCAS", JavaConstant.INT_0); + } + + public static Object vuvCAE() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndExchange(obj6, new TestObject(4)); + } + + @Test + public void testvuvCAE() { + testAtomicVirtualization("vuvCAE", null, 1); + } + + public static boolean vuuCAS() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndSet(obj6, obj7); + } + + @Test + public void testvuuCAS() { + testAtomicVirtualization("vuuCAS", JavaConstant.INT_0); + } + + public static Object vuuCAE() { + AtomicReference a = new AtomicReference<>(new TestObject(3)); + return a.compareAndExchange(obj6, obj7); + } + + @Test + public void testvuuCAE() { + testAtomicVirtualization("vuuCAE", null, 1); + } + + private void testAtomicVirtualization(String snippet, JavaConstant expectedValue) { + testAtomicVirtualization(snippet, expectedValue, 0); + } + + protected void testAtomicVirtualization(String snippet, JavaConstant expectedValue, int expectedAllocations) { + testEscapeAnalysis(snippet, expectedValue, false, expectedAllocations); + test(snippet); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java index 50cf6019eb..312656ed61 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java @@ -692,7 +692,7 @@ public class MatchProcessor extends AbstractProcessor { private RoundEnvironment currentRound; @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java index e2891c6aea..f1d8435722 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCLIRGenerator.java @@ -420,9 +420,9 @@ public abstract class SPARCLIRGenerator extends LIRGenerator { } @Override - public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { + public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers) { Variable result = newVariable(LIRKind.value(SPARCKind.WORD)); - append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length))); + append(new SPARCArrayEqualsOp(this, kind, result, load(array1), load(array2), asAllocatable(length), directPointers)); return result; } @@ -477,4 +477,9 @@ public abstract class SPARCLIRGenerator extends LIRGenerator { public void emitPause() { append(new SPARCPauseOp()); } + + @Override + public void emitSpeculationFence() { + throw GraalError.unimplemented(); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java index 2e71b7fc22..68775201f1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CheckGraalInvariants.java @@ -181,6 +181,7 @@ public class CheckGraalInvariants extends GraalCompilerTest { @Test @SuppressWarnings("try") public void test() { + assumeManagementLibraryIsLoadable(); runTest(new InvariantsTool()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java index d52bbe7a00..45850d2d6a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,56 +24,74 @@ package org.graalvm.compiler.core.test; -import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty; - import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; -import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.junit.Assert; import org.junit.Test; public class CompareCanonicalizerTest2 extends GraalCompilerTest { - @SuppressWarnings("unused") private static int sink0; - @SuppressWarnings("unused") private static int sink1; + @SuppressWarnings("unused") private static boolean sink; private StructuredGraph getCanonicalizedGraph(String name) { - StructuredGraph graph = parseEager(name, AllowAssumptions.YES); + StructuredGraph graph = getRegularGraph(name); new CanonicalizerPhase().apply(graph, new PhaseContext(getProviders())); return graph; } - public void testIntegerTestCanonicalization(String name) { - StructuredGraph graph = getCanonicalizedGraph(name); - Assert.assertThat(graph.getNodes().filter(IntegerLessThanNode.class), isNotEmpty()); + private StructuredGraph getRegularGraph(String name) { + StructuredGraph graph = parseEager(name, AllowAssumptions.YES); + return graph; } @Test public void test0() { - testIntegerTestCanonicalization("integerTestCanonicalization0"); + assertEquals(getCanonicalizedGraph("integerTestCanonicalization0"), getRegularGraph("integerTestCanonicalization0")); + } + + public static void integerTestCanonicalization0(int a) { + sink = 1 < a + 1; } @Test public void test1() { - testIntegerTestCanonicalization("integerTestCanonicalization1"); - } - - public static void integerTestCanonicalization0(int a) { - if (1 < a + 1) { - sink1 = 0; - } else { - sink0 = -1; - } + assertEquals(getCanonicalizedGraph("integerTestCanonicalization1"), getRegularGraph("integerTestCanonicalization1")); } public static void integerTestCanonicalization1(int a) { - if (a - 1 < -1) { - sink1 = 0; - } else { - sink0 = -1; - } + sink = a - 1 < -1; + } + + @Test + public void test2() { + assertEquals(getCanonicalizedGraph("integerTestCanonicalization2a"), getCanonicalizedGraph("integerTestCanonicalization2Reference")); + assertEquals(getCanonicalizedGraph("integerTestCanonicalization2b"), getCanonicalizedGraph("integerTestCanonicalization2Reference")); + } + + public static boolean integerTestCanonicalization2a(Object[] arr) { + return arr.length - 1 < 0; + } + + public static boolean integerTestCanonicalization2b(Object[] arr) { + return arr.length < 1; + } + + public static boolean integerTestCanonicalization2Reference(Object[] arr) { + return arr.length == 0; + } + + @Test + public void test3() { + assertEquals(getCanonicalizedGraph("integerTestCanonicalization3"), getCanonicalizedGraph("integerTestCanonicalization3Reference")); + } + + public static boolean integerTestCanonicalization3(Object[] arr) { + return ((long) (arr.length - 1)) - 1 < 0; + } + + public static boolean integerTestCanonicalization3Reference(Object[] arr) { + return arr.length < 2; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java index 7822d2fdb8..22f732f410 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CompareCanonicalizerTest3.java @@ -92,16 +92,18 @@ public class CompareCanonicalizerTest3 extends GraalCompilerTest { assertCanonicallyEqual("integerTestCanonicalization1", "referenceSnippet1"); } - public static void integerTestCanonicalization1(char a) { - if (Integer.compareUnsigned(a - 2, a) < 0) { + public static void integerTestCanonicalization1(char[] a) { + int len = a.length; + if (Integer.compareUnsigned(len - 2, len) < 0) { sink1 = 0; } else { sink0 = -1; } } - public static void referenceSnippet1(char a) { - if (Integer.compareUnsigned(a, 2) >= 0) { + public static void referenceSnippet1(char[] a) { + int len = a.length; + if (Integer.compareUnsigned(len, 2) >= 0) { sink1 = 0; } else { sink0 = -1; @@ -238,12 +240,18 @@ public class CompareCanonicalizerTest3 extends GraalCompilerTest { StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES); PhaseContext context = new PhaseContext(getProviders()); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); new GuardLoweringPhase().apply(graph, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo())); new FrameStateAssignmentPhase().apply(graph); canonicalizer.apply(graph, context); + StructuredGraph referenceGraph = parseEager(reference, AllowAssumptions.YES); canonicalizer.apply(referenceGraph, context); + new GuardLoweringPhase().apply(referenceGraph, new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo())); + new FrameStateAssignmentPhase().apply(referenceGraph); + canonicalizer.apply(referenceGraph, context); + canonicalizer.apply(referenceGraph, context); assertEquals(referenceGraph, graph, true, true); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java index 19189c96a8..85f0a6f6b3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest13.java @@ -31,6 +31,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; +import org.junit.Ignore; import org.junit.Test; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -282,6 +283,7 @@ public class ConditionalEliminationTest13 extends ConditionalEliminationTestBase testConditionalElimination("testSnippet9", "referenceSnippet9"); } + @Ignore("Need better unsigned stamps for this conditional elimination to work.") @Test public void test10() { testConditionalElimination("testSnippet10", "referenceSnippet4"); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java index 7f01decda3..964ec3e42f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java @@ -47,6 +47,7 @@ public class DumpPathTest extends GraalCompilerTest { @Test public void testDump() throws IOException { + assumeManagementLibraryIsLoadable(); Path dumpDirectoryPath = Files.createTempDirectory("DumpPathTest"); String[] extensions = new String[]{".cfg", ".bgv", ".graph-strings"}; EconomicMap, Object> overrides = OptionValues.newOptionMap(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java index 016e9af0e2..29e9a7cdd7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java @@ -43,6 +43,7 @@ public class GraphResetDebugTest extends GraalCompilerTest { @SuppressWarnings("try") @Test public void test1() { + assumeManagementLibraryIsLoadable(); EconomicMap, Object> map = EconomicMap.create(); // Configure with an option that enables scopes map.put(DebugOptions.DumpOnError, true); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java index 533b3442bb..64f0e3c3f6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardedIntrinsicTest.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.InvokeNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.extended.LoadHubNode; import org.graalvm.compiler.nodes.extended.LoadMethodNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java index 6724b2cef2..d6c9bebd01 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java @@ -35,7 +35,7 @@ import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.calc.AddNode; -import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.schedule.SchedulePhase; @@ -71,7 +71,7 @@ public class LongNodeChainTest extends GraalCompilerTest { addNode.setY(newAddNode); addNode = newAddNode; } - opaque.replaceAndDelete(opaque.getValue()); + opaque.remove(); } else { value = constant; for (int i = 0; i < N; ++i) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java index 16eb9311ae..f00de78e63 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/EATestBase.java @@ -24,6 +24,8 @@ package org.graalvm.compiler.core.test.ea; +import static org.graalvm.compiler.graph.iterators.NodePredicates.isA; + import java.util.List; import org.graalvm.compiler.core.test.GraalCompilerTest; @@ -33,6 +35,7 @@ import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.java.NewArrayNode; import org.graalvm.compiler.nodes.java.NewInstanceNode; +import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode; import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; @@ -139,6 +142,10 @@ public class EATestBase extends GraalCompilerTest { * iteration */ protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) { + testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis, 0); + } + + protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis, int expectedAllocationCount) { prepareGraph(snippet, iterativeEscapeAnalysis); if (expectedConstantResult != null) { for (ReturnNode returnNode : returnNodes) { @@ -146,9 +153,11 @@ public class EATestBase extends GraalCompilerTest { Assert.assertEquals(expectedConstantResult, returnNode.result().asConstant()); } } - int newInstanceCount = graph.getNodes().filter(NewInstanceNode.class).count() + graph.getNodes().filter(NewArrayNode.class).count() + - graph.getNodes().filter(CommitAllocationNode.class).count(); - Assert.assertEquals(0, newInstanceCount); + int newInstanceCount = graph.getNodes().filter(isA(NewInstanceNode.class).or(NewArrayNode.class).or(AllocatedObjectNode.class)).count(); + Assert.assertEquals("Expected allocation count does not match", expectedAllocationCount, newInstanceCount); + if (expectedAllocationCount == 0) { + Assert.assertTrue("Unexpected CommitAllocationNode", graph.getNodes().filter(CommitAllocationNode.class).isEmpty()); + } } @SuppressWarnings("try") diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java index 24aa3f26e6..df38449ddf 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PEAAssertionsTest.java @@ -45,7 +45,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { public static Object field; - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippet1(int i) { Integer object = new Integer(i); GraalDirectives.ensureVirtualized(object); @@ -56,7 +56,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippet1", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippet2(int i) { Integer object = new Integer(i); GraalDirectives.ensureVirtualized(object); @@ -68,7 +68,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippet2", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippet3(int i) { Integer object = new Integer(i); field = object; @@ -80,7 +80,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippet3", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetHere1(int i) { Integer object = new Integer(i); GraalDirectives.ensureVirtualizedHere(object); @@ -91,7 +91,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetHere1", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetHere2(int i) { Integer object = new Integer(i); GraalDirectives.ensureVirtualizedHere(object); @@ -103,7 +103,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetHere2", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetHere3(int i) { Integer object = new Integer(i); field = object; @@ -136,7 +136,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetBoxing2", 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetControlFlow1(boolean b, int i) { Integer object = new Integer(i); if (b) { @@ -151,7 +151,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetControlFlow1", true, 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetControlFlow2(boolean b, int i) { Integer object = new Integer(i); if (b) { @@ -168,7 +168,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetControlFlow2", true, 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetControlFlow3(boolean b, int i) { Integer object = new Integer(i); GraalDirectives.ensureVirtualized(object); @@ -186,7 +186,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetControlFlow3", true, 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetControlFlow4(boolean b, int i) { Integer object = new Integer(i); if (b) { @@ -202,7 +202,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetControlFlow4", true, 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetControlFlow5(boolean b, int i) { Integer object = new Integer(i); if (b) { @@ -223,7 +223,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { Object b; } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetIndirect1(boolean b, int i) { Integer object = new Integer(i); TestClass t = new TestClass(); @@ -242,7 +242,7 @@ public class PEAAssertionsTest extends GraalCompilerTest { test("snippetIndirect1", true, 1); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static void snippetIndirect2(boolean b, int i) { Integer object = new Integer(i); TestClass t = new TestClass(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java index 11cdd8deb2..3fe24e7290 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/PartialEscapeAnalysisTest.java @@ -293,14 +293,14 @@ public class PartialEscapeAnalysisTest extends EATestBase { Assert.assertTrue("partial escape analysis should have removed all NewArrayNode allocations", graph.getNodes().filter(NewArrayNode.class).isEmpty()); ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, false, false); - double probabilitySum = 0; + double frequencySum = 0; int materializeCount = 0; for (CommitAllocationNode materialize : graph.getNodes().filter(CommitAllocationNode.class)) { - probabilitySum += cfg.blockFor(materialize).probability() * materialize.getVirtualObjects().size(); + frequencySum += cfg.blockFor(materialize).getRelativeFrequency() * materialize.getVirtualObjects().size(); materializeCount += materialize.getVirtualObjects().size(); } Assert.assertEquals("unexpected number of MaterializeObjectNodes", expectedCount, materializeCount); - Assert.assertEquals("unexpected probability of MaterializeObjectNodes", expectedProbability, probabilitySum, 0.01); + Assert.assertEquals("unexpected frequency of MaterializeObjectNodes", expectedProbability, frequencySum, 0.01); for (Node node : graph.getNodes()) { for (Class clazz : invalidNodeClasses) { Assert.assertFalse("instance of invalid class: " + clazz.getSimpleName(), clazz.isInstance(node) && node.usages().isNotEmpty()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeCompareAndSwapVirtualizationTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeCompareAndSwapVirtualizationTest.java new file mode 100644 index 0000000000..72aa11f2df --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ea/UnsafeCompareAndSwapVirtualizationTest.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018, 2018, 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.ea; + +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.AtomicReferenceArray; + +import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode; +import org.junit.Test; + +import jdk.vm.ci.meta.JavaConstant; + +public class UnsafeCompareAndSwapVirtualizationTest extends EATestBase { + + private static Object obj1 = new Object(); + private static Object obj2 = new Object(); + private static final Object OBJ1 = new Object(); + + public static boolean bothVirtualNoMatch() { + AtomicReference a = new AtomicReference<>(); + return a.compareAndSet(new Object(), new Object()); + } + + @Test + public void bothVirtualNoMatchTest() { + testEscapeAnalysis("bothVirtualNoMatch", JavaConstant.INT_0, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean bothVirtualMatch() { + Object expect = new Object(); + AtomicReference a = new AtomicReference<>(expect); + return a.compareAndSet(expect, new Object()); + } + + @Test + public void bothVirtualMatchTest() { + testEscapeAnalysis("bothVirtualMatch", JavaConstant.INT_1, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean expectedVirtualMatch() { + Object o = new Object(); + AtomicReference a = new AtomicReference<>(o); + return a.compareAndSet(o, obj1); + } + + @Test + public void expectedVirtualMatchTest() { + testEscapeAnalysis("expectedVirtualMatch", JavaConstant.INT_1, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean expectedVirtualNoMatch() { + Object o = new Object(); + AtomicReference a = new AtomicReference<>(); + return a.compareAndSet(o, obj1); + } + + @Test + public void expectedVirtualNoMatchTest() { + testEscapeAnalysis("expectedVirtualNoMatch", JavaConstant.INT_0, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean bothNonVirtualNoMatch() { + AtomicReference a = new AtomicReference<>(); + return a.compareAndSet(OBJ1, obj2); + } + + @Test + public void bothNonVirtualNoMatchTest() { + testEscapeAnalysis("bothNonVirtualNoMatch", JavaConstant.INT_0, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean bothNonVirtualMatch() { + AtomicReference a = new AtomicReference<>(OBJ1); + return a.compareAndSet(OBJ1, obj2); + } + + @Test + public void bothNonVirtualMatchTest() { + testEscapeAnalysis("bothNonVirtualMatch", JavaConstant.INT_1, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean onlyInitialValueVirtualNoMatch() { + AtomicReference a = new AtomicReference<>(new Object()); + return a.compareAndSet(obj1, obj2); + } + + @Test + public void onlyInitialValueVirtualNoMatchTest() { + testEscapeAnalysis("onlyInitialValueVirtualNoMatch", JavaConstant.INT_0, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean onlyInitialValueVirtualMatch() { + Object o = new Object(); + AtomicReference a = new AtomicReference<>(o); + return a.compareAndSet(o, obj2); + } + + @Test + public void onlyInitialValueVirtualMatchTest() { + testEscapeAnalysis("onlyInitialValueVirtualMatch", JavaConstant.INT_1, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } + + public static boolean bothVirtualNoMatchArray() { + AtomicReferenceArray array = new AtomicReferenceArray<>(1); + return array.compareAndSet(0, new Object(), new Object()); + } + + @Test + public void bothVirtualNoMatchArrayTest() { + testEscapeAnalysis("bothVirtualNoMatchArray", JavaConstant.INT_0, true); + assertTrue(graph.getNodes(LogicCompareAndSwapNode.TYPE).isEmpty()); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/PolymorphicInliningTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/PolymorphicInliningTest.java index 55ff31d737..6555b79d88 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/PolymorphicInliningTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/PolymorphicInliningTest.java @@ -48,6 +48,8 @@ import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.test.SubprocessUtil; import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import java.io.IOException; @@ -55,6 +57,11 @@ import java.util.List; public class PolymorphicInliningTest extends GraalCompilerTest { + @Before + public void checkJavaAgent() { + Assume.assumeFalse("Java Agent found -> skipping", SubprocessUtil.isJavaAgentAttached()); + } + @Test public void testInSubprocess() throws InterruptedException, IOException { String recursionPropName = getClass().getName() + ".recursion"; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java index 3f1c1f0169..02c96ab0bc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/StaticAnalysisTests.java @@ -120,7 +120,7 @@ public class StaticAnalysisTests { assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class)); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) static void test03Entry() { Data data = new Data(); data.f = new Integer(42); @@ -148,7 +148,7 @@ public class StaticAnalysisTests { assertEquals(m(sa, B.class, "foo").getFormalReturn(), t(Data.class), t(Integer.class)); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) static void test04Entry() { Data data = null; for (int i = 0; i < 2; i++) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java index a4da251fd7..898d8e1f75 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/CompilationWrapper.java @@ -41,7 +41,6 @@ import java.io.IOException; import java.io.PrintStream; import java.util.Map; -import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DiagnosticsOutputDirectory; import org.graalvm.compiler.debug.PathUtilities; @@ -163,8 +162,9 @@ public abstract class CompilationWrapper { * Creates the {@link DebugContext} to use when retrying a compilation. * * @param options the options for configuring the debug context + * @param logStream the log stream to use in the debug context */ - protected abstract DebugContext createRetryDebugContext(OptionValues options); + protected abstract DebugContext createRetryDebugContext(OptionValues options, PrintStream logStream); @SuppressWarnings("try") public final T run(DebugContext initialDebug) { @@ -227,22 +227,27 @@ public abstract class CompilationWrapper { return handleException(cause); } - String dir = this.outputDirectory.getPath(); - if (dir == null) { - return handleException(cause); - } - String dumpName = PathUtilities.sanitizeFileName(toString()); - File dumpPath = new File(dir, dumpName); - dumpPath.mkdirs(); - if (!dumpPath.exists()) { - TTY.println("Warning: could not create diagnostics directory " + dumpPath); - return handleException(cause); + File dumpPath = null; + try { + String dir = this.outputDirectory.getPath(); + if (dir != null) { + String dumpName = PathUtilities.sanitizeFileName(toString()); + dumpPath = new File(dir, dumpName); + dumpPath.mkdirs(); + if (!dumpPath.exists()) { + TTY.println("Warning: could not create diagnostics directory " + dumpPath); + dumpPath = null; + } + } + } catch (Throwable t) { + TTY.println("Warning: could not create Graal diagnostic directory"); + t.printStackTrace(TTY.out); } String message; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try (PrintStream ps = new PrintStream(baos)) { - ps.printf("%s: Compilation of %s failed: ", Thread.currentThread(), this); + ps.printf("%s: Compilation of %s failed:%n", Thread.currentThread(), this); cause.printStackTrace(ps); ps.printf("To disable compilation %s notifications, set %s to %s (e.g., -Dgraal.%s=%s).%n", causeType, @@ -253,11 +258,19 @@ public abstract class CompilationWrapper { causeType, actionKey.getName(), ExceptionAction.Print, actionKey.getName(), ExceptionAction.Print); - ps.println("Retrying compilation of " + this); + if (dumpPath != null) { + ps.println("Retrying compilation of " + this); + } else { + ps.println("Not retrying compilation of " + this + " as the dump path could not be created."); + } message = baos.toString(); } TTY.print(message); + if (dumpPath == null) { + return handleException(cause); + } + File retryLogFile = new File(dumpPath, "retry.log"); try (PrintStream ps = new PrintStream(new FileOutputStream(retryLogFile))) { ps.print(message); @@ -270,15 +283,27 @@ public abstract class CompilationWrapper { MethodFilter, null, DumpPath, dumpPath.getPath()); - try (DebugContext retryDebug = createRetryDebugContext(retryOptions); DebugCloseable s = retryDebug.disableIntercept()) { + ByteArrayOutputStream logBaos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(logBaos); + try (DebugContext retryDebug = createRetryDebugContext(retryOptions, ps)) { T res = performCompilation(retryDebug); + ps.println("There was no exception during retry."); maybeExitVM(action); return res; - } catch (Throwable ignore) { + } catch (Throwable e) { + ps.println("Exception during retry:"); + e.printStackTrace(ps); // Failures during retry are silent T res = handleException(cause); maybeExitVM(action); return res; + } finally { + ps.close(); + try (FileOutputStream fos = new FileOutputStream(retryLogFile, true)) { + fos.write(logBaos.toByteArray()); + } catch (Throwable e) { + TTY.printf("Error writing to %s: %s%n", retryLogFile, e); + } } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java index e0eef41f9f..06618ab3a3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java @@ -27,6 +27,8 @@ package org.graalvm.compiler.core.gen; import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isLegal; import static jdk.vm.ci.code.ValueUtil.isRegister; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.AllTargets; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks; import static org.graalvm.compiler.core.common.GraalOptions.MatchExpressions; import static org.graalvm.compiler.debug.DebugOptions.LogVerbose; import static org.graalvm.compiler.lir.LIR.verifyBlock; @@ -312,6 +314,19 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) { + if (MitigateSpeculativeExecutionAttacks.getValue(options) == AllTargets) { + boolean hasControlSplitPredecessor = false; + for (Block b : block.getPredecessors()) { + if (b.getSuccessorCount() > 1) { + hasControlSplitPredecessor = true; + break; + } + } + boolean isStartBlock = block.getPredecessorCount() == 0; + if (hasControlSplitPredecessor || isStartBlock) { + getLIRGeneratorTool().emitSpeculationFence(); + } + } } @Override @@ -372,6 +387,8 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio debug.log("interior match for %s", valueNode); } else if (operand instanceof ComplexMatchValue) { debug.log("complex match for %s", valueNode); + // Set current position to the position of the root matched node. + setSourcePosition(node.getNodeSourcePosition()); ComplexMatchValue match = (ComplexMatchValue) operand; operand = match.evaluate(this); if (operand != null) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java index c77278ad5f..587ac908b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java @@ -47,10 +47,13 @@ import org.graalvm.compiler.nodes.calc.IntegerTestNode; import org.graalvm.compiler.nodes.calc.LeftShiftNode; import org.graalvm.compiler.nodes.calc.MulNode; import org.graalvm.compiler.nodes.calc.NarrowNode; +import org.graalvm.compiler.nodes.calc.NegateNode; +import org.graalvm.compiler.nodes.calc.NotNode; import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; import org.graalvm.compiler.nodes.calc.OrNode; import org.graalvm.compiler.nodes.calc.PointerEqualsNode; import org.graalvm.compiler.nodes.calc.ReinterpretNode; +import org.graalvm.compiler.nodes.calc.RightShiftNode; import org.graalvm.compiler.nodes.calc.SignExtendNode; import org.graalvm.compiler.nodes.calc.SubNode; import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode; @@ -78,6 +81,8 @@ import jdk.vm.ci.meta.Value; @MatchableNode(nodeClass = WriteNode.class, inputs = {"address", "value"}) @MatchableNode(nodeClass = ZeroExtendNode.class, inputs = {"value"}) @MatchableNode(nodeClass = AndNode.class, inputs = {"x", "y"}, commutative = true) +@MatchableNode(nodeClass = NegateNode.class, inputs = {"value"}) +@MatchableNode(nodeClass = NotNode.class, inputs = {"value"}) @MatchableNode(nodeClass = FloatEqualsNode.class, inputs = {"x", "y"}, commutative = true) @MatchableNode(nodeClass = FloatLessThanNode.class, inputs = {"x", "y"}, commutative = true) @MatchableNode(nodeClass = PointerEqualsNode.class, inputs = {"x", "y"}, commutative = true) @@ -93,6 +98,7 @@ import jdk.vm.ci.meta.Value; @MatchableNode(nodeClass = PiNode.class, inputs = {"object"}) @MatchableNode(nodeClass = LogicCompareAndSwapNode.class, inputs = {"address", "expectedValue", "newValue"}) @MatchableNode(nodeClass = ValueCompareAndSwapNode.class, inputs = {"address", "expectedValue", "newValue"}) +@MatchableNode(nodeClass = RightShiftNode.class, inputs = {"x", "y"}) public abstract class NodeMatchRules { NodeLIRBuilder lirBuilder; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java index a5bce486fb..f4d60475e3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java @@ -34,7 +34,7 @@ import org.graalvm.compiler.nodes.LogicConstantNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.tiers.PhaseContext; /** @@ -68,7 +68,7 @@ public class GraphChangeMonitoringPhase extends PhaseSui * Phase may add nodes but not end up using them so ignore additions. Nodes going dead and * having their inputs change are the main interesting differences. */ - HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NodeEvent.NODE_ADDED); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener().exclude(NodeEvent.NODE_ADDED); StructuredGraph graphCopy = (StructuredGraph) graph.copy(graph.getDebug()); DebugContext debug = graph.getDebug(); try (NodeEventScope s = graphCopy.trackNodeEvents(listener)) { @@ -90,7 +90,7 @@ public class GraphChangeMonitoringPhase extends PhaseSui } if (!filteredNodes.isEmpty()) { /* rerun it on the real graph in a new Debug scope so Dump and Log can find it. */ - listener = new HashSetNodeEventListener(); + listener = new EconomicSetNodeEventListener(); try (NodeEventScope s = graph.trackNodeEvents(listener)) { try (DebugContext.Scope s2 = debug.scope("WithGraphChangeMonitoring")) { if (debug.isDumpEnabled(DebugContext.DETAILED_LEVEL)) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java index d5c5adf7f4..dd36b26699 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/MidTier.java @@ -24,6 +24,9 @@ package org.graalvm.compiler.core.phases; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.GuardTargets; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.NonDeoptGuardTargets; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks; import static org.graalvm.compiler.core.common.GraalOptions.ConditionalElimination; import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode; import static org.graalvm.compiler.core.common.GraalOptions.OptDeoptimizationGrouping; @@ -47,6 +50,7 @@ import org.graalvm.compiler.phases.common.FloatingReadPhase; import org.graalvm.compiler.phases.common.FrameStateAssignmentPhase; import org.graalvm.compiler.phases.common.GuardLoweringPhase; import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; +import org.graalvm.compiler.phases.common.InsertGuardFencesPhase; import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase; import org.graalvm.compiler.phases.common.LockEliminationPhase; import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; @@ -78,6 +82,10 @@ public class MidTier extends PhaseSuite { appendPhase(new GuardLoweringPhase()); + if (MitigateSpeculativeExecutionAttacks.getValue(options) == GuardTargets || MitigateSpeculativeExecutionAttacks.getValue(options) == NonDeoptGuardTargets) { + appendPhase(new InsertGuardFencesPhase()); + } + if (VerifyHeapAtReturn.getValue(options)) { appendPhase(new VerifyHeapAtReturnPhase()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java index f8df4bafb3..51fd42375e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java @@ -44,6 +44,7 @@ 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.options.OptionValues; import org.graalvm.compiler.phases.tiers.SuitesProvider; import org.graalvm.compiler.phases.tiers.TargetProvider; import org.graalvm.compiler.phases.util.Providers; @@ -153,7 +154,7 @@ public abstract class Backend implements TargetProvider, ValueKindFactory, Object> map = EconomicMap.create(); // Configure with an option that enables scopes map.put(DebugOptions.DumpOnError, true); @@ -226,6 +227,7 @@ public class DebugContextTest { @Test public void testDisabledSandbox() { + TimerKeyTest.assumeManagementLibraryIsLoadable(); EconomicMap, Object> map = EconomicMap.create(); // Configure with an option that enables scopes map.put(DebugOptions.DumpOnError, true); @@ -283,6 +285,7 @@ public class DebugContextTest { @Test public void testDisableIntercept() { + TimerKeyTest.assumeManagementLibraryIsLoadable(); EconomicMap, Object> map = EconomicMap.create(); // Configure with an option that enables scopes map.put(DebugOptions.DumpOnError, true); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java index 8937e83ce0..f1945112f5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java @@ -39,6 +39,7 @@ import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.serviceprovider.GraalServices; import org.junit.Assume; +import org.junit.AssumptionViolatedException; import org.junit.Before; import org.junit.Test; @@ -47,9 +48,20 @@ public class TimerKeyTest { @Before public void checkCapabilities() { + assumeManagementLibraryIsLoadable(); Assume.assumeTrue("skipping management interface test", GraalServices.isCurrentThreadCpuTimeSupported()); } + /** @see JDK-8076557 */ + static void assumeManagementLibraryIsLoadable() { + try { + /* Trigger loading of the management library using the bootstrap class loader. */ + GraalServices.getCurrentThreadAllocatedBytes(); + } catch (UnsatisfiedLinkError | NoClassDefFoundError | UnsupportedOperationException e) { + throw new AssumptionViolatedException("Management interface is unavailable: " + e); + } + } + /** * Actively spins the current thread for at least a given number of milliseconds in such a way * that timers for the current thread keep ticking over. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java index c344eb85d2..1ddaa06505 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java @@ -80,7 +80,7 @@ import jdk.vm.ci.meta.JavaMethod; */ public final class DebugContext implements AutoCloseable { - public static final Description NO_DESCRIPTION = null; + public static final Description NO_DESCRIPTION = new Description(null, "NO_DESCRIPTION"); public static final GlobalMetrics NO_GLOBAL_METRIC_VALUES = null; public static final Iterable NO_CONFIG_CUSTOMIZERS = Collections.emptyList(); @@ -404,6 +404,18 @@ public final class DebugContext implements AutoCloseable { return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), factories); } + public static DebugContext create(OptionValues options, PrintStream logStream, DebugHandlersFactory factory) { + return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, logStream, Immutable.create(options), Collections.singletonList(factory)); + } + + /** + * Creates a {@link DebugContext} based on a given set of option values and {@code factories}. + * The {@link DebugHandlersFactory#LOADER} can be used for the latter. + */ + public static DebugContext create(OptionValues options, Description description, Iterable factories) { + return new DebugContext(description, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), factories); + } + /** * Creates a {@link DebugContext}. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java index 0c34d0dfc5..ec237a3ec2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java @@ -127,8 +127,6 @@ public class DebugOptions { @Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.", type = OptionType.Debug) public static final OptionKey PrintBackendCFG = new OptionKey<>(true); - @Option(help = "Output probabilities for fixed nodes during binary graph dumping.", type = OptionType.Debug) - public static final OptionKey PrintGraphProbabilities = new OptionKey<>(false); @Option(help = "Enable dumping to the IdealGraphVisualizer.", type = OptionType.Debug) public static final OptionKey PrintGraph = new OptionKey<>(true); @Option(help = "Print graphs to files instead of sending them over the network.", type = OptionType.Debug) diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java index ae6dba5404..9ac88ba8fa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DiagnosticsOutputDirectory.java @@ -86,6 +86,7 @@ public class DiagnosticsOutputDirectory { } if (CLOSED.equals(path)) { TTY.println("Warning: Graal diagnostic directory already closed"); + return null; } return path; } @@ -129,6 +130,7 @@ public class DiagnosticsOutputDirectory { Path dir = Paths.get(outDir); if (dir.toFile().exists()) { + String prefix = new File(outDir).getName() + "/"; File zip = new File(outDir + ".zip").getAbsoluteFile(); List toDelete = new ArrayList<>(); try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip))) { @@ -137,7 +139,7 @@ public class DiagnosticsOutputDirectory { @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (attrs.isRegularFile()) { - String name = dir.relativize(file).toString(); + String name = prefix + dir.relativize(file).toString(); ZipEntry ze = new ZipEntry(name); zos.putNextEntry(ze); Files.copy(file, zos); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/GraphSnippetTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/GraphSnippetTest.java index 41982d0dc8..52db938e7e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/GraphSnippetTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test/graphio/GraphSnippetTest.java @@ -31,7 +31,7 @@ import org.junit.Assume; import org.junit.Test; public class GraphSnippetTest { - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) @Test public void dumpTheFile() throws Exception { Class snippets = null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java index 3720f5f971..a57337ca47 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeSourcePosition.java @@ -28,6 +28,7 @@ import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.None; import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Placeholder; import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Substitution; +import java.util.Iterator; import java.util.Objects; import org.graalvm.compiler.bytecode.BytecodeDisassembler; @@ -40,7 +41,7 @@ import jdk.vm.ci.meta.JavaMethod; import jdk.vm.ci.meta.MetaUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; -public class NodeSourcePosition extends BytecodePosition { +public class NodeSourcePosition extends BytecodePosition implements Iterable { private static final boolean STRICT_SOURCE_POSITION = Boolean.getBoolean("debug.graal.SourcePositionStrictChecks"); private static final boolean SOURCE_POSITION_BYTECODES = Boolean.getBoolean("debug.graal.SourcePositionDisassemble"); @@ -53,17 +54,16 @@ public class NodeSourcePosition extends BytecodePosition { * Remove marker frames. */ public NodeSourcePosition trim() { - if (marker != None) { - return null; + NodeSourcePosition lastMarker = null; + for (NodeSourcePosition current = this; current != null; current = current.getCaller()) { + if (current.marker != None) { + lastMarker = current; + } } - NodeSourcePosition caller = getCaller(); - if (caller != null) { - caller = caller.trim(); + if (lastMarker == null) { + return this; } - if (caller != getCaller()) { - return new NodeSourcePosition(caller, getMethod(), getBCI()); - } - return this; + return lastMarker.getCaller(); } public ResolvedJavaMethod getRootMethod() { @@ -81,6 +81,25 @@ public class NodeSourcePosition extends BytecodePosition { return true; } + @Override + public Iterator iterator() { + return new Iterator() { + private NodeSourcePosition currentPosition = NodeSourcePosition.this; + + @Override + public boolean hasNext() { + return currentPosition != null; + } + + @Override + public NodeSourcePosition next() { + NodeSourcePosition current = currentPosition; + currentPosition = currentPosition.getCaller(); + return current; + } + }; + } + enum Marker { None, Placeholder, @@ -124,11 +143,19 @@ public class NodeSourcePosition extends BytecodePosition { } public static NodeSourcePosition substitution(ResolvedJavaMethod method) { - return substitution(null, method); + return substitution(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI); + } + + public static NodeSourcePosition substitution(ResolvedJavaMethod method, int bci) { + return substitution(null, method, bci); } public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method) { - return new NodeSourcePosition(caller, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution); + return substitution(caller, method, BytecodeFrame.INVALID_FRAMESTATE_BCI); + } + + public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) { + return new NodeSourcePosition(caller, method, bci, Substitution); } public boolean isSubstitution() { @@ -195,10 +222,10 @@ public class NodeSourcePosition extends BytecodePosition { return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), 0); } assert link == null || isSubstitution || verifyCaller(this, link) : link; - - return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), getBCI()); + assert !isSubstitution || marker == None; + return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), getBCI(), isSubstitution ? Substitution : None); } else { - return new NodeSourcePosition(getCaller().addCaller(newSourceLanguagePosition, link, isSubstitution), getMethod(), getBCI()); + return new NodeSourcePosition(getCaller().addCaller(newSourceLanguagePosition, link, isSubstitution), getMethod(), getBCI(), marker); } } @@ -221,6 +248,9 @@ public class NodeSourcePosition extends BytecodePosition { private static void format(StringBuilder sb, NodeSourcePosition pos) { MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); + if (pos.marker != None) { + sb.append(" " + pos.marker); + } if (SOURCE_POSITION_BYTECODES) { String disassembly = BytecodeDisassembler.disassembleOne(pos.getMethod(), pos.getBCI()); if (disassembly != null && disassembly.length() > 0) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java index 3d86669ef6..94f37af9e5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java @@ -56,7 +56,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.Phase; @@ -148,7 +147,7 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { replacements = createReplacements(graalRuntime.getOptions(), p, snippetReflection, bytecodeProvider); } try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { - plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, stampProvider); + plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes); replacements.setGraphBuilderPlugins(plugins); } try (InitTimer rt = timer("create Suites provider")) { @@ -164,10 +163,9 @@ public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory { } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection, - HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, - HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, - replacements); + HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, + HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements); AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false); return plugins; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java index ad2245a8fc..07a2ef7da9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMoveFactory.java @@ -29,7 +29,7 @@ import static jdk.vm.ci.meta.JavaConstant.INT_0; import static jdk.vm.ci.meta.JavaConstant.LONG_0; import org.graalvm.compiler.core.aarch64.AArch64MoveFactory; -import org.graalvm.compiler.lir.LIRInstruction; +import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction; import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant; import jdk.vm.ci.hotspot.HotSpotConstant; @@ -52,7 +52,7 @@ public class AArch64HotSpotMoveFactory extends AArch64MoveFactory { } @Override - public LIRInstruction createLoad(AllocatableValue dst, Constant src) { + public AArch64LIRInstruction createLoad(AllocatableValue dst, Constant src) { Constant usedSource; if (COMPRESSED_NULL.equals(src)) { usedSource = INT_0; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiAndn.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiAndn.java new file mode 100644 index 0000000000..a6d9b49000 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiAndn.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64.test; + +import org.junit.Test; +import org.junit.Assert; + +/** + * Tests Bit Manipulation Instruction andn pattern matching and result. + */ +public class BmiAndn extends BmiCompilerTest { + // from Intel manual VEX.NDS.LZ.0F38.W0 F2 /r, example c4e260f2c2 + private final byte[] instrMask = new byte[]{ + (byte) 0xFF, + (byte) 0x1F, + (byte) 0x00, + (byte) 0xFF}; + private final byte[] instrPattern = new byte[]{ + (byte) 0xC4, // prefix for 3-byte VEX instruction + (byte) 0x02, // 00010 implied 0F 38 leading opcode bytes + (byte) 0x00, + (byte) 0xF2}; + + public int andni(int n1, int n2) { + return (n1 & (~n2)); + } + + public long andnl(long n1, long n2) { + return (n1 & (~n2)); + } + + // Pattern matching check for andni + @Test + public void test1() { + Assert.assertTrue(verifyPositive("andni", instrMask, instrPattern)); + } + + // Pattern matching check for andnl + @Test + public void test2() { + Assert.assertTrue(verifyPositive("andnl", instrMask, instrPattern)); + } + + // Result correctness check + @Test + public void test3() { + int n1 = 42; + int n2 = 100; + test("andni", n1, n2); + } + + @Test + public void test4() { + long n1 = 420000000; + long n2 = 1000000000; + test("andnl", n1, n2); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsi.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsi.java new file mode 100644 index 0000000000..ac6ec5d79d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsi.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64.test; + +import org.junit.Test; +import org.junit.Assert; + +/** + * Tests Bit Manipulation Instruction blsi pattern matching and result. + */ +public class BmiBlsi extends BmiCompilerTest { + // from Intel manual VEX.NDD.LZ.0F38.W0 F3 /3, example c4e260f2c2 + private final byte[] instrMask = new byte[]{ + (byte) 0xFF, + (byte) 0x1F, + (byte) 0x00, + (byte) 0xFF, + (byte) 0b0011_1000}; + private final byte[] instrPattern = new byte[]{ + (byte) 0xC4, // prefix for 3-byte VEX instruction + (byte) 0x02, // 00010 implied 0F 38 leading opcode bytes + (byte) 0x00, + (byte) 0xF3, + (byte) 0b0001_1000}; // bits 543 == 011 (3) + + public int blsii(int n1) { + return (n1 & (-n1)); + } + + public long blsil(long n1) { + return (n1 & (-n1)); + } + + // Pattern matching check for blsii + @Test + public void test1() { + Assert.assertTrue(verifyPositive("blsii", instrMask, instrPattern)); + } + + // Pattern matching check for blsil + @Test + public void test2() { + Assert.assertTrue(verifyPositive("blsil", instrMask, instrPattern)); + } + + // Result correctness check + @Test + public void test3() { + int n1 = 42; + test("blsii", n1); + } + + @Test + public void test4() { + long n1 = 420000000; + test("blsil", n1); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsmsk.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsmsk.java new file mode 100644 index 0000000000..e76c50b19b --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsmsk.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64.test; + +import org.junit.Test; +import org.junit.Assert; + +/** + * Tests Bit Manipulation Instruction blsmsk pattern matching and result. + */ +public class BmiBlsmsk extends BmiCompilerTest { + // from Intel manual VEX.NDD.LZ.0F38.W0 F3 /2, example c4e260f2c2 + private final byte[] instrMask = new byte[]{ + (byte) 0xFF, + (byte) 0x1F, + (byte) 0x00, + (byte) 0xFF, + (byte) 0b0011_1000}; + private final byte[] instrPattern = new byte[]{ + (byte) 0xC4, // prefix for 3-byte VEX instruction + (byte) 0x02, // 00010 implied 0F 38 leading opcode bytes + (byte) 0x00, + (byte) 0xF3, + (byte) 0b0001_0000}; // bits 543 == 010 (2) + + public int blsmski(int n1) { + return (n1 ^ (n1 - 1)); + } + + public long blsmskl(long n1) { + return (n1 ^ (n1 - 1)); + } + + // Pattern matching check for blsmski + @Test + public void test1() { + Assert.assertTrue(verifyPositive("blsmski", instrMask, instrPattern)); + } + + // Pattern matching check for blsmskl + @Test + public void test2() { + Assert.assertTrue(verifyPositive("blsmskl", instrMask, instrPattern)); + } + + // Result correctness check + @Test + public void test3() { + int n1 = 42; + test("blsmski", n1); + } + + @Test + public void test4() { + long n1 = 420000000; + test("blsmskl", n1); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsr.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsr.java new file mode 100644 index 0000000000..ff7865c1a8 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiBlsr.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64.test; + +import org.junit.Test; +import org.junit.Assert; + +/** + * Tests Bit Manipulation Instruction blsr pattern matching and result. + */ +public class BmiBlsr extends BmiCompilerTest { + // from Intel manual VEX.NDD.LZ.0F38.W0 F3 /3, example c4e260f2c2 + private final byte[] instrMask = new byte[]{ + (byte) 0xFF, + (byte) 0x1F, + (byte) 0x00, + (byte) 0xFF, + (byte) 0b0011_1000}; + private final byte[] instrPattern = new byte[]{ + (byte) 0xC4, // prefix for 3-byte VEX instruction + (byte) 0x02, // 00010 implied 0F 38 leading opcode bytes + (byte) 0x00, + (byte) 0xF3, + (byte) 0b0000_1000}; // bits 543 == 011 (3) + + public int blsri(int n1) { + return (n1 & (n1 - 1)); + } + + public long blsrl(long n1) { + return (n1 & (n1 - 1)); + } + + // Pattern matching check for blsri + @Test + public void test1() { + Assert.assertTrue(verifyPositive("blsri", instrMask, instrPattern)); + } + + // Pattern matching check for blsrl + @Test + public void test2() { + Assert.assertTrue(verifyPositive("blsrl", instrMask, instrPattern)); + } + + // Result correctness check + @Test + public void test3() { + int n1 = 42; + test("blsri", n1); + } + + @Test + public void test4() { + long n1 = 420000000; + test("blsrl", n1); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiCompilerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiCompilerTest.java new file mode 100644 index 0000000000..9dc9958cd0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/BmiCompilerTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64.test; + +import static org.junit.Assume.assumeTrue; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.junit.Assert; +import org.junit.Before; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.Architecture; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public abstract class BmiCompilerTest extends GraalCompilerTest { + + @Before + public void checkAMD64() { + Architecture arch = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget().arch; + assumeTrue("skipping AMD64 specific test", arch instanceof AMD64); + assumeTrue("skipping BMI1 specific test", ((AMD64) arch).getFeatures().contains(AMD64.CPUFeature.BMI1)); + } + + public boolean verifyPositive(String methodName, byte[] instrMask, byte[] instrPattern) { + ResolvedJavaMethod method = getResolvedJavaMethod(methodName); + StructuredGraph graph = parseForCompile(method); + + CompilationResult c = compile(method, graph); + byte[] targetCode = c.getTargetCode(); + + return countCpuInstructions(targetCode, instrMask, instrPattern) >= 1; + } + + public static int countCpuInstructions(byte[] nativeCode, byte[] instrMask, byte[] instrPattern) { + int count = 0; + int patternSize = Math.min(instrMask.length, instrPattern.length); + boolean found; + Assert.assertTrue(patternSize > 0); + for (int i = 0, n = nativeCode.length - patternSize; i < n;) { + found = true; + for (int j = 0; j < patternSize; j++) { + if ((nativeCode[i + j] & instrMask[j]) != instrPattern[j]) { + found = false; + break; + } + } + if (found) { + ++count; + i += patternSize - 1; + } + i++; + } + return count; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayIndexOfStub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayIndexOfStub.java new file mode 100644 index 0000000000..7f9efa76c9 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64ArrayIndexOfStub.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.amd64; + +import jdk.vm.ci.meta.JavaKind; +import org.graalvm.compiler.api.replacements.Snippet; +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; +import org.graalvm.compiler.hotspot.meta.HotSpotProviders; +import org.graalvm.compiler.hotspot.stubs.SnippetStub; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.replacements.amd64.AMD64ArrayIndexOfNode; +import jdk.internal.vm.compiler.word.Pointer; + +public class AMD64ArrayIndexOfStub extends SnippetStub { + + public AMD64ArrayIndexOfStub(ForeignCallDescriptor foreignCallDescriptor, OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) { + super(foreignCallDescriptor.getName(), options, providers, linkage); + } + + @Snippet + private static int indexOfTwoConsecutiveBytes(Pointer arrayPointer, int arrayLength, int searchValue) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, true, arrayPointer, arrayLength, searchValue); + } + + @Snippet + private static int indexOfTwoConsecutiveChars(Pointer arrayPointer, int arrayLength, int searchValue) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, true, arrayPointer, arrayLength, searchValue); + } + + @Snippet + private static int indexOf1Byte(Pointer arrayPointer, int arrayLength, byte b) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b); + } + + @Snippet + private static int indexOf2Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2); + } + + @Snippet + private static int indexOf3Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2, b3); + } + + @Snippet + private static int indexOf4Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3, byte b4) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Byte, arrayPointer, arrayLength, b1, b2, b3, b4); + } + + @Snippet + private static int indexOf1Char(Pointer arrayPointer, int arrayLength, char c) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c); + } + + @Snippet + private static int indexOf2Chars(Pointer arrayPointer, int arrayLength, char c1, char c2) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2); + } + + @Snippet + private static int indexOf3Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2, c3); + } + + @Snippet + private static int indexOf4Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4) { + return AMD64ArrayIndexOfNode.optimizedArrayIndexOf(JavaKind.Char, arrayPointer, arrayLength, c1, c2, c3, c4); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java index cd74c0fcbd..781ee1b1d3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java @@ -52,7 +52,6 @@ import org.graalvm.compiler.hotspot.meta.HotSpotStampProvider; import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider; import org.graalvm.compiler.hotspot.word.HotSpotWordTypes; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.nodes.spi.LoweringProvider; import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.common.AddressLoweringPhase; @@ -142,8 +141,7 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { replacements = createReplacements(options, p, snippetReflection, bytecodeProvider); } try (InitTimer rt = timer("create GraphBuilderPhase plugins")) { - plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, - stampProvider); + plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes); replacements.setGraphBuilderPlugins(plugins); } try (InitTimer rt = timer("create Suites provider")) { @@ -159,10 +157,9 @@ public class AMD64HotSpotBackendFactory implements HotSpotBackendFactory { } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, OptionValues options, TargetDescription target, - HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, - HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, - replacements); + HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, + HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) { + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements); AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue(options), false); return plugins; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java index 0a19c75e24..4dc758b55c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotCounterOp.java @@ -24,18 +24,21 @@ package org.graalvm.compiler.hotspot.amd64; -import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; -import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; import static jdk.vm.ci.amd64.AMD64.rax; import static jdk.vm.ci.amd64.AMD64.rbx; import static jdk.vm.ci.code.ValueUtil.asRegister; import static jdk.vm.ci.code.ValueUtil.isRegister; +import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; +import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler; import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.hotspot.HotSpotCounterOp; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotCounterOp; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; @@ -90,7 +93,7 @@ public class AMD64HotSpotCounterOp extends HotSpotCounterOp { // load counters array masm.movptr(countersArrayReg, countersArrayAddr); - CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(masm, countersArrayReg, increment, displacement); + CounterProcedure emitProcedure = (counterIndex, increment, displacement) -> emitIncrement(crb, masm, countersArrayReg, increment, displacement); forEachCounter(emitProcedure, target); // restore scratch register @@ -109,7 +112,7 @@ public class AMD64HotSpotCounterOp extends HotSpotCounterOp { return false; } - private static void emitIncrement(AMD64MacroAssembler masm, Register countersArrayReg, Value incrementValue, int displacement) { + private static void emitIncrement(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register countersArrayReg, Value incrementValue, int displacement) { // address for counter value AMD64Address counterAddr = new AMD64Address(countersArrayReg, displacement); // increment counter (in memory) @@ -119,6 +122,12 @@ public class AMD64HotSpotCounterOp extends HotSpotCounterOp { } else { masm.addq(counterAddr, asRegister(incrementValue)); } - + if (BenchmarkCounters.Options.AbortOnBenchmarkCounterOverflow.getValue(crb.getOptions())) { + Label target = new Label(); + masm.jccb(AMD64Assembler.ConditionFlag.NoOverflow, target); + crb.blockComment("[BENCHMARK COUNTER OVERFLOW]"); + masm.illegal(); + masm.bind(target); + } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java index 713ada7bbd..c9e51ed5b3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotForeignCallsProvider.java @@ -48,6 +48,7 @@ import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.replacements.amd64.AMD64ArrayIndexOf; import org.graalvm.compiler.word.WordTypes; import jdk.vm.ci.code.CallingConvention; @@ -108,6 +109,27 @@ public class AMD64HotSpotForeignCallsProvider extends HotSpotHostForeignCallsPro registerForeignCall(UPDATE_BYTES_CRC32C, config.updateBytesCRC32C, NativeCall, PRESERVES_REGISTERS, LEAF_NOFP, REEXECUTABLE_ONLY_AFTER_EXCEPTION, any()); } + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_1_BYTE, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_1_BYTE, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_2_BYTES, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_2_BYTES, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_3_BYTES, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_3_BYTES, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_4_BYTES, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_4_BYTES, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_1_CHAR, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_1_CHAR, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_2_CHARS, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_2_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_3_CHARS, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_3_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS))); + link(new AMD64ArrayIndexOfStub(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS, options, providers, + registerStubCall(AMD64ArrayIndexOf.STUB_INDEX_OF_4_CHARS, LEAF, REEXECUTABLE, NO_LOCATIONS))); + super.initialize(providers, options); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java index 5219604eff..15854797db 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java @@ -133,6 +133,11 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp return (HotSpotProviders) super.getProviders(); } + @Override + protected int getMaxVectorSize() { + return config.maxVectorSize; + } + /** * Utility for emitting the instruction to save RBP. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java new file mode 100644 index 0000000000..4245e17fd3 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.lir.test/src/org/graalvm/compiler/hotspot/lir/test/BenchmarkCounterOverflowTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018, 2018, 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.lir.test; + +import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine; +import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.graalvm.compiler.hotspot.debug.BenchmarkCounters; +import org.graalvm.compiler.lir.ConstantValue; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.lir.jtt.LIRTest; +import org.graalvm.compiler.lir.jtt.LIRTestSpecification; +import org.graalvm.compiler.test.SubprocessUtil; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.meta.JavaConstant; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class BenchmarkCounterOverflowTest extends LIRTest { + private static final String SUBPROCESS_PROPERTY = BenchmarkCounterOverflowTest.class.getSimpleName() + ".subprocess.call"; + private static final boolean VERBOSE = Boolean.getBoolean(BenchmarkCounterOverflowTest.class.getSimpleName() + ".verbose"); + + private static LIRKind intKind; + + @Before + public void checkAMD64() { + Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); + Assume.assumeTrue("skipping HotSpot specific test", getBackend() instanceof HotSpotBackend); + } + + @Before + public void setUp() { + intKind = LIRKind.fromJavaKind(getBackend().getTarget().arch, JavaKind.Long); + } + + private static final LIRTestSpecification constCounterIncrement = new LIRTestSpecification() { + @Override + public void generate(LIRGeneratorTool gen) { + gen.append(gen.createBenchmarkCounter("counter", "test", new ConstantValue(intKind, JavaConstant.forLong(Integer.MAX_VALUE)))); + } + }; + + @SuppressWarnings("unused") + @LIRIntrinsic + public static void counterInc(LIRTestSpecification spec) { + } + + public static void test(long count) { + for (long i = 0; i < count; i++) { + counterInc(constCounterIncrement); + GraalDirectives.blackhole(i); + } + } + + @Test + public void incrementCounter() { + Assume.assumeTrue("not a subprocess -> skip", Boolean.getBoolean(SUBPROCESS_PROPERTY)); + BenchmarkCounters.enabled = true; + + Object[] args = new Object[]{Integer.MAX_VALUE * 4L}; + ResolvedJavaMethod method = getResolvedJavaMethod("test"); + executeActualCheckDeopt(getInitialOptions(), method, EMPTY, null, args); + } + + @Test + public void spawnSubprocess() throws Throwable { + Assume.assumeFalse("subprocess already spawned -> skip", Boolean.getBoolean(SUBPROCESS_PROPERTY)); + List vmArgs = withoutDebuggerArguments(getVMCommandLine()); + vmArgs.add("-XX:JVMCICounterSize=1"); + vmArgs.add("-Dgraal." + BenchmarkCounters.Options.AbortOnBenchmarkCounterOverflow.getName() + "=true"); + vmArgs.add("-D" + SUBPROCESS_PROPERTY + "=true"); + + // Disable increment range checks (e.g. HotSpotCounterOp.checkIncrements()) + vmArgs.add("-dsa"); + vmArgs.add("-da"); + + List mainClassAndArgs = new ArrayList<>(); + mainClassAndArgs.add("com.oracle.mxtool.junit.MxJUnitWrapper"); + mainClassAndArgs.add(BenchmarkCounterOverflowTest.class.getName()); + + SubprocessUtil.Subprocess proc = SubprocessUtil.java(vmArgs, mainClassAndArgs); + + if (VERBOSE) { + System.out.println(proc); + } + + Assert.assertNotEquals("Expected non-zero exit status", 0, proc.exitCode); + + Iterator it = proc.output.iterator(); + while (it.hasNext()) { + String line = it.next(); + if (line.contains("Problematic frame:")) { + if (!it.hasNext()) { + // no more line + break; + } + line = it.next(); + if (line.contains(BenchmarkCounterOverflowTest.class.getName() + ".test")) { + return; + } + Assert.fail("Unexpected stack trace: " + line); + } + } + Assert.fail(String.format("Could not find method in output:%n%s", proc)); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java similarity index 98% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java index f340ca51d2..8f8f49228d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java @@ -22,7 +22,7 @@ */ -package org.graalvm.compiler.core.sparc.test; +package org.graalvm.compiler.hotspot.sparc.test; import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java index ce1dedf2a6..7c6e2be64c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java @@ -193,19 +193,19 @@ public class SPARCHotSpotBackend extends HotSpotHostBackend { @Override public void enter(CompilationResultBuilder crb) { final int frameSize = crb.frameMap.totalFrameSize(); - final int stackpoinerChange = -frameSize; + final int stackpointerChange = -frameSize; SPARCMacroAssembler masm = (SPARCMacroAssembler) crb.asm; if (!isStub) { emitStackOverflowCheck(crb); } - if (SPARCAssembler.isSimm13(stackpoinerChange)) { - masm.save(sp, stackpoinerChange, sp); + if (SPARCAssembler.isSimm13(stackpointerChange)) { + masm.save(sp, stackpointerChange, sp); } else { try (ScratchRegister sc = masm.getScratchRegister()) { Register scratch = sc.getRegister(); assert isGlobalRegister(scratch) : "Only global registers are allowed before save. Got register " + scratch; - masm.setx(stackpoinerChange, scratch, false); + masm.setx(stackpointerChange, scratch, false); masm.save(sp, scratch, sp); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java index 10edc6148b..153dc82420 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java @@ -104,7 +104,7 @@ public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory { HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes); BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection); HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(runtime.getOptions(), p, snippetReflection, bytecodeProvider, target); - Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, lowerer, stampProvider, snippetReflection, replacements, wordTypes); + Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, snippetReflection, replacements, wordTypes); replacements.setGraphBuilderPlugins(plugins); HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements); HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers, @@ -115,10 +115,9 @@ public class SPARCHotSpotBackendFactory implements HotSpotBackendFactory { } protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess, - HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotStampProvider stampProvider, + HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) { - Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider, - replacements); + Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, replacements); SPARCGraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), false); return plugins; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BigIntegerIntrinsicsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BigIntegerIntrinsicsTest.java new file mode 100644 index 0000000000..956bb10185 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/BigIntegerIntrinsicsTest.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.hotspot.test; + +import java.math.BigInteger; +import java.util.Random; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; +import org.graalvm.compiler.runtime.RuntimeProvider; + +import org.junit.Test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/* + * Indirectly test intrinsic/call substitutions for (innate) methods: + * + * BigInteger.implMultiplyToLen + * BigInteger.implMulAdd + * BigInteger.implMontgomeryMultiply + * BigInteger.implMontgomerySquare + * BigInteger.implSquareToLen + * + * via BigInteger.multiply() and .modPow(). Note that the actual substitution + * is not tested per se (only execution based on admissible intrinsics). + * + */ +public final class BigIntegerIntrinsicsTest extends MethodSubstitutionTest { + + static final int N = 100; + + @Test + public void testMultiplyToLen() throws ClassNotFoundException { + + // Intrinsic must be available. + org.junit.Assume.assumeTrue(config.useMultiplyToLenIntrinsic()); + // Test case is (currently) AMD64 only. + org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); + + Class javaclass = Class.forName("java.math.BigInteger"); + + TestIntrinsic tin = new TestIntrinsic("testMultiplyAux", javaclass, + "multiply", BigInteger.class); + + for (int i = 0; i < N; i++) { + + BigInteger big1 = randomBig(i); + BigInteger big2 = randomBig(i); + + // Invoke BigInteger BigInteger.multiply(BigInteger) + BigInteger res1 = (BigInteger) tin.invokeJava(big1, big2); + + // Invoke BigInteger testMultiplyAux(BigInteger) + BigInteger res2 = (BigInteger) tin.invokeTest(big1, big2); + + assertDeepEquals(res1, res2); + + // Invoke BigInteger testMultiplyAux(BigInteger) through code handle. + BigInteger res3 = (BigInteger) tin.invokeCode(big1, big2); + + assertDeepEquals(res1, res3); + } + } + + @Test + public void testMulAdd() throws ClassNotFoundException { + + // Intrinsic must be available. + org.junit.Assume.assumeTrue(config.useMulAddIntrinsic() || + config.useSquareToLenIntrinsic()); + // Test case is (currently) AMD64 only. + org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); + + Class javaclass = Class.forName("java.math.BigInteger"); + + TestIntrinsic tin = new TestIntrinsic("testMultiplyAux", javaclass, + "multiply", BigInteger.class); + + for (int i = 0; i < N; i++) { + + BigInteger big1 = randomBig(i); + + // Invoke BigInteger BigInteger.multiply(BigInteger) + BigInteger res1 = (BigInteger) tin.invokeJava(big1, big1); + + // Invoke BigInteger testMultiplyAux(BigInteger) + BigInteger res2 = (BigInteger) tin.invokeTest(big1, big1); + + assertDeepEquals(res1, res2); + + // Invoke BigInteger testMultiplyAux(BigInteger) through code handle. + BigInteger res3 = (BigInteger) tin.invokeCode(big1, big1); + + assertDeepEquals(res1, res3); + } + } + + @Test + public void testMontgomery() throws ClassNotFoundException { + + // Intrinsic must be available. + org.junit.Assume.assumeTrue(config.useMontgomeryMultiplyIntrinsic() || + config.useMontgomerySquareIntrinsic()); + // Test case is (currently) AMD64 only. + org.junit.Assume.assumeTrue(getTarget().arch instanceof AMD64); + + Class javaclass = Class.forName("java.math.BigInteger"); + + TestIntrinsic tin = new TestIntrinsic("testMontgomeryAux", javaclass, + "modPow", BigInteger.class, BigInteger.class); + + for (int i = 0; i < N; i++) { + + BigInteger big1 = randomBig(i); + BigInteger big2 = randomBig(i); + + // Invoke BigInteger BigInteger.modPow(BigExp, BigInteger) + BigInteger res1 = (BigInteger) tin.invokeJava(big1, bigTwo, big2); + + // Invoke BigInteger testMontgomeryAux(BigInteger, BigExp, BigInteger) + BigInteger res2 = (BigInteger) tin.invokeTest(big1, bigTwo, big2); + + assertDeepEquals(res1, res2); + + // Invoke BigInteger testMontgomeryAux(BigInteger, BigExp, BigInteger) through code + // handle. + BigInteger res3 = (BigInteger) tin.invokeCode(big1, bigTwo, big2); + + assertDeepEquals(res1, res3); + } + } + + public static BigInteger testMultiplyAux(BigInteger a, BigInteger b) { + return a.multiply(b); + } + + public static BigInteger testMontgomeryAux(BigInteger a, BigInteger exp, BigInteger b) { + return a.modPow(exp, b); + } + + private class TestIntrinsic { + + TestIntrinsic(String testmname, Class javaclass, String javamname, Class... params) { + + javamethod = getResolvedJavaMethod(javaclass, javamname, params); + testmethod = getResolvedJavaMethod(testmname); + + assert javamethod != null; + assert testmethod != null; + + // Force the test method to be compiled. + testcode = getCode(testmethod); + + assert testcode != null; + } + + Object invokeJava(BigInteger big, Object... args) { + + return invokeSafe(javamethod, big, args); + } + + Object invokeTest(Object... args) { + + return invokeSafe(testmethod, null, args); + } + + Object invokeCode(Object... args) { + + return executeVarargsSafe(testcode, args); + } + + // Private data section: + private ResolvedJavaMethod javamethod; + private ResolvedJavaMethod testmethod; + private InstalledCode testcode; + } + + private static GraalHotSpotVMConfig config = ((HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class)).getVMConfig(); + + private static BigInteger bigTwo = BigInteger.valueOf(2); + private static Random rnd = new Random(17); + + private static BigInteger randomBig(int i) { + return new BigInteger(rnd.nextInt(4096) + i2sz(i), rnd); + } + + private static int i2sz(int i) { + return i * 3 + 1; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java index 75aac871fb..84ce715e1b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java @@ -260,6 +260,9 @@ public class CheckGraalIntrinsics extends GraalTest { // Stub based intrinsics but implementation seems complex in C2 "sun/security/provider/DigestBase.implCompressMultiBlock([BII)I"); + // See JDK-8207146. + String oopName = isJDK12OrHigher() ? "Reference" : "Object"; + if (isJDK9OrHigher()) { // Relevant for Java flight recorder add(toBeInvestigated, @@ -304,6 +307,7 @@ public class CheckGraalIntrinsics extends GraalTest { * explicitly as the more generic method might be more restrictive and therefore slower * than necessary. */ + add(toBeInvestigated, // Mapped to compareAndExchange* "jdk/internal/misc/Unsafe.compareAndExchangeByteAcquire(Ljava/lang/Object;JBB)B", @@ -312,8 +316,8 @@ public class CheckGraalIntrinsics extends GraalTest { "jdk/internal/misc/Unsafe.compareAndExchangeIntRelease(Ljava/lang/Object;JII)I", "jdk/internal/misc/Unsafe.compareAndExchangeLongAcquire(Ljava/lang/Object;JJJ)J", "jdk/internal/misc/Unsafe.compareAndExchangeLongRelease(Ljava/lang/Object;JJJ)J", - "jdk/internal/misc/Unsafe.compareAndExchangeReferenceAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", - "jdk/internal/misc/Unsafe.compareAndExchangeReferenceRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchange" + oopName + "Acquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", + "jdk/internal/misc/Unsafe.compareAndExchange" + oopName + "Release(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", "jdk/internal/misc/Unsafe.compareAndExchangeShortAcquire(Ljava/lang/Object;JSS)S", "jdk/internal/misc/Unsafe.compareAndExchangeShortRelease(Ljava/lang/Object;JSS)S", @@ -330,10 +334,10 @@ public class CheckGraalIntrinsics extends GraalTest { "jdk/internal/misc/Unsafe.weakCompareAndSetLongAcquire(Ljava/lang/Object;JJJ)Z", "jdk/internal/misc/Unsafe.weakCompareAndSetLongPlain(Ljava/lang/Object;JJJ)Z", "jdk/internal/misc/Unsafe.weakCompareAndSetLongRelease(Ljava/lang/Object;JJJ)Z", - "jdk/internal/misc/Unsafe.weakCompareAndSetReference(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", - "jdk/internal/misc/Unsafe.weakCompareAndSetReferenceAcquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", - "jdk/internal/misc/Unsafe.weakCompareAndSetReferencePlain(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", - "jdk/internal/misc/Unsafe.weakCompareAndSetReferenceRelease(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSet" + oopName + "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSet" + oopName + "Acquire(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSet" + oopName + "Plain(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", + "jdk/internal/misc/Unsafe.weakCompareAndSet" + oopName + "Release(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z", "jdk/internal/misc/Unsafe.weakCompareAndSetShort(Ljava/lang/Object;JSS)Z", "jdk/internal/misc/Unsafe.weakCompareAndSetShortAcquire(Ljava/lang/Object;JSS)Z", "jdk/internal/misc/Unsafe.weakCompareAndSetShortPlain(Ljava/lang/Object;JSS)Z", @@ -344,10 +348,6 @@ public class CheckGraalIntrinsics extends GraalTest { "java/lang/StringCoding.hasNegatives([BII)Z", "java/lang/StringCoding.implEncodeISOArray([BI[BII)I", "java/lang/StringLatin1.indexOf([B[B)I", - "java/lang/StringLatin1.inflate([BI[BII)V", - "java/lang/StringLatin1.inflate([BI[CII)V", - "java/lang/StringUTF16.compress([BI[BII)I", - "java/lang/StringUTF16.compress([CI[BII)I", "java/lang/StringUTF16.getChar([BI)C", "java/lang/StringUTF16.getChars([BII[CI)V", "java/lang/StringUTF16.indexOf([BI[BII)I", @@ -387,6 +387,10 @@ public class CheckGraalIntrinsics extends GraalTest { // Can we implement these on non-AMD64 platforms? C2 seems to. add(toBeInvestigated, "java/lang/String.compareTo(Ljava/lang/String;)I", + "java/lang/StringLatin1.inflate([BI[BII)V", + "java/lang/StringLatin1.inflate([BI[CII)V", + "java/lang/StringUTF16.compress([BI[BII)I", + "java/lang/StringUTF16.compress([CI[BII)I", "jdk/internal/misc/Unsafe.compareAndExchangeByte(Ljava/lang/Object;JBB)B", "jdk/internal/misc/Unsafe.compareAndExchangeShort(Ljava/lang/Object;JSS)S", "jdk/internal/misc/Unsafe.compareAndSetByte(Ljava/lang/Object;JBB)Z", @@ -399,7 +403,7 @@ public class CheckGraalIntrinsics extends GraalTest { "sun/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J", "sun/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I", "sun/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J", - "sun/misc/Unsafe.getAndSetReference(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;"); + "sun/misc/Unsafe.getAndSet" + oopName + "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;"); if (isJDK9OrHigher()) { if (!(arch instanceof AArch64)) { @@ -412,7 +416,7 @@ public class CheckGraalIntrinsics extends GraalTest { "jdk/internal/misc/Unsafe.getAndAddLong(Ljava/lang/Object;JJ)J", "jdk/internal/misc/Unsafe.getAndSetInt(Ljava/lang/Object;JI)I", "jdk/internal/misc/Unsafe.getAndSetLong(Ljava/lang/Object;JJ)J", - "jdk/internal/misc/Unsafe.getAndSetReference(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;"); + "jdk/internal/misc/Unsafe.getAndSet" + oopName + "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;"); } add(toBeInvestigated, "jdk/internal/misc/Unsafe.getCharUnaligned(Ljava/lang/Object;J)C", @@ -527,6 +531,10 @@ public class CheckGraalIntrinsics extends GraalTest { return GraalServices.JAVA_SPECIFICATION_VERSION >= 11; } + private static boolean isJDK12OrHigher() { + return GraalServices.JAVA_SPECIFICATION_VERSION >= 12; + } + public interface Refiner { void refine(CheckGraalIntrinsics checker); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java index 87d42c4744..2fc5694f4e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java @@ -54,6 +54,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { */ @Test public void testVMCompilation1() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", "-XX:+UseJVMCICompiler", "-Dgraal.CompilationFailureAction=ExitVM", @@ -69,6 +70,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { */ @Test public void testVMCompilation2() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", "-XX:+UseJVMCICompiler", "-Dgraal.ExitVMOnException=true", @@ -109,6 +111,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { */ @Test public void testVMCompilation3() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); final int maxProblems = 2; Probe retryingProbe = new Probe("Retrying compilation of", maxProblems) { @Override @@ -146,6 +149,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { */ @Test public void testTruffleCompilation1() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList( "-Dgraal.CompilationFailureAction=ExitVM", @@ -175,6 +179,7 @@ public class CompilationWrapperTest extends GraalCompilerTest { */ @Test public void testTruffleCompilation3() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); Probe[] probes = { new Probe("Exiting VM due to TrufflePerformanceWarningsAreFatal=true", 1), }; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java index be70c20fac..c76070763e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ConstantPoolSubstitutionsTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -76,7 +76,7 @@ public class ConstantPoolSubstitutionsTests extends GraalCompilerTest { private static Object getConstantPoolForObject() { String miscPackage = Java8OrEarlier ? "sun.misc" - : (Java11OrEarlier ? "jdk.internal.misc" : "jdk.internal.access"); + : (Java11OrEarlier ? "jdk.internal.misc" : "jdk.internal.access"); try { Class sharedSecretsClass = Class.forName(miscPackage + ".SharedSecrets"); Class javaLangAccessClass = Class.forName(miscPackage + ".JavaLangAccess"); @@ -115,10 +115,11 @@ public class ConstantPoolSubstitutionsTests extends GraalCompilerTest { Object javaBaseModule = JLModule.fromClass(String.class); Object cModule = JLModule.fromClass(c); uncheckedAddExports(javaBaseModule, "jdk.internal.reflect", cModule); - if (Java11OrEarlier) + if (Java11OrEarlier) { uncheckedAddExports(javaBaseModule, "jdk.internal.misc", cModule); - else + } else { uncheckedAddExports(javaBaseModule, "jdk.internal.access", cModule); + } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java index 15f12d277f..5db46fee61 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/DataPatchTest.java @@ -28,7 +28,7 @@ package org.graalvm.compiler.hotspot.test; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java index 846cbda490..de637d85d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java @@ -60,6 +60,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase { @BeforeClass public static void checkVMArguments() { + assumeManagementLibraryIsLoadable(); /* * Note: The -Xcomp execution mode of the VM will stop most of the OSR test cases from * working as every method is compiled at level3 (followed by level4 on the second diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java index 20d476ad87..a7caf696a8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalCompilerTest.java @@ -28,7 +28,6 @@ import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.nodes.StructuredGraph; @@ -37,7 +36,6 @@ import org.graalvm.compiler.runtime.RuntimeProvider; import jdk.vm.ci.code.InstalledCode; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.runtime.JVMCI; /** * A Graal compiler test that needs access to the {@link HotSpotGraalRuntimeProvider}. @@ -53,12 +51,11 @@ public abstract class HotSpotGraalCompilerTest extends GraalCompilerTest { protected InstalledCode compileAndInstallSubstitution(Class c, String methodName) { ResolvedJavaMethod method = getMetaAccess().lookupJavaMethod(getMethod(c, methodName)); - HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler(); HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); HotSpotProviders providers = rt.getHostBackend().getProviders(); CompilationIdentifier compilationId = runtime().getHostBackend().getCompilationIdentifier(method); OptionValues options = getInitialOptions(); - StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, compilationId, options, getDebugContext(options)); + StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, compilationId, getDebugContext(options)); if (graph != null) { return getCode(method, graph, true, true, graph.getOptions()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java index 3b93165dce..2b292f8039 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalManagementTest.java @@ -73,8 +73,10 @@ public class HotSpotGraalManagementTest { public HotSpotGraalManagementTest() { try { + /* Trigger loading of the management library using the bootstrap class loader. */ + ManagementFactory.getThreadMXBean(); MBeanServerFactory.findMBeanServer(null); - } catch (NoClassDefFoundError e) { + } catch (UnsatisfiedLinkError | NoClassDefFoundError e) { throw new AssumptionViolatedException("Management classes/module(s) not available: " + e); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStackIntrospectionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStackIntrospectionTest.java index 1af819ea6e..18a4102236 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStackIntrospectionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotStackIntrospectionTest.java @@ -26,8 +26,6 @@ package org.graalvm.compiler.hotspot.test; import java.util.function.Function; -import org.graalvm.compiler.test.GraalTest; -import org.junit.Assume; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -80,15 +78,11 @@ public class HotSpotStackIntrospectionTest extends HotSpotGraalCompilerTest { @Test public void run() throws InvalidInstalledCodeException { - // The JDK9 bits are currently broken - Assume.assumeTrue(GraalTest.Java8OrEarlier); test("testSnippet"); } @Test public void runSynchronized() throws InvalidInstalledCodeException { - // The JDK9 bits are currently broken - Assume.assumeTrue(GraalTest.Java8OrEarlier); test("testSynchronizedSnippet"); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java index 0d417cd73f..99592e91a9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/JVMCIInfopointErrorTest.java @@ -148,7 +148,7 @@ public class JVMCIInfopointErrorTest extends GraalCompilerTest { CompilationResult compResult = compile(method, graph); CodeCacheProvider codeCache = getCodeCache(); - HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, method, null, compResult); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, method, null, compResult, getInitialOptions()); codeCache.addCode(method, compiledCode, null, null); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java index 699c613ce6..8c7d39d5f7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java @@ -32,7 +32,6 @@ import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.core.test.GraalCompilerTest; import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.hotspot.HotSpotGraalCompiler; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; import org.graalvm.compiler.nodes.StructuredGraph; @@ -48,7 +47,6 @@ import org.junit.Test; import jdk.vm.ci.hotspot.HotSpotVMConfigStore; import jdk.vm.ci.hotspot.VMIntrinsicMethod; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.runtime.JVMCI; /** * Exercise the compilation of intrinsic method substitutions. @@ -58,7 +56,6 @@ public class TestIntrinsicCompiles extends GraalCompilerTest { @Test @SuppressWarnings("try") public void test() throws ClassNotFoundException { - HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) JVMCI.getRuntime().getCompiler(); HotSpotGraalRuntimeProvider rt = (HotSpotGraalRuntimeProvider) Graal.getRequiredCapability(RuntimeProvider.class); HotSpotProviders providers = rt.getHostBackend().getProviders(); Plugins graphBuilderPlugins = providers.getGraphBuilderPlugins(); @@ -75,7 +72,7 @@ public class TestIntrinsicCompiles extends GraalCompilerTest { if (plugin instanceof MethodSubstitutionPlugin) { ResolvedJavaMethod method = CheckGraalIntrinsics.resolveIntrinsic(getMetaAccess(), intrinsic); if (!method.isNative()) { - StructuredGraph graph = compiler.getIntrinsicGraph(method, providers, INVALID_COMPILATION_ID, options, debug); + StructuredGraph graph = providers.getReplacements().getIntrinsicGraph(method, INVALID_COMPILATION_ID, debug); getCode(method, graph); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java index 641d6e247c..de931a85e1 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationStatistics.java @@ -24,8 +24,6 @@ package org.graalvm.compiler.hotspot; -import static java.lang.Thread.currentThread; - import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; @@ -37,7 +35,6 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.Deque; import java.util.Locale; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java index e0596989d9..955466b6ea 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java @@ -31,6 +31,7 @@ import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureA import static org.graalvm.compiler.core.phases.HighTier.Options.Inline; import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing; +import java.io.PrintStream; import java.util.List; import jdk.internal.vm.compiler.collections.EconomicMap; @@ -105,9 +106,9 @@ public class CompilationTask { } @Override - protected DebugContext createRetryDebugContext(OptionValues retryOptions) { + protected DebugContext createRetryDebugContext(OptionValues retryOptions, PrintStream logStream) { SnippetReflectionProvider snippetReflection = compiler.getGraalRuntime().getHostProviders().getSnippetReflection(); - return DebugContext.create(retryOptions, new GraalDebugHandlersFactory(snippetReflection)); + return DebugContext.create(retryOptions, logStream, new GraalDebugHandlersFactory(snippetReflection)); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java index 80db6566fb..9af297acb9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java @@ -652,11 +652,13 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase { public final long newInstanceAddress = getAddress("JVMCIRuntime::new_instance"); public final long newArrayAddress = getAddress("JVMCIRuntime::new_array"); public final long newMultiArrayAddress = getAddress("JVMCIRuntime::new_multi_array"); + public final long dynamicNewInstanceAddress = getAddress("JVMCIRuntime::dynamic_new_instance"); // Allocation stubs that return null when allocation fails public final long newInstanceOrNullAddress = getAddress("JVMCIRuntime::new_instance_or_null", 0L); public final long newArrayOrNullAddress = getAddress("JVMCIRuntime::new_array_or_null", 0L); public final long newMultiArrayOrNullAddress = getAddress("JVMCIRuntime::new_multi_array_or_null", 0L); + public final long dynamicNewInstanceOrNullAddress = getAddress("JVMCIRuntime::dynamic_new_instance_or_null", 0L); public boolean areNullAllocationStubsAvailable() { return newInstanceOrNullAddress != 0L; @@ -669,9 +671,11 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase { if (newInstanceOrNullAddress == 0L) { assert newArrayOrNullAddress == 0L; assert newMultiArrayOrNullAddress == 0L; + assert dynamicNewInstanceOrNullAddress == 0L; } else { assert newArrayOrNullAddress != 0L; assert newMultiArrayOrNullAddress != 0L; + assert dynamicNewInstanceOrNullAddress != 0L; } return true; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java index 728b368792..70ffc57b62 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java @@ -34,7 +34,7 @@ import jdk.vm.ci.hotspot.HotSpotVMConfigStore; * * Fields are grouped according to the most recent JBS issue showing why they are versioned. * - * JDK Version: 11+ + * JDK Version: 12+ */ final class GraalHotSpotVMConfigVersioned extends HotSpotVMConfigAccess { @@ -42,13 +42,8 @@ final class GraalHotSpotVMConfigVersioned extends HotSpotVMConfigAccess { super(store); } - private boolean initInlineNotify() { - String syncKnobs = getFlag("SyncKnobs", String.class, ""); - return syncKnobs == null || !syncKnobs.contains("InlineNotify=0"); - } - - // JSK-8132287 - boolean inlineNotify = initInlineNotify(); + // JDK-8210848 + boolean inlineNotify = true; // JDK-8073583 boolean useCRC32CIntrinsics = getFlag("UseCRC32CIntrinsics", Boolean.class); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java index a08613f534..f4c445a48c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java @@ -441,9 +441,14 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen } @Override - public CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compResult) { + public CompiledCode createCompiledCode(ResolvedJavaMethod method, + CompilationRequest compilationRequest, + CompilationResult compResult, + boolean isDefault, + OptionValues options) { + assert !isDefault || compResult.getName() == null : "a default nmethod should have a null name since it is associated with a Method*"; HotSpotCompilationRequest compRequest = compilationRequest instanceof HotSpotCompilationRequest ? (HotSpotCompilationRequest) compilationRequest : null; - return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult); + return HotSpotCompiledCodeBuilder.createCompiledCode(getCodeCache(), method, compRequest, compResult, options); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java index 5d2f4b5764..af199db984 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot; +import static org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder.Options.ShowSubstitutionSourceInfo; import static org.graalvm.util.CollectionsUtil.anyMatch; import java.nio.ByteBuffer; @@ -33,10 +34,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.EnumMap; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.stream.Stream; import java.util.stream.Stream.Builder; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.code.CompilationResult.CodeAnnotation; import org.graalvm.compiler.code.CompilationResult.CodeComment; @@ -45,6 +49,9 @@ import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.options.Option; +import org.graalvm.compiler.options.OptionKey; +import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.CodeCacheProvider; import jdk.vm.ci.code.DebugInfo; @@ -64,14 +71,20 @@ import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.ResolvedJavaMethod; public class HotSpotCompiledCodeBuilder { + public static class Options { + // @formatter:off + @Option(help = "Controls whether the source position information of snippets and method substitutions" + + " are exposed to HotSpot. Can be useful when profiling to get more precise position information.") + public static final OptionKey ShowSubstitutionSourceInfo = new OptionKey<>(false); + } - public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult) { + public static HotSpotCompiledCode createCompiledCode(CodeCacheProvider codeCache, ResolvedJavaMethod method, HotSpotCompilationRequest compRequest, CompilationResult compResult, OptionValues options) { String name = compResult.getName(); byte[] targetCode = compResult.getTargetCode(); int targetCodeSize = compResult.getTargetCodeSize(); - Site[] sites = getSortedSites(codeCache, compResult); + Site[] sites = getSortedSites(compResult, options, codeCache.shouldDebugNonSafepoints() && method != null); Assumption[] assumptions = compResult.getAssumptions(); @@ -205,7 +218,7 @@ public class HotSpotCompiledCodeBuilder { * {@code DebugInformationRecorder::add_new_pc_offset}). In addition, it expects * {@link Infopoint} PCs to be unique. */ - private static Site[] getSortedSites(CodeCacheProvider codeCache, CompilationResult target) { + private static Site[] getSortedSites(CompilationResult target, OptionValues options, boolean includeSourceInfo) { List sites = new ArrayList<>( target.getExceptionHandlers().size() + target.getInfopoints().size() + target.getDataPatches().size() + target.getMarks().size() + target.getSourceMappings().size()); sites.addAll(target.getExceptionHandlers()); @@ -213,39 +226,89 @@ public class HotSpotCompiledCodeBuilder { sites.addAll(target.getDataPatches()); sites.addAll(target.getMarks()); - if (codeCache.shouldDebugNonSafepoints()) { + if (includeSourceInfo) { /* * Translate the source mapping into appropriate info points. In HotSpot only one * position can really be represented and recording the end PC seems to give the best * results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these * unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case. */ - List sourcePositionSites = new ArrayList<>(); - for (SourceMapping source : target.getSourceMappings()) { - NodeSourcePosition sourcePosition = source.getSourcePosition(); - if (sourcePosition.isPlaceholder() || sourcePosition.isSubstitution()) { - // HotSpot doesn't understand any of the special positions so just drop them. - continue; - } - assert sourcePosition.verify(); - sourcePosition = sourcePosition.trim(); - /* - * Don't add BYTECODE_POSITION info points that would potentially create conflicts. - * Under certain conditions the site's pc is not the pc that gets recorded by - * HotSpot (see @code {CodeInstaller::site_Call}). So, avoid adding any source - * positions that can potentially map to the same pc. To do that make sure that the - * source mapping doesn't contain a pc of any important Site. - */ - if (sourcePosition != null && !anyMatch(sites, s -> source.contains(s.pcOffset))) { - sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION)); + List sourceMappings = new ArrayList<>(); + ListIterator sourceMappingListIterator = target.getSourceMappings().listIterator(); + if (sourceMappingListIterator.hasNext()) { + SourceMapping currentSource = sourceMappingListIterator.next(); + NodeSourcePosition sourcePosition = currentSource.getSourcePosition(); + if (!sourcePosition.isPlaceholder() && !sourcePosition.isSubstitution()) { + sourceMappings.add(currentSource); + } + while (sourceMappingListIterator.hasNext()) { + SourceMapping nextSource = sourceMappingListIterator.next(); + assert currentSource.getStartOffset() <= nextSource.getStartOffset() : "Must be presorted"; + currentSource = nextSource; + sourcePosition = currentSource.getSourcePosition(); + if (!sourcePosition.isPlaceholder() && !sourcePosition.isSubstitution()) { + sourceMappings.add(currentSource); + } } } + + /* + * Don't add BYTECODE_POSITION info points that would potentially create conflicts. + * Under certain conditions the site's pc is not the pc that gets recorded by HotSpot + * (see @code {CodeInstaller::site_Call}). So, avoid adding any source positions that + * can potentially map to the same pc. To do that the following code makes sure that the + * source mapping doesn't contain a pc of any important Site. + */ + sites.sort(new SiteComparator()); + + ListIterator siteListIterator = sites.listIterator(); + sourceMappingListIterator = sourceMappings.listIterator(); + + List sourcePositionSites = new ArrayList<>(); + Site site = null; + + // Iterate over sourceMappings and sites in parallel. Create source position infopoints + // only for source mappings that don't have any sites inside their intervals. + while (sourceMappingListIterator.hasNext()) { + SourceMapping source = sourceMappingListIterator.next(); + + // Skip sites before the current source mapping + if (site == null || site.pcOffset < source.getStartOffset()) { + while (siteListIterator.hasNext()) { + site = siteListIterator.next(); + if (site.pcOffset >= source.getStartOffset()) { + break; + } + } + } + assert !siteListIterator.hasNext() || site.pcOffset >= source.getStartOffset(); + if (site != null && source.getStartOffset() <= site.pcOffset && site.pcOffset <= source.getEndOffset()) { + // Conflicting source mapping, skip it. + continue; + } else { + // Since the sites are sorted there can not be any more sites in this interval. + } + assert !siteListIterator.hasNext() || site.pcOffset > source.getEndOffset(); + // Good source mapping. Create an infopoint and add it to the list. + NodeSourcePosition sourcePosition = source.getSourcePosition(); + assert sourcePosition.verify(); + if (!ShowSubstitutionSourceInfo.getValue(options)) { + sourcePosition = sourcePosition.trim(); + assert verifyTrim(sourcePosition); + } + if (sourcePosition != null) { + assert !anyMatch(sites, s -> source.getStartOffset() <= s.pcOffset && s.pcOffset <= source.getEndOffset()); + sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION)); + } + } + sites.addAll(sourcePositionSites); } SiteComparator c = new SiteComparator(); Collections.sort(sites, c); + if (c.sawCollidingInfopoints) { Infopoint lastInfopoint = null; List copy = new ArrayList<>(sites.size()); @@ -265,6 +328,14 @@ public class HotSpotCompiledCodeBuilder { } sites = copy; } + return sites.toArray(new Site[sites.size()]); } + + private static boolean verifyTrim(NodeSourcePosition sourcePosition) { + for (NodeSourcePosition sp = sourcePosition; sp != null; sp = sp.getCaller()) { + assert (sp.getMethod().getAnnotation(Snippet.class) == null && sp.getMethod().getAnnotation(MethodSubstitution.class) == null); + } + return true; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java index 1f315ba8d0..958a4ef88b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java @@ -27,6 +27,8 @@ package org.graalvm.compiler.hotspot; import static jdk.vm.ci.code.ValueUtil.isRegister; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; +import static org.graalvm.compiler.nodes.debug.DynamicCounterNode.MAX_INCREMENT; +import static org.graalvm.compiler.nodes.debug.DynamicCounterNode.MIN_INCREMENT; import java.util.Arrays; @@ -69,6 +71,21 @@ public abstract class HotSpotCounterOp extends LIRInstruction { this.increments = increments; this.thread = registers.getThreadRegister(); this.config = config; + checkIncrements(); + } + + private boolean checkIncrements() { + for (int i = 0; i < increments.length; i++) { + Value increment = increments[i]; + if (isJavaConstant(increment)) { + long incValue = asLong(asJavaConstant(increment)); + if (incValue < MIN_INCREMENT || incValue > MAX_INCREMENT) { + String message = String.format("Benchmark counter %s:%s has increment out of range [%d .. %d]: %d", groups[i], names[i], MIN_INCREMENT, MAX_INCREMENT, incValue); + assert false : message; + } + } + } + return true; } protected static int getDisplacementForLongIndex(TargetDescription target, long index) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java index 98d634c795..a42d84b2c6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.hotspot; import static org.graalvm.compiler.core.common.GraalOptions.OptAssumptions; -import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; import java.io.ByteArrayOutputStream; import java.io.PrintStream; @@ -35,8 +34,6 @@ import java.util.Formatter; import java.util.List; import org.graalvm.compiler.api.runtime.GraalJVMCICompiler; -import org.graalvm.compiler.bytecode.Bytecode; -import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.GraalCompiler; import org.graalvm.compiler.core.common.CompilationIdentifier; @@ -54,9 +51,6 @@ import org.graalvm.compiler.lir.phases.LIRSuites; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; -import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins; -import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; -import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization; @@ -139,7 +133,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { } CompilationTask task = new CompilationTask(jvmciRuntime, this, hsRequest, true, installAsDefault, options); CompilationRequestResult r = null; - try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories()); + try (DebugContext debug = graalRuntime.openDebugContext(options, task.getCompilationIdentifier(), method, getDebugHandlersFactories(), DebugContext.DEFAULT_LOG_STREAM); Activation a = debug.activate()) { r = task.runCompilation(debug); } @@ -152,7 +146,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { HotSpotBackend backend = graalRuntime.getHostBackend(); HotSpotProviders providers = backend.getProviders(); final boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; - StructuredGraph graph = method.isNative() || isOSR ? null : getIntrinsicGraph(method, providers, compilationId, options, debug); + StructuredGraph graph = method.isNative() || isOSR ? null : providers.getReplacements().getIntrinsicGraph(method, compilationId, debug); if (graph == null) { SpeculationLog speculationLog = method.getSpeculationLog(); @@ -204,47 +198,6 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler { return compileHelper(CompilationResultBuilderFactory.Default, result, graph, method, entryBCI, useProfilingInfo, options); } - /** - * Gets a graph produced from the intrinsic for a given method that can be compiled and - * installed for the method. - * - * @param method - * @param compilationId - * @param options - * @param debug - * @return an intrinsic graph that can be compiled and installed for {@code method} or null - */ - @SuppressWarnings("try") - public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, HotSpotProviders providers, CompilationIdentifier compilationId, OptionValues options, DebugContext debug) { - Replacements replacements = providers.getReplacements(); - Bytecode subst = replacements.getSubstitutionBytecode(method); - if (subst != null) { - ResolvedJavaMethod substMethod = subst.getMethod(); - assert !substMethod.equals(method); - BytecodeProvider bytecodeProvider = subst.getOrigin(); - // @formatter:off - StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES). - method(substMethod). - compilationId(compilationId). - recordInlinedMethods(bytecodeProvider.shouldRecordMethodDependencies()). - setIsSubstitution(true). - build(); - // @formatter:on - try (DebugContext.Scope scope = debug.scope("GetIntrinsicGraph", graph)) { - Plugins plugins = new Plugins(providers.getGraphBuilderPlugins()); - GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); - IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, bytecodeProvider, ROOT_COMPILATION); - new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, - OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); - assert !graph.isFrozen(); - return graph; - } catch (Throwable e) { - debug.handle(e); - } - } - return null; - } - protected OptimisticOptimizations getOptimisticOpts(ProfilingInfo profilingInfo, OptionValues options) { return new OptimisticOptimizations(profilingInfo, options); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java index a7b43ce8c4..a4c83d2c0e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java @@ -28,8 +28,8 @@ import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining; -import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM; +import java.io.PrintStream; import java.util.ArrayList; import java.util.EnumMap; import java.util.List; @@ -276,7 +276,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { } @Override - public DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable factories) { + public DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable factories, PrintStream logStream) { if (management != null && management.poll(false) != null) { if (compilable instanceof HotSpotResolvedJavaMethod) { HotSpotResolvedObjectType type = ((HotSpotResolvedJavaMethod) compilable).getDeclaringClass(); @@ -294,7 +294,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider { } } Description description = new Description(compilable, compilationId.toString(CompilationIdentifier.Verbosity.ID)); - return DebugContext.create(compilationOptions, description, metricValues, DEFAULT_LOG_STREAM, factories); + return DebugContext.create(compilationOptions, description, metricValues, logStream, factories); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java index 1bd00c6594..b349deaea4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java @@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot; +import java.io.PrintStream; import java.util.Map; import org.graalvm.compiler.api.runtime.GraalRuntime; @@ -69,8 +70,9 @@ public interface HotSpotGraalRuntimeProvider extends GraalRuntime, RuntimeProvid * @param compilationOptions the options used to configure the compilation debug context * @param compilationId a system wide unique compilation id * @param compilable the input to the compilation + * @param logStream the log stream to use in this context */ - DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable factories); + DebugContext openDebugContext(OptionValues compilationOptions, CompilationIdentifier compilationId, Object compilable, Iterable factories, PrintStream logStream); /** * Gets the option values associated with this runtime. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java index a780ff0771..687413386d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotHostBackend.java @@ -42,6 +42,7 @@ import org.graalvm.compiler.lir.framemap.ReferenceMapBuilder; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; +import org.graalvm.compiler.word.Word; import jdk.vm.ci.code.CallingConvention; import jdk.vm.ci.common.InitTimer; @@ -50,7 +51,6 @@ import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.runtime.JVMCICompiler; -import org.graalvm.compiler.word.Word; /** * Common functionality of HotSpot host backends. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java index 95615191b6..250cc21a29 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/BenchmarkCounters.java @@ -75,7 +75,7 @@ import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; */ public class BenchmarkCounters { - static class Options { + public static class Options { //@formatter:off @Option(help = "Turn on the benchmark counters, and displays the results on VM shutdown", type = OptionType.Debug) @@ -95,6 +95,8 @@ public class BenchmarkCounters { public static final OptionKey BenchmarkCountersDumpDynamic = new OptionKey<>(true); @Option(help = "Dump static counters", type = OptionType.Debug) public static final OptionKey BenchmarkCountersDumpStatic = new OptionKey<>(false); + @Option(help = "file:doc-files/AbortOnBenchmarkCounterOverflowHelp.txt", type = OptionType.Debug) + public static final OptionKey AbortOnBenchmarkCounterOverflow = new OptionKey<>(false); //@formatter:on } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/AbortOnBenchmarkCounterOverflowHelp.txt b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/AbortOnBenchmarkCounterOverflowHelp.txt new file mode 100644 index 0000000000..840dcc407e --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/AbortOnBenchmarkCounterOverflowHelp.txt @@ -0,0 +1,4 @@ +Abort VM with SIGILL if benchmark counters controlled by the (Generic|Timed|Benchmark)DynamicCounters +option overflow. This feature is only supported on AMD64. +WARNING: No descriptive error message will be printed! In case of an overflow, +manual inspection of the emitted code is required. \ No newline at end of file diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt index 8d5ddf9470..0a2ef8b5c2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/debug/doc-files/BenchmarkDynamicCountersHelp.txt @@ -1,8 +1,8 @@ -Turn on the benchmark counters, and listen for specific patterns on System.out/System.err. -The format of this option is: +Turn on the benchmark counters. The format of this option is: (err|out),start pattern,end pattern +Start counting when the start pattern matches on the given stream and stop when the end pattern occurs. You can use "~" to match 1 or more digits. Examples: @@ -21,4 +21,7 @@ about allocations within the DaCapo pmd benchmark: The JVMCICounterSize value depends on the granularity of the profiling - 10000 should be sufficient. Omit JVMCICountersExcludeCompiler to exclude counting allocations on the compiler threads. -The counters can be further configured by the ProfileAllocationsContext option. \ No newline at end of file +The counters can be further configured by the ProfileAllocationsContext option. + +We highly recommend the use of -Dgraal.AbortOnBenchmarkCounterOverflow=true to +detect counter overflows eagerly. \ No newline at end of file diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java index 0a74d58d3a..c15aaa7a94 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java @@ -773,20 +773,6 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider return field.getOffset(); } - @Override - public int arrayScalingFactor(JavaKind kind) { - if (runtime.getVMConfig().useCompressedOops && kind == JavaKind.Object) { - return super.arrayScalingFactor(JavaKind.Int); - } else { - return super.arrayScalingFactor(kind); - } - } - - @Override - public int arrayBaseOffset(JavaKind kind) { - return metaAccess.getArrayBaseOffset(kind); - } - @Override public int arrayLengthOffset() { return runtime.getVMConfig().arrayOopDescLengthOffset(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java index 003c16ab91..2faa802a39 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java @@ -109,9 +109,21 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC * cannot be re-executed. * @param killedLocations the memory locations killed by the stub call */ - public HotSpotForeignCallLinkage registerStubCall(ForeignCallDescriptor descriptor, Transition transition, Reexecutability reexecutability, + public HotSpotForeignCallLinkage registerStubCall( + ForeignCallDescriptor descriptor, + Transition transition, + Reexecutability reexecutability, LocationIdentity... killedLocations) { - return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, 0L, PRESERVES_REGISTERS, JavaCall, JavaCallee, transition, reexecutability, + return register(HotSpotForeignCallLinkageImpl.create(metaAccess, + codeCache, + wordTypes, + this, + descriptor, + 0L, PRESERVES_REGISTERS, + JavaCall, + JavaCallee, + transition, + reexecutability, killedLocations)); } @@ -119,7 +131,7 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC * Creates and registers the linkage for a foreign call. * * @param descriptor the signature of the foreign call - * @param address the address of the code to call + * @param address the address of the code to call (must be non-zero) * @param outgoingCcType outgoing (caller) calling convention type * @param effect specifies if the call destroys or preserves all registers (apart from * temporaries which are always destroyed) @@ -129,16 +141,34 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC * cannot be re-executed. * @param killedLocations the memory locations killed by the foreign call */ - public HotSpotForeignCallLinkage registerForeignCall(ForeignCallDescriptor descriptor, long address, CallingConvention.Type outgoingCcType, RegisterEffect effect, Transition transition, - Reexecutability reexecutability, LocationIdentity... killedLocations) { + public HotSpotForeignCallLinkage registerForeignCall( + ForeignCallDescriptor descriptor, + long address, + CallingConvention.Type outgoingCcType, + RegisterEffect effect, + Transition transition, + Reexecutability reexecutability, + LocationIdentity... killedLocations) { Class resultType = descriptor.getResultType(); - assert address != 0; + assert address != 0 : descriptor; assert transition != SAFEPOINT || resultType.isPrimitive() || Word.class.isAssignableFrom(resultType) : "non-leaf foreign calls must return objects in thread local storage: " + descriptor; - return register(HotSpotForeignCallLinkageImpl.create(metaAccess, codeCache, wordTypes, this, descriptor, address, effect, outgoingCcType, null, transition, reexecutability, killedLocations)); + return register(HotSpotForeignCallLinkageImpl.create(metaAccess, + codeCache, + wordTypes, + this, + descriptor, + address, + effect, + outgoingCcType, + null, // incomingCcType + transition, + reexecutability, + killedLocations)); } /** - * Creates a {@linkplain ForeignCallStub stub} for a foreign call. + * Creates a {@linkplain ForeignCallStub stub} for the foreign call described by + * {@code descriptor} if {@code address != 0}. * * @param descriptor the signature of the call to the stub * @param address the address of the foreign code to call @@ -150,14 +180,22 @@ public abstract class HotSpotForeignCallsProviderImpl implements HotSpotForeignC * cannot be re-executed. * @param killedLocations the memory locations killed by the foreign call */ - public void linkForeignCall(OptionValues options, HotSpotProviders providers, ForeignCallDescriptor descriptor, long address, boolean prependThread, Transition transition, - Reexecutability reexecutability, LocationIdentity... killedLocations) { - ForeignCallStub stub = new ForeignCallStub(options, jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutability, killedLocations); - HotSpotForeignCallLinkage linkage = stub.getLinkage(); - HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); - linkage.setCompiledStub(stub); - register(linkage); - register(targetLinkage); + public void linkForeignCall(OptionValues options, + HotSpotProviders providers, + ForeignCallDescriptor descriptor, + long address, + boolean prependThread, + Transition transition, + Reexecutability reexecutability, + LocationIdentity... killedLocations) { + if (address != 0) { + ForeignCallStub stub = new ForeignCallStub(options, jvmciRuntime, providers, address, descriptor, prependThread, transition, reexecutability, killedLocations); + HotSpotForeignCallLinkage linkage = stub.getLinkage(); + HotSpotForeignCallLinkage targetLinkage = stub.getTargetLinkage(); + linkage.setCompiledStub(stub); + register(linkage); + register(targetLinkage); + } } public static final boolean PREPEND_THREAD = true; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java index 5b1c9406a4..f9a383d1d8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java @@ -91,8 +91,6 @@ import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode; -import org.graalvm.compiler.nodes.spi.LoweringProvider; -import org.graalvm.compiler.nodes.spi.StampProvider; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.tiers.CompilerConfiguration; @@ -126,15 +124,13 @@ public class HotSpotGraphBuilderPlugins { * @param constantReflection * @param snippetReflection * @param foreignCalls - * @param stampProvider */ public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess, - ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, LoweringProvider lowerer, - StampProvider stampProvider, ReplacementsImpl replacements) { + ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ReplacementsImpl replacements) { InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration); Plugins plugins = new Plugins(invocationPlugins); - NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, lowerer, wordTypes); + NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes); HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes); HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java index 990c0d14bd..ef5bc5e70e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java @@ -81,6 +81,8 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil. import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_TOP_LOCATION; import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITORENTER; import static org.graalvm.compiler.hotspot.replacements.MonitorSnippets.MONITOREXIT; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE; +import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.DYNAMIC_NEW_INSTANCE_OR_NULL; import static org.graalvm.compiler.hotspot.replacements.ThreadSubstitutions.THREAD_IS_INTERRUPTED; import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPOSTCALL; import static org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.G1WBPRECALL; @@ -225,11 +227,20 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc; } - private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine) { + private void registerArrayCopy(JavaKind kind, + long routine, + long alignedRoutine, + long disjointRoutine, + long alignedDisjointRoutine) { registerArrayCopy(kind, routine, alignedRoutine, disjointRoutine, alignedDisjointRoutine, false); } - private void registerArrayCopy(JavaKind kind, long routine, long alignedRoutine, long disjointRoutine, long alignedDisjointRoutine, boolean uninit) { + private void registerArrayCopy(JavaKind kind, + long routine, + long alignedRoutine, + long disjointRoutine, + long alignedDisjointRoutine, + boolean uninit) { /* * Sometimes the same function is used for multiple cases so share them when that's the case * but only within the same Kind. For instance short and char are the same copy routines but @@ -290,11 +301,13 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall linkForeignCall(options, providers, NEW_INSTANCE, c.newInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); linkForeignCall(options, providers, NEW_ARRAY, c.newArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); linkForeignCall(options, providers, NEW_MULTI_ARRAY, c.newMultiArrayAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(options, providers, DYNAMIC_NEW_INSTANCE, c.dynamicNewInstanceAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE); if (c.areNullAllocationStubsAvailable()) { linkForeignCall(options, providers, NEW_INSTANCE_OR_NULL, c.newInstanceOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); linkForeignCall(options, providers, NEW_ARRAY_OR_NULL, c.newArrayOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); linkForeignCall(options, providers, NEW_MULTI_ARRAY_OR_NULL, c.newMultiArrayOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE, TLAB_TOP_LOCATION, TLAB_END_LOCATION); + linkForeignCall(options, providers, DYNAMIC_NEW_INSTANCE_OR_NULL, c.dynamicNewInstanceOrNullAddress, PREPEND_THREAD, SAFEPOINT, REEXECUTABLE); } link(new ExceptionHandlerStub(options, providers, foreignCalls.get(EXCEPTION_HANDLER))); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java index 4bd6a0da52..648b5a9345 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/HotSpotNarrowOopStamp.java @@ -65,12 +65,8 @@ public final class HotSpotNarrowOopStamp extends NarrowOopStamp { } @Override - public JavaConstant asConstant() { - if (alwaysNull()) { - return HotSpotCompressedNullConstant.COMPRESSED_NULL; - } else { - return null; - } + public JavaConstant nullConstant() { + return HotSpotCompressedNullConstant.COMPRESSED_NULL; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java index b539adae67..c7fa265c89 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/type/KlassPointerStamp.java @@ -122,11 +122,11 @@ public final class KlassPointerStamp extends MetaspacePointerStamp { } @Override - public Constant asConstant() { - if (alwaysNull() && isCompressed()) { + public JavaConstant nullConstant() { + if (isCompressed()) { return HotSpotCompressedNullConstant.COMPRESSED_NULL; } else { - return super.asConstant(); + return super.nullConstant(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java index 2beb6e63ed..363cf7a159 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java @@ -269,10 +269,10 @@ public class NewObjectSnippets implements Snippets { DeoptimizeNode.deopt(None, RuntimeConstraint); } - return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(fillContents, threadRegister, options, counters, nonNullType)); + return PiNode.piCastToSnippetReplaceeStamp(allocateInstanceDynamicHelper(type, fillContents, threadRegister, options, counters, nonNullType)); } - private static Object allocateInstanceDynamicHelper(boolean fillContents, Register threadRegister, OptionValues options, Counters counters, Class nonNullType) { + private static Object allocateInstanceDynamicHelper(Class type, boolean fillContents, Register threadRegister, OptionValues options, Counters counters, Class nonNullType) { KlassPointer hub = ClassGetHubNode.readClass(nonNullType); if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) { KlassPointer nonNullHub = ClassGetHubNode.piCastNonNull(hub, SnippetAnchorNode.anchor()); @@ -297,8 +297,7 @@ public class NewObjectSnippets implements Snippets { DeoptimizeNode.deopt(None, RuntimeConstraint); } } - DeoptimizeNode.deopt(None, RuntimeConstraint); - return null; + return dynamicNewInstanceStub(type); } /** @@ -386,6 +385,24 @@ public class NewObjectSnippets implements Snippets { @NodeIntrinsic(value = ForeignCallNode.class, injectedStampIsNonNull = false) private static native Object newArrayOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, KlassPointer hub, int length); + /** + * New dynamic array stub that throws an {@link OutOfMemoryError} on allocation failure. + */ + public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE = new ForeignCallDescriptor("dynamic_new_instance", Object.class, Class.class); + + /** + * New dynamic array stub that returns null on allocation failure. + */ + public static final ForeignCallDescriptor DYNAMIC_NEW_INSTANCE_OR_NULL = new ForeignCallDescriptor("dynamic_new_instance_or_null", Object.class, Class.class); + + public static Object dynamicNewInstanceStub(Class elementType) { + if (useNullAllocationStubs(INJECTED_VMCONFIG)) { + return nonNullOrDeopt(dynamicNewInstanceOrNull(DYNAMIC_NEW_INSTANCE_OR_NULL, elementType)); + } else { + return dynamicNewInstance(DYNAMIC_NEW_INSTANCE, elementType); + } + } + /** * Deoptimizes if {@code obj == null} otherwise returns {@code obj}. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java index 09259eae0b..dcb2ed8e07 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java @@ -36,20 +36,6 @@ import static org.graalvm.util.CollectionsUtil.allMatch; import java.util.ListIterator; import java.util.concurrent.atomic.AtomicInteger; -import jdk.vm.ci.code.CodeCacheProvider; -import jdk.vm.ci.code.InstalledCode; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterConfig; -import jdk.vm.ci.code.site.Call; -import jdk.vm.ci.code.site.ConstantReference; -import jdk.vm.ci.code.site.DataPatch; -import jdk.vm.ci.code.site.Infopoint; -import jdk.vm.ci.hotspot.HotSpotCompiledCode; -import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; -import jdk.vm.ci.meta.DefaultProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.TriState; - import jdk.internal.vm.compiler.collections.EconomicSet; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompilationIdentifier; @@ -73,6 +59,20 @@ import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; +import jdk.vm.ci.code.CodeCacheProvider; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.code.RegisterConfig; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.ConstantReference; +import jdk.vm.ci.code.site.DataPatch; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.hotspot.HotSpotCompiledCode; +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.meta.DefaultProfilingInfo; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.TriState; + //JaCoCo Exclude /** @@ -202,7 +202,7 @@ public abstract class Stub { assert destroyedCallerRegisters != null; // Add a GeneratePIC check here later, we don't want to install // code if we don't have a corresponding VM global symbol. - HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult); + HotSpotCompiledCode compiledCode = HotSpotCompiledCodeBuilder.createCompiledCode(codeCache, null, null, compResult, options); code = codeCache.installCode(null, compiledCode, null, null, false); } catch (Throwable e) { throw debug.handle(e); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java index a64c75a39f..a474357417 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java @@ -424,6 +424,7 @@ import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.util.ValueMergeUtil; +import org.graalvm.compiler.serviceprovider.GraalServices; import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.code.BailoutException; @@ -1036,6 +1037,15 @@ public class BytecodeParser implements GraphBuilderContext { deopt.updateNodeSourcePosition(() -> createBytecodePosition()); } + /** + * @param type the type being instantiated + */ + protected void handleIllegalNewInstance(JavaType type) { + assert !graphBuilderConfig.unresolvedIsError(); + DeoptimizeNode deopt = append(new DeoptimizeNode(InvalidateRecompile, Unresolved)); + deopt.updateNodeSourcePosition(() -> createBytecodePosition()); + } + /** * @param type the type of the array being instantiated * @param length the length of the array @@ -1418,6 +1428,14 @@ public class BytecodeParser implements GraphBuilderContext { return false; } + /** + * Check if a type is resolved. Can be overwritten by sub-classes to implement different type + * resolution rules. + */ + protected boolean typeIsResolved(JavaType type) { + return type instanceof ResolvedJavaType; + } + protected void genInvokeStatic(int cpi, int opcode) { JavaMethod target = lookupMethod(cpi, opcode); assert !uninitializedIsError || @@ -1477,7 +1495,28 @@ public class BytecodeParser implements GraphBuilderContext { protected void genInvokeVirtual(int cpi, int opcode) { JavaMethod target = lookupMethod(cpi, opcode); - genInvokeVirtual(target); + if (callTargetIsResolved(target)) { + genInvokeVirtual((ResolvedJavaMethod) target); + } else { + handleUnresolvedInvoke(target, InvokeKind.Virtual); + } + } + + protected void genInvokeVirtual(ResolvedJavaMethod resolvedTarget) { + int cpi = stream.readCPI(); + + /* + * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or + * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see + * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic + */ + + if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) { + return; + } + + ValueNode[] args = frameState.popArguments(resolvedTarget.getSignature().getParameterCount(true)); + appendInvoke(InvokeKind.Virtual, resolvedTarget, args); } private boolean genDynamicInvokeHelper(ResolvedJavaMethod target, int cpi, int opcode) { @@ -1530,36 +1569,6 @@ public class BytecodeParser implements GraphBuilderContext { return true; } - void genInvokeVirtual(JavaMethod target) { - if (!genInvokeVirtualHelper(target)) { - handleUnresolvedInvoke(target, InvokeKind.Virtual); - } - } - - private boolean genInvokeVirtualHelper(JavaMethod target) { - if (!callTargetIsResolved(target)) { - return false; - } - - ResolvedJavaMethod resolvedTarget = (ResolvedJavaMethod) target; - int cpi = stream.readCPI(); - - /* - * Special handling for runtimes that rewrite an invocation of MethodHandle.invoke(...) or - * MethodHandle.invokeExact(...) to a static adapter. HotSpot does this - see - * https://wiki.openjdk.java.net/display/HotSpot/Method+handles+and+invokedynamic - */ - - if (genDynamicInvokeHelper(resolvedTarget, cpi, INVOKEVIRTUAL)) { - return true; - } - - ValueNode[] args = frameState.popArguments(target.getSignature().getParameterCount(true)); - appendInvoke(InvokeKind.Virtual, (ResolvedJavaMethod) target, args); - - return true; - } - protected void genInvokeSpecial(int cpi, int opcode) { JavaMethod target = lookupMethod(cpi, opcode); genInvokeSpecial(target); @@ -3018,7 +3027,7 @@ public class BytecodeParser implements GraphBuilderContext { if (graphBuilderConfig.eagerResolving()) { catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF); } - if (catchType instanceof ResolvedJavaType) { + if (typeIsResolved(catchType)) { TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType); if (graphBuilderConfig.getSkippedExceptionTypes() != null) { @@ -3667,7 +3676,7 @@ public class BytecodeParser implements GraphBuilderContext { if (con instanceof JavaType) { // this is a load of class constant which might be unresolved JavaType type = (JavaType) con; - if (type instanceof ResolvedJavaType) { + if (typeIsResolved(type)) { frameState.push(JavaKind.Object, appendConstant(getConstantReflection().asJavaClass((ResolvedJavaType) type))); } else { handleUnresolvedLoadConstant(type); @@ -3923,16 +3932,56 @@ public class BytecodeParser implements GraphBuilderContext { return result; } + private String unresolvedMethodAssertionMessage(JavaMethod result) { + String message = result.format("%H.%n(%P)%R"); + if (GraalServices.Java8OrEarlier) { + JavaType declaringClass = result.getDeclaringClass(); + String className = declaringClass.getName(); + switch (className) { + case "Ljava/nio/ByteBuffer;": + case "Ljava/nio/ShortBuffer;": + case "Ljava/nio/CharBuffer;": + case "Ljava/nio/IntBuffer;": + case "Ljava/nio/LongBuffer;": + case "Ljava/nio/FloatBuffer;": + case "Ljava/nio/DoubleBuffer;": + case "Ljava/nio/MappedByteBuffer;": { + switch (result.getName()) { + case "position": + case "limit": + case "mark": + case "reset": + case "clear": + case "flip": + case "rewind": { + String returnType = result.getSignature().getReturnType(null).toJavaName(); + if (returnType.equals(declaringClass.toJavaName())) { + message += String.format(" [Probably cause: %s was compiled with javac from JDK 9+ using " + + "`-target 8` and `-source 8` options. See https://bugs.openjdk.java.net/browse/JDK-4774077 for details.]", method.getDeclaringClass().toClassName()); + } + } + } + break; + } + } + } + return message; + } + private JavaMethod lookupMethod(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode); - assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : result; + assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : unresolvedMethodAssertionMessage(result); return result; } protected JavaField lookupField(int cpi, int opcode) { maybeEagerlyResolve(cpi, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode); + return lookupField(result); + } + + protected JavaField lookupField(JavaField result) { assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result; if (parsingIntrinsic() || eagerInitializing) { if (result instanceof ResolvedJavaField) { @@ -3984,16 +4033,22 @@ public class BytecodeParser implements GraphBuilderContext { } } - private void genCheckCast() { - int cpi = getStream().readCPI(); + private void genCheckCast(int cpi) { JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.pop(JavaKind.Object); + genCheckCast(type, object); + } - if (!(type instanceof ResolvedJavaType)) { + protected void genCheckCast(JavaType type, ValueNode object) { + if (typeIsResolved(type)) { + genCheckCast((ResolvedJavaType) type, object); + } else { handleUnresolvedCheckCast(type, object); - return; } - ResolvedJavaType resolvedType = (ResolvedJavaType) type; + } + + protected void genCheckCast(ResolvedJavaType resolvedType, ValueNode objectIn) { + ValueNode object = objectIn; TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), resolvedType); JavaTypeProfile profile = getProfileForTypeCheck(checkedType); @@ -4041,20 +4096,27 @@ public class BytecodeParser implements GraphBuilderContext { frameState.push(JavaKind.Object, castNode); } - private void genInstanceOf() { - int cpi = getStream().readCPI(); + private void genInstanceOf(int cpi) { JavaType type = lookupType(cpi, INSTANCEOF); ValueNode object = frameState.pop(JavaKind.Object); + genInstanceOf(type, object); + } - if (!(type instanceof ResolvedJavaType)) { + protected void genInstanceOf(JavaType type, ValueNode object) { + if (typeIsResolved(type)) { + genInstanceOf((ResolvedJavaType) type, object); + } else { handleUnresolvedInstanceOf(type, object); - return; } - TypeReference resolvedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type); - JavaTypeProfile profile = getProfileForTypeCheck(resolvedType); + } + + protected void genInstanceOf(ResolvedJavaType resolvedType, ValueNode objectIn) { + ValueNode object = objectIn; + TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), resolvedType); + JavaTypeProfile profile = getProfileForTypeCheck(checkedType); for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) { - if (plugin.handleInstanceOf(this, object, resolvedType.getType(), profile)) { + if (plugin.handleInstanceOf(this, object, checkedType.getType(), profile)) { return; } } @@ -4069,12 +4131,12 @@ public class BytecodeParser implements GraphBuilderContext { if (!typeCheck.isTautology()) { append(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile)); } - instanceOfNode = LogicConstantNode.forBoolean(resolvedType.getType().isAssignableFrom(singleType)); + instanceOfNode = LogicConstantNode.forBoolean(checkedType.getType().isAssignableFrom(singleType)); } } } if (instanceOfNode == null) { - instanceOfNode = createInstanceOf(resolvedType, object, null); + instanceOfNode = createInstanceOf(checkedType, object, null); } LogicNode logicNode = genUnique(instanceOfNode); @@ -4106,20 +4168,23 @@ public class BytecodeParser implements GraphBuilderContext { genNewInstance(type); } - void genNewInstance(JavaType type) { - if (!(type instanceof ResolvedJavaType)) { + protected void genNewInstance(JavaType type) { + if (typeIsResolved(type)) { + genNewInstance((ResolvedJavaType) type); + } else { handleUnresolvedNewInstance(type); - return; } - ResolvedJavaType resolvedType = (ResolvedJavaType) type; + } + + protected void genNewInstance(ResolvedJavaType resolvedType) { if (resolvedType.isAbstract() || resolvedType.isInterface()) { - handleUnresolvedNewInstance(type); + handleIllegalNewInstance(resolvedType); return; } ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin(); if (!resolvedType.isInitialized() && classInitializationPlugin == null) { - handleUnresolvedNewInstance(type); + handleIllegalNewInstance(resolvedType); return; } @@ -4192,14 +4257,19 @@ public class BytecodeParser implements GraphBuilderContext { private void genNewObjectArray(int cpi) { JavaType type = lookupType(cpi, ANEWARRAY); + genNewObjectArray(type); + } - if (!(type instanceof ResolvedJavaType)) { + private void genNewObjectArray(JavaType type) { + if (typeIsResolved(type)) { + genNewObjectArray((ResolvedJavaType) type); + } else { ValueNode length = frameState.pop(JavaKind.Int); handleUnresolvedNewObjectArray(type, length); - return; } + } - ResolvedJavaType resolvedType = (ResolvedJavaType) type; + private void genNewObjectArray(ResolvedJavaType resolvedType) { ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType.getArrayClass())) { @@ -4221,15 +4291,21 @@ public class BytecodeParser implements GraphBuilderContext { JavaType type = lookupType(cpi, MULTIANEWARRAY); int rank = getStream().readUByte(bci() + 3); ValueNode[] dims = new ValueNode[rank]; + genNewMultiArray(type, rank, dims); + } - if (!(type instanceof ResolvedJavaType)) { + private void genNewMultiArray(JavaType type, int rank, ValueNode[] dims) { + if (typeIsResolved(type)) { + genNewMultiArray((ResolvedJavaType) type, rank, dims); + } else { for (int i = rank - 1; i >= 0; i--) { dims[i] = frameState.pop(JavaKind.Int); } handleUnresolvedNewMultiArray(type, dims); - return; } - ResolvedJavaType resolvedType = (ResolvedJavaType) type; + } + + private void genNewMultiArray(ResolvedJavaType resolvedType, int rank, ValueNode[] dims) { ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) { @@ -4260,12 +4336,12 @@ public class BytecodeParser implements GraphBuilderContext { } private void genGetField(JavaField field, ValueNode receiverInput) { - ValueNode receiver = maybeEmitExplicitNullCheck(receiverInput); if (field instanceof ResolvedJavaField) { + ValueNode receiver = maybeEmitExplicitNullCheck(receiverInput); ResolvedJavaField resolvedField = (ResolvedJavaField) field; genGetField(resolvedField, receiver); } else { - handleUnresolvedLoadField(field, receiver); + handleUnresolvedLoadField(field, receiverInput); } } @@ -4370,9 +4446,10 @@ public class BytecodeParser implements GraphBuilderContext { } private void genPutField(JavaField field, ValueNode value) { - ValueNode receiver = maybeEmitExplicitNullCheck(frameState.pop(JavaKind.Object)); + ValueNode receiverInput = frameState.pop(JavaKind.Object); if (field instanceof ResolvedJavaField) { + ValueNode receiver = maybeEmitExplicitNullCheck(receiverInput); ResolvedJavaField resolvedField = (ResolvedJavaField) field; if (!parsingIntrinsic() && GeneratePIC.getValue(getOptions())) { @@ -4390,7 +4467,7 @@ public class BytecodeParser implements GraphBuilderContext { } genStoreField(receiver, resolvedField, value); } else { - handleUnresolvedStoreField(field, value, receiver); + handleUnresolvedStoreField(field, value, receiverInput); } } @@ -4484,6 +4561,7 @@ public class BytecodeParser implements GraphBuilderContext { } protected void genPutStatic(JavaField field) { + int stackSizeBefore = frameState.stackSize(); ValueNode value = frameState.pop(field.getJavaKind()); ResolvedJavaField resolvedField = resolveStaticFieldAccess(field, value); if (resolvedField == null) { @@ -4496,7 +4574,10 @@ public class BytecodeParser implements GraphBuilderContext { ClassInitializationPlugin classInitializationPlugin = this.graphBuilderConfig.getPlugins().getClassInitializationPlugin(); if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedField.getDeclaringClass())) { - FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); + JavaKind[] pushedSlotKinds = {field.getJavaKind()}; + ValueNode[] pushedValues = {value}; + FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, pushedSlotKinds, pushedValues); + assert stackSizeBefore == stateBefore.stackSize(); classInitializationPlugin.apply(this, resolvedField.getDeclaringClass(), stateBefore); } @@ -4869,8 +4950,8 @@ public class BytecodeParser implements GraphBuilderContext { case ANEWARRAY : genNewObjectArray(stream.readCPI()); break; case ARRAYLENGTH : genArrayLength(); break; case ATHROW : genThrow(); break; - case CHECKCAST : genCheckCast(); break; - case INSTANCEOF : genInstanceOf(); break; + case CHECKCAST : genCheckCast(stream.readCPI()); break; + case INSTANCEOF : genInstanceOf(stream.readCPI()); break; case MONITORENTER : genMonitorEnter(frameState.pop(JavaKind.Object), stream.nextBCI()); break; case MONITOREXIT : genMonitorExit(frameState.pop(JavaKind.Object), null, stream.nextBCI()); break; case MULTIANEWARRAY : genNewMultiArray(stream.readCPI()); break; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java index 9098e3d098..40a822dbd3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.java; -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyRelativeFrequencies; import java.util.List; @@ -75,17 +75,17 @@ public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.N protected EconomicMap processLoop(LoopBeginNode loop, Double initialState) { EconomicMap exitStates = ReentrantNodeIterator.processLoop(this, loop, 1D).exitStates; - double exitProbability = 0.0; + double exitRelativeFrequency = 0.0; for (double d : exitStates.getValues()) { - exitProbability += d; + exitRelativeFrequency += d; } - exitProbability = Math.min(1.0, exitProbability); - exitProbability = Math.max(ControlFlowGraph.MIN_PROBABILITY, exitProbability); - double loopFrequency = 1.0 / exitProbability; + exitRelativeFrequency = Math.min(1.0, exitRelativeFrequency); + exitRelativeFrequency = Math.max(ControlFlowGraph.MIN_RELATIVE_FREQUENCY, exitRelativeFrequency); + double loopFrequency = 1.0 / exitRelativeFrequency; loop.setLoopFrequency(loopFrequency); double adjustmentFactor = initialState * loopFrequency; - exitStates.replaceAll((exitNode, probability) -> multiplyProbabilities(probability, adjustmentFactor)); + exitStates.replaceAll((exitNode, frequency) -> multiplyRelativeFrequencies(frequency, adjustmentFactor)); return exitStates; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java index d6f5756af5..0d8eb8671e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java @@ -370,7 +370,15 @@ public final class FrameStateBuilder implements SideEffectsState { if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { throw shouldNotReachHere(); } - return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci); + if (parser.intrinsicContext != null && (parent == null || parent.intrinsicContext != parser.intrinsicContext)) { + // When parsing an intrinsic put in a substitution marker showing the original method as + // the caller. This keeps the relationship between the method and the method + // substitution clear in resulting NodeSourcePosition. + NodeSourcePosition original = new NodeSourcePosition(outerSourcePosition, parser.intrinsicContext.getOriginalMethod(), -1); + return NodeSourcePosition.substitution(original, code.getMethod(), bci); + } else { + return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci); + } } public FrameStateBuilder copy() { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java index 11dd738bc7..ba532725eb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotpath/HP_allocate02.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.jtt.JTTTest; */ public class HP_allocate02 extends JTTTest { - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static int test(int count) { int sum = 0; for (int i = 0; i < count; i++) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java index 5fee7f2a0d..9b99f5c120 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/hotspot/Test6823354.java @@ -199,7 +199,7 @@ public class Test6823354 { loadandrunclass(classname); } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation","unused"}) static void loadandrunclass(String classname) throws Exception { Class cl = Class.forName(classname); URLClassLoader apploader = (URLClassLoader) cl.getClassLoader(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java new file mode 100644 index 0000000000..9017f072da --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/TrichotomyTest.java @@ -0,0 +1,2561 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.jtt.optimize; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.List; + +import org.graalvm.compiler.jtt.JTTTest; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; +import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; +import org.graalvm.compiler.phases.common.CanonicalizerPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runner.notification.RunNotifier; +import org.junit.runners.BlockJUnit4ClassRunner; +import org.junit.runners.model.FrameworkMethod; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.Statement; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +@RunWith(TrichotomyTest.Runner.class) +public class TrichotomyTest extends JTTTest { + + @Test + @Ignore + public void dummy() { + // needed for mx unittest + } + + public static int compare1(int a, int b) { + return (a < b) ? -1 : (a == b) ? 0 : 1; + } + + public static int compare2(int a, int b) { + return (a < b) ? -1 : (a <= b) ? 0 : 1; + } + + public static int compare3(int a, int b) { + return (a < b) ? -1 : (a > b) ? 1 : 0; + } + + public static int compare4(int a, int b) { + return (a < b) ? -1 : (a != b) ? 1 : 0; + } + + public static int compare5(int a, int b) { + return (a > b) ? 1 : (a < b) ? -1 : 0; + } + + public static int compare6(int a, int b) { + return (a > b) ? 1 : (a == b) ? 0 : -1; + } + + public static int compare7(int a, int b) { + return (a > b) ? 1 : (a >= b) ? 0 : -1; + } + + public static int compare8(int a, int b) { + return (a > b) ? 1 : (a != b) ? -1 : 0; + } + + public static int compare9(int a, int b) { + return (a == b) ? 0 : (a < b) ? -1 : 1; + } + + public static int compare10(int a, int b) { + return (a == b) ? 0 : (a <= b) ? -1 : 1; + } + + public static int compare11(int a, int b) { + return (a == b) ? 0 : (a > b) ? 1 : -1; + } + + public static int compare12(int a, int b) { + return (a == b) ? 0 : (a >= b) ? 1 : -1; + } + + public static int compare13(int a, int b) { + return (a <= b) ? ((a == b) ? 0 : -1) : 1; + } + + public static int compare14(int a, int b) { + return (a <= b) ? ((a < b) ? -1 : 0) : 1; + } + + public static int compare15(int a, int b) { + return (a <= b) ? ((a >= b) ? 0 : -1) : 1; + } + + public static int compare16(int a, int b) { + return (a <= b) ? ((a != b) ? -1 : 0) : 1; + } + + public static int compare17(int a, int b) { + return (a >= b) ? ((a <= b) ? 0 : 1) : -1; + } + + public static int compare18(int a, int b) { + return (a >= b) ? ((a == b) ? 0 : 1) : -1; + } + + public static int compare19(int a, int b) { + return (a >= b) ? ((a > b) ? 1 : 0) : -1; + } + + public static int compare20(int a, int b) { + return (a >= b) ? ((a != b) ? 1 : 0) : -1; + } + + public static int compare21(int a, int b) { + return (a != b) ? ((a < b) ? -1 : 1) : 0; + } + + public static int compare22(int a, int b) { + return (a != b) ? ((a <= b) ? -1 : 1) : 0; + } + + public static int compare23(int a, int b) { + return (a != b) ? ((a > b) ? 1 : -1) : 0; + } + + public static int compare24(int a, int b) { + return (a != b) ? ((a >= b) ? 1 : -1) : 0; + } + + public static int compare25(int a, int b) { + return (a < b) ? -1 : (b == a) ? 0 : 1; + } + + public static int compare26(int a, int b) { + return (a < b) ? -1 : (b >= a) ? 0 : 1; + } + + public static int compare27(int a, int b) { + return (a < b) ? -1 : (b < a) ? 1 : 0; + } + + public static int compare28(int a, int b) { + return (a < b) ? -1 : (b != a) ? 1 : 0; + } + + public static int compare29(int a, int b) { + return (a > b) ? 1 : (b > a) ? -1 : 0; + } + + public static int compare30(int a, int b) { + return (a > b) ? 1 : (b == a) ? 0 : -1; + } + + public static int compare31(int a, int b) { + return (a > b) ? 1 : (b <= a) ? 0 : -1; + } + + public static int compare32(int a, int b) { + return (a > b) ? 1 : (b != a) ? -1 : 0; + } + + public static int compare33(int a, int b) { + return (a == b) ? 0 : (b > a) ? -1 : 1; + } + + public static int compare34(int a, int b) { + return (a == b) ? 0 : (b >= a) ? -1 : 1; + } + + public static int compare35(int a, int b) { + return (a == b) ? 0 : (b < a) ? 1 : -1; + } + + public static int compare36(int a, int b) { + return (a == b) ? 0 : (b <= a) ? 1 : -1; + } + + public static int compare37(int a, int b) { + return (a <= b) ? ((b == a) ? 0 : -1) : 1; + } + + public static int compare38(int a, int b) { + return (a <= b) ? ((b > a) ? -1 : 0) : 1; + } + + public static int compare39(int a, int b) { + return (a <= b) ? ((b <= a) ? 0 : -1) : 1; + } + + public static int compare40(int a, int b) { + return (a <= b) ? ((b != a) ? -1 : 0) : 1; + } + + public static int compare41(int a, int b) { + return (a >= b) ? ((b >= a) ? 0 : 1) : -1; + } + + public static int compare42(int a, int b) { + return (a >= b) ? ((b == a) ? 0 : 1) : -1; + } + + public static int compare43(int a, int b) { + return (a >= b) ? ((b < a) ? 1 : 0) : -1; + } + + public static int compare44(int a, int b) { + return (a >= b) ? ((b != a) ? 1 : 0) : -1; + } + + public static int compare45(int a, int b) { + return (a != b) ? ((b > a) ? -1 : 1) : 0; + } + + public static int compare46(int a, int b) { + return (a != b) ? ((b >= a) ? -1 : 1) : 0; + } + + public static int compare47(int a, int b) { + return (a != b) ? ((b < a) ? 1 : -1) : 0; + } + + public static int compare48(int a, int b) { + return (a != b) ? ((b <= a) ? 1 : -1) : 0; + } + + public static int compareAlwaysFalse1(int a, int b) { + return (a >= b) ? 1 : (a > b) ? 2 : -1; + } + + public static int compareAlwaysFalse2(int a, int b) { + return (a <= b) ? 1 : (a < b) ? 2 : -1; + } + + public static int compareAlwaysFalse3(int a, int b) { + return (a == b) ? 1 : (a == b) ? 2 : -1; + } + + public static int compareAlwaysFalse4(int a, int b) { + return (a != b) ? 1 : (a < b) ? 2 : -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller1(int a, int b) { + return compare1(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller2(int a, int b) { + return compare1(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller3(int a, int b) { + return compare1(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller4(int a, int b) { + return compare2(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller5(int a, int b) { + return compare2(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller6(int a, int b) { + return compare2(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller7(int a, int b) { + return compare3(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller8(int a, int b) { + return compare3(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller9(int a, int b) { + return compare3(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller10(int a, int b) { + return compare4(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller11(int a, int b) { + return compare4(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller12(int a, int b) { + return compare4(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller13(int a, int b) { + return compare5(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller14(int a, int b) { + return compare5(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller15(int a, int b) { + return compare5(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller16(int a, int b) { + return compare6(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller17(int a, int b) { + return compare6(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller18(int a, int b) { + return compare6(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller19(int a, int b) { + return compare7(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller20(int a, int b) { + return compare7(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller21(int a, int b) { + return compare7(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller22(int a, int b) { + return compare8(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller23(int a, int b) { + return compare8(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller24(int a, int b) { + return compare8(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller25(int a, int b) { + return compare9(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller26(int a, int b) { + return compare9(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller27(int a, int b) { + return compare9(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller28(int a, int b) { + return compare10(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller29(int a, int b) { + return compare10(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller30(int a, int b) { + return compare10(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller31(int a, int b) { + return compare11(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller32(int a, int b) { + return compare11(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller33(int a, int b) { + return compare11(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller34(int a, int b) { + return compare12(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller35(int a, int b) { + return compare12(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller36(int a, int b) { + return compare12(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller37(int a, int b) { + return compare13(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller38(int a, int b) { + return compare13(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller39(int a, int b) { + return compare13(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller40(int a, int b) { + return compare14(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller41(int a, int b) { + return compare14(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller42(int a, int b) { + return compare14(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller43(int a, int b) { + return compare15(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller44(int a, int b) { + return compare15(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller45(int a, int b) { + return compare15(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller46(int a, int b) { + return compare16(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller47(int a, int b) { + return compare16(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller48(int a, int b) { + return compare16(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller49(int a, int b) { + return compare17(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller50(int a, int b) { + return compare17(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller51(int a, int b) { + return compare17(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller52(int a, int b) { + return compare18(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller53(int a, int b) { + return compare18(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller54(int a, int b) { + return compare18(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller55(int a, int b) { + return compare19(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller56(int a, int b) { + return compare19(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller57(int a, int b) { + return compare19(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller58(int a, int b) { + return compare20(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller59(int a, int b) { + return compare20(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller60(int a, int b) { + return compare20(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller61(int a, int b) { + return compare21(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller62(int a, int b) { + return compare21(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller63(int a, int b) { + return compare21(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller64(int a, int b) { + return compare22(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller65(int a, int b) { + return compare22(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller66(int a, int b) { + return compare22(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller67(int a, int b) { + return compare23(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller68(int a, int b) { + return compare23(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller69(int a, int b) { + return compare23(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller70(int a, int b) { + return compare24(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller71(int a, int b) { + return compare24(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller72(int a, int b) { + return compare24(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller73(int a, int b) { + return compare25(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller74(int a, int b) { + return compare25(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller75(int a, int b) { + return compare25(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller76(int a, int b) { + return compare26(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller77(int a, int b) { + return compare26(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller78(int a, int b) { + return compare26(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller79(int a, int b) { + return compare27(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller80(int a, int b) { + return compare27(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller81(int a, int b) { + return compare27(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller82(int a, int b) { + return compare28(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller83(int a, int b) { + return compare28(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller84(int a, int b) { + return compare28(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller85(int a, int b) { + return compare29(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller86(int a, int b) { + return compare29(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller87(int a, int b) { + return compare29(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller88(int a, int b) { + return compare30(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller89(int a, int b) { + return compare30(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller90(int a, int b) { + return compare30(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller91(int a, int b) { + return compare31(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller92(int a, int b) { + return compare31(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller93(int a, int b) { + return compare31(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller94(int a, int b) { + return compare32(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller95(int a, int b) { + return compare32(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller96(int a, int b) { + return compare32(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller97(int a, int b) { + return compare33(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller98(int a, int b) { + return compare33(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller99(int a, int b) { + return compare33(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller100(int a, int b) { + return compare34(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller101(int a, int b) { + return compare34(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller102(int a, int b) { + return compare34(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller103(int a, int b) { + return compare35(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller104(int a, int b) { + return compare35(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller105(int a, int b) { + return compare35(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller106(int a, int b) { + return compare36(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller107(int a, int b) { + return compare36(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller108(int a, int b) { + return compare36(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller109(int a, int b) { + return compare37(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller110(int a, int b) { + return compare37(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller111(int a, int b) { + return compare37(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller112(int a, int b) { + return compare38(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller113(int a, int b) { + return compare38(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller114(int a, int b) { + return compare38(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller115(int a, int b) { + return compare39(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller116(int a, int b) { + return compare39(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller117(int a, int b) { + return compare39(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller118(int a, int b) { + return compare40(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller119(int a, int b) { + return compare40(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller120(int a, int b) { + return compare40(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller121(int a, int b) { + return compare41(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller122(int a, int b) { + return compare41(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller123(int a, int b) { + return compare41(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller124(int a, int b) { + return compare42(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller125(int a, int b) { + return compare42(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller126(int a, int b) { + return compare42(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller127(int a, int b) { + return compare43(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller128(int a, int b) { + return compare43(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller129(int a, int b) { + return compare43(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller130(int a, int b) { + return compare44(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller131(int a, int b) { + return compare44(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller132(int a, int b) { + return compare44(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller133(int a, int b) { + return compare45(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller134(int a, int b) { + return compare45(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller135(int a, int b) { + return compare45(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller136(int a, int b) { + return compare46(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller137(int a, int b) { + return compare46(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller138(int a, int b) { + return compare46(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller139(int a, int b) { + return compare47(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller140(int a, int b) { + return compare47(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller141(int a, int b) { + return compare47(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller142(int a, int b) { + return compare48(a, b) == -1; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller143(int a, int b) { + return compare48(a, b) < 0; + } + + @TestCase(op = Operation.SMALLER) + public static boolean testSmaller144(int a, int b) { + return compare48(a, b) <= -1; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual1(int a, int b) { + return compare1(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual2(int a, int b) { + return compare2(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual3(int a, int b) { + return compare3(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual4(int a, int b) { + return compare4(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual5(int a, int b) { + return compare5(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual6(int a, int b) { + return compare6(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual7(int a, int b) { + return compare7(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual8(int a, int b) { + return compare8(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual9(int a, int b) { + return compare9(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual10(int a, int b) { + return compare10(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual11(int a, int b) { + return compare11(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual12(int a, int b) { + return compare12(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual13(int a, int b) { + return compare13(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual14(int a, int b) { + return compare14(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual15(int a, int b) { + return compare15(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual16(int a, int b) { + return compare16(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual17(int a, int b) { + return compare17(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual18(int a, int b) { + return compare18(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual19(int a, int b) { + return compare19(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual20(int a, int b) { + return compare20(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual21(int a, int b) { + return compare21(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual22(int a, int b) { + return compare22(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual23(int a, int b) { + return compare23(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual24(int a, int b) { + return compare24(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual25(int a, int b) { + return compare2(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual26(int a, int b) { + return compare26(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual27(int a, int b) { + return compare27(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual28(int a, int b) { + return compare28(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual29(int a, int b) { + return compare29(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual30(int a, int b) { + return compare30(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual31(int a, int b) { + return compare31(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual32(int a, int b) { + return compare32(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual33(int a, int b) { + return compare33(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual34(int a, int b) { + return compare34(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual35(int a, int b) { + return compare35(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual36(int a, int b) { + return compare36(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual37(int a, int b) { + return compare37(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual38(int a, int b) { + return compare38(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual39(int a, int b) { + return compare39(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual40(int a, int b) { + return compare40(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual41(int a, int b) { + return compare41(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual42(int a, int b) { + return compare42(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual43(int a, int b) { + return compare43(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual44(int a, int b) { + return compare44(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual45(int a, int b) { + return compare45(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual46(int a, int b) { + return compare46(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual47(int a, int b) { + return compare47(a, b) <= 0; + } + + @TestCase(op = Operation.SMALLER_EQUAL) + public static boolean testSmallerEqual48(int a, int b) { + return compare48(a, b) <= 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual1(int a, int b) { + return compare1(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual2(int a, int b) { + return compare2(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual3(int a, int b) { + return compare3(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual4(int a, int b) { + return compare4(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual5(int a, int b) { + return compare5(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual6(int a, int b) { + return compare6(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual7(int a, int b) { + return compare7(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual8(int a, int b) { + return compare8(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual9(int a, int b) { + return compare9(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual10(int a, int b) { + return compare10(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual11(int a, int b) { + return compare11(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual12(int a, int b) { + return compare12(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual13(int a, int b) { + return compare13(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual14(int a, int b) { + return compare14(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual15(int a, int b) { + return compare15(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual16(int a, int b) { + return compare16(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual17(int a, int b) { + return compare17(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual18(int a, int b) { + return compare18(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual19(int a, int b) { + return compare19(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual20(int a, int b) { + return compare20(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual21(int a, int b) { + return compare21(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual22(int a, int b) { + return compare22(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual23(int a, int b) { + return compare23(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual24(int a, int b) { + return compare24(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual25(int a, int b) { + return compare25(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual26(int a, int b) { + return compare26(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual27(int a, int b) { + return compare27(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual28(int a, int b) { + return compare28(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual29(int a, int b) { + return compare29(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual30(int a, int b) { + return compare30(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual31(int a, int b) { + return compare31(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual32(int a, int b) { + return compare32(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual33(int a, int b) { + return compare33(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual34(int a, int b) { + return compare34(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual35(int a, int b) { + return compare35(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual36(int a, int b) { + return compare36(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual37(int a, int b) { + return compare37(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual38(int a, int b) { + return compare38(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual39(int a, int b) { + return compare39(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual40(int a, int b) { + return compare40(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual41(int a, int b) { + return compare41(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual42(int a, int b) { + return compare42(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual43(int a, int b) { + return compare43(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual44(int a, int b) { + return compare44(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual45(int a, int b) { + return compare45(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual46(int a, int b) { + return compare46(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual47(int a, int b) { + return compare47(a, b) == 0; + } + + @TestCase(op = Operation.EQUAL) + public static boolean testEqual48(int a, int b) { + return compare48(a, b) == 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual1(int a, int b) { + return compare1(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual2(int a, int b) { + return compare2(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual3(int a, int b) { + return compare3(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual4(int a, int b) { + return compare4(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual5(int a, int b) { + return compare5(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual6(int a, int b) { + return compare6(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual7(int a, int b) { + return compare7(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual8(int a, int b) { + return compare8(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual9(int a, int b) { + return compare9(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual10(int a, int b) { + return compare10(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual11(int a, int b) { + return compare11(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual12(int a, int b) { + return compare12(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual13(int a, int b) { + return compare13(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual14(int a, int b) { + return compare14(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual15(int a, int b) { + return compare15(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual16(int a, int b) { + return compare16(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual17(int a, int b) { + return compare17(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual18(int a, int b) { + return compare18(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual19(int a, int b) { + return compare19(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual20(int a, int b) { + return compare20(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual21(int a, int b) { + return compare21(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual22(int a, int b) { + return compare22(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual23(int a, int b) { + return compare23(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual24(int a, int b) { + return compare24(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual25(int a, int b) { + return compare25(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual26(int a, int b) { + return compare26(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual27(int a, int b) { + return compare27(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual28(int a, int b) { + return compare28(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual29(int a, int b) { + return compare29(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual30(int a, int b) { + return compare30(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual31(int a, int b) { + return compare31(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual32(int a, int b) { + return compare32(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual33(int a, int b) { + return compare33(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual34(int a, int b) { + return compare34(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual35(int a, int b) { + return compare35(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual36(int a, int b) { + return compare36(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual37(int a, int b) { + return compare37(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual38(int a, int b) { + return compare38(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual39(int a, int b) { + return compare39(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual40(int a, int b) { + return compare40(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual41(int a, int b) { + return compare41(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual42(int a, int b) { + return compare42(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual43(int a, int b) { + return compare43(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual44(int a, int b) { + return compare44(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual45(int a, int b) { + return compare45(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual46(int a, int b) { + return compare46(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual47(int a, int b) { + return compare47(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER_EQUAL) + public static boolean testGreaterEqual48(int a, int b) { + return compare48(a, b) >= 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater1(int a, int b) { + return compare1(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater2(int a, int b) { + return compare1(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater3(int a, int b) { + return compare1(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater4(int a, int b) { + return compare2(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater5(int a, int b) { + return compare2(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater6(int a, int b) { + return compare2(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater7(int a, int b) { + return compare3(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater8(int a, int b) { + return compare3(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater9(int a, int b) { + return compare3(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater10(int a, int b) { + return compare4(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater11(int a, int b) { + return compare4(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater12(int a, int b) { + return compare4(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater13(int a, int b) { + return compare5(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater14(int a, int b) { + return compare5(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater15(int a, int b) { + return compare5(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater16(int a, int b) { + return compare6(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater17(int a, int b) { + return compare6(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater18(int a, int b) { + return compare6(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater19(int a, int b) { + return compare7(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater20(int a, int b) { + return compare7(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater21(int a, int b) { + return compare7(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater22(int a, int b) { + return compare8(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater23(int a, int b) { + return compare8(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater24(int a, int b) { + return compare8(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater25(int a, int b) { + return compare9(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater26(int a, int b) { + return compare9(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater27(int a, int b) { + return compare9(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater28(int a, int b) { + return compare10(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater29(int a, int b) { + return compare10(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater30(int a, int b) { + return compare10(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater31(int a, int b) { + return compare11(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater32(int a, int b) { + return compare11(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater33(int a, int b) { + return compare11(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater34(int a, int b) { + return compare12(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater35(int a, int b) { + return compare12(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater36(int a, int b) { + return compare12(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater37(int a, int b) { + return compare13(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater38(int a, int b) { + return compare13(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater39(int a, int b) { + return compare13(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater40(int a, int b) { + return compare14(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater41(int a, int b) { + return compare14(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater42(int a, int b) { + return compare14(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater43(int a, int b) { + return compare15(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater44(int a, int b) { + return compare15(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater45(int a, int b) { + return compare15(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater46(int a, int b) { + return compare16(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater47(int a, int b) { + return compare16(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater48(int a, int b) { + return compare16(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater49(int a, int b) { + return compare17(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater50(int a, int b) { + return compare17(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater51(int a, int b) { + return compare17(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater52(int a, int b) { + return compare18(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater53(int a, int b) { + return compare18(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater54(int a, int b) { + return compare18(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater55(int a, int b) { + return compare19(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater56(int a, int b) { + return compare19(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater57(int a, int b) { + return compare19(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater58(int a, int b) { + return compare20(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater59(int a, int b) { + return compare20(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater60(int a, int b) { + return compare20(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater61(int a, int b) { + return compare21(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater62(int a, int b) { + return compare21(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater63(int a, int b) { + return compare21(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater64(int a, int b) { + return compare22(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater65(int a, int b) { + return compare22(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater66(int a, int b) { + return compare22(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater67(int a, int b) { + return compare23(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater68(int a, int b) { + return compare23(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater69(int a, int b) { + return compare23(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater70(int a, int b) { + return compare24(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater71(int a, int b) { + return compare24(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater72(int a, int b) { + return compare24(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater73(int a, int b) { + return compare25(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater74(int a, int b) { + return compare25(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater75(int a, int b) { + return compare25(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater76(int a, int b) { + return compare26(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater77(int a, int b) { + return compare26(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater78(int a, int b) { + return compare26(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater79(int a, int b) { + return compare27(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater80(int a, int b) { + return compare27(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater81(int a, int b) { + return compare27(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater82(int a, int b) { + return compare28(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater83(int a, int b) { + return compare28(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater84(int a, int b) { + return compare28(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater85(int a, int b) { + return compare29(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater86(int a, int b) { + return compare29(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater87(int a, int b) { + return compare29(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater88(int a, int b) { + return compare30(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater89(int a, int b) { + return compare30(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater90(int a, int b) { + return compare30(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater91(int a, int b) { + return compare31(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater92(int a, int b) { + return compare31(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater93(int a, int b) { + return compare31(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater94(int a, int b) { + return compare32(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater95(int a, int b) { + return compare32(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater96(int a, int b) { + return compare32(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater97(int a, int b) { + return compare33(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater98(int a, int b) { + return compare33(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater99(int a, int b) { + return compare33(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater100(int a, int b) { + return compare34(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater101(int a, int b) { + return compare34(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater102(int a, int b) { + return compare34(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater103(int a, int b) { + return compare35(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater104(int a, int b) { + return compare35(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater105(int a, int b) { + return compare35(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater106(int a, int b) { + return compare36(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater107(int a, int b) { + return compare36(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater108(int a, int b) { + return compare36(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater109(int a, int b) { + return compare37(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater110(int a, int b) { + return compare37(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater111(int a, int b) { + return compare37(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater112(int a, int b) { + return compare38(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater113(int a, int b) { + return compare38(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater114(int a, int b) { + return compare38(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater115(int a, int b) { + return compare39(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater116(int a, int b) { + return compare39(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater117(int a, int b) { + return compare39(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater118(int a, int b) { + return compare40(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater119(int a, int b) { + return compare40(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater120(int a, int b) { + return compare40(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater121(int a, int b) { + return compare41(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater122(int a, int b) { + return compare41(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater123(int a, int b) { + return compare41(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater124(int a, int b) { + return compare42(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater125(int a, int b) { + return compare42(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater126(int a, int b) { + return compare42(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater127(int a, int b) { + return compare43(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater128(int a, int b) { + return compare43(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater129(int a, int b) { + return compare43(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater130(int a, int b) { + return compare44(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater131(int a, int b) { + return compare44(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater132(int a, int b) { + return compare44(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater133(int a, int b) { + return compare45(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater134(int a, int b) { + return compare45(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater135(int a, int b) { + return compare45(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater136(int a, int b) { + return compare46(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater137(int a, int b) { + return compare46(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater138(int a, int b) { + return compare46(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater139(int a, int b) { + return compare47(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater140(int a, int b) { + return compare47(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater141(int a, int b) { + return compare47(a, b) >= 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater142(int a, int b) { + return compare48(a, b) == 1; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater143(int a, int b) { + return compare48(a, b) > 0; + } + + @TestCase(op = Operation.GREATER) + public static boolean testGreater144(int a, int b) { + return compare48(a, b) >= 1; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse1(int a, int b) { + return compareAlwaysFalse1(a, b) == 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse2(int a, int b) { + return compareAlwaysFalse1(a, b) > 1; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse3(int a, int b) { + return compareAlwaysFalse1(a, b) >= 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse4(int a, int b) { + return compareAlwaysFalse2(a, b) == 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse5(int a, int b) { + return compareAlwaysFalse2(a, b) > 1; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse6(int a, int b) { + return compareAlwaysFalse2(a, b) >= 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse7(int a, int b) { + return compareAlwaysFalse3(a, b) == 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse8(int a, int b) { + return compareAlwaysFalse3(a, b) > 1; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse9(int a, int b) { + return compareAlwaysFalse3(a, b) >= 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse10(int a, int b) { + return compareAlwaysFalse4(a, b) == 2; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse11(int a, int b) { + return compareAlwaysFalse4(a, b) > 1; + } + + @TestCase(op = Operation.ALWAYS_FALSE) + public static boolean testAlwaysFalse12(int a, int b) { + return compareAlwaysFalse4(a, b) >= 2; + } + + enum Operation { + SMALLER, + SMALLER_EQUAL, + EQUAL, + GREATER_EQUAL, + GREATER, + ALWAYS_FALSE + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @interface TestCase { + Operation op(); + } + + @Override + protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { + if (method.getDeclaringClass().getUnqualifiedName().equals(TrichotomyTest.class.getSimpleName()) && method.getName().startsWith("compare")) { + return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method); + } + return super.bytecodeParserShouldInlineInvoke(b, method, args); + } + + private static void runTest(TrichotomyTest self, FrameworkMethod method) { + String name = method.getName(); + + // test correctness + TestCase test = method.getAnnotation(TestCase.class); + Operation op = test.op(); + Result result = self.test(name, 0, 0); + Assert.assertEquals(result.returnValue, (op == Operation.EQUAL || op == Operation.SMALLER_EQUAL || op == Operation.GREATER_EQUAL) ? true : false); + result = self.test(name, 0, 1); + Assert.assertEquals(result.returnValue, (op == Operation.SMALLER || op == Operation.SMALLER_EQUAL) ? true : false); + result = self.test(name, 1, 0); + Assert.assertEquals(result.returnValue, (op == Operation.GREATER || op == Operation.GREATER_EQUAL) ? true : false); + + // test folding + StructuredGraph graph = self.parseForCompile(self.getResolvedJavaMethod(name)); + HighTierContext context = self.getDefaultHighTierContext(); + CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); + canonicalizer.apply(graph, context); + Assert.assertTrue("Too many ConditionalNodes after canonicalization", graph.getNodes().filter(ConditionalNode.class).count() <= 1); + Assert.assertTrue("Unexpected IfNodes after canonicalization", graph.getNodes().filter(IfNode.class).isEmpty()); + } + + public static class Runner extends BlockJUnit4ClassRunner { + public Runner(Class klass) throws InitializationError { + super(klass); + } + + @Override + protected List computeTestMethods() { + return getTestClass().getAnnotatedMethods(TestCase.class); + } + + @Override + protected void runChild(FrameworkMethod method, RunNotifier notifier) { + super.runChild(method, notifier); + } + + @Override + protected Statement methodInvoker(FrameworkMethod method, Object test) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + runTest((TrichotomyTest) test, method); + } + }; + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java index f5876d0a77..be878b18f3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance01.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.jtt.JTTTest; public final class Class_newInstance01 extends JTTTest { - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean test(int i) throws IllegalAccessException, InstantiationException { if (i == 0) { return Class_newInstance01.class.newInstance() != null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java index b8d3d3a7e7..750a909140 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance02.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.jtt.JTTTest; public final class Class_newInstance02 extends JTTTest { - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean test(int i) throws IllegalAccessException, InstantiationException { if (i == 0) { // note: we rely on the other class here. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java index d119d94a4a..0fde2f84ce 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance03.java @@ -35,7 +35,7 @@ public class Class_newInstance03 extends JTTTest { public abstract static class AbstractClass { } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean test(int i) throws IllegalAccessException, InstantiationException { if (i == 0) { return AbstractClass.class.newInstance() != null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java index cd8962c20b..c91e693757 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance06.java @@ -40,7 +40,7 @@ public final class Class_newInstance06 extends JTTTest { } } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean test(int i) throws IllegalAccessException, InstantiationException { if (i == 0) { return Class_newInstance.class.newInstance() != null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java index d84bc61548..beb47a27ae 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/reflect/Class_newInstance07.java @@ -39,7 +39,7 @@ public final class Class_newInstance07 extends JTTTest { } } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean test(int i) throws IllegalAccessException, InstantiationException { if (i == 0) { return Class_newInstance.class.newInstance() != null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java index b821bc07bb..4bffbbab76 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayCompareToOp.java @@ -30,8 +30,8 @@ import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; -import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; @@ -78,8 +78,8 @@ public final class AArch64ArrayCompareToOp extends AArch64LIRInstruction { this.kind2 = kind2; // Both offsets should be the same but better be safe than sorry. - this.array1BaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind1); - this.array2BaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind2); + this.array1BaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(kind1); + this.array2BaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(kind2); this.resultValue = result; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java index f0ba1fa227..51b3fdd997 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java @@ -64,14 +64,14 @@ public final class AArch64ArrayEqualsOp extends AArch64LIRInstruction { @Temp({REG}) protected Value temp3; @Temp({REG}) protected Value temp4; - public AArch64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { + public AArch64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length, boolean directPointers) { super(TYPE); assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; - this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); - this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); + this.arrayBaseOffset = directPointers ? 0 : tool.getProviders().getMetaAccess().getArrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getMetaAccess().getArrayIndexScale(kind); this.resultValue = result; this.array1Value = array1; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SpeculativeBarrier.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SpeculativeBarrier.java new file mode 100644 index 0000000000..b2cfef2a5a --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SpeculativeBarrier.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018, 2018, 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.lir.aarch64; + +import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; + +public class AArch64SpeculativeBarrier extends AArch64LIRInstruction { + private static final LIRInstructionClass TYPE = LIRInstructionClass.create(AArch64SpeculativeBarrier.class); + + public AArch64SpeculativeBarrier() { + super(TYPE); + } + + @Override + protected void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { + masm.csdb(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java index 0c8505b73e..9d9c2d7f32 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArithmeticLIRGeneratorTool.java @@ -39,6 +39,14 @@ public interface AMD64ArithmeticLIRGeneratorTool extends ArithmeticLIRGeneratorT Value emitCountTrailingZeros(Value value); + Value emitLogicalAndNot(Value value1, Value value2); + + Value emitLowestSetIsolatedBit(Value value); + + Value emitGetMaskUpToLowestSetBit(Value value); + + Value emitResetLowestSetBit(Value value); + enum RoundingMode { NEAREST(0), DOWN(1), diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java index 4d9416797c..e953e68062 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayCompareToOp.java @@ -84,8 +84,8 @@ public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction { this.kind2 = kind2; // Both offsets should be the same but better be safe than sorry. - this.array1BaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind1); - this.array2BaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind2); + this.array1BaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(kind1); + this.array2BaseOffset = tool.getProviders().getMetaAccess().getArrayBaseOffset(kind2); this.resultValue = result; this.array1Value = array1; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java index 7ea304d419..807983c49d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java @@ -24,24 +24,6 @@ package org.graalvm.compiler.lir.amd64; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.amd64.AMD64Address; -import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; -import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; -import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; -import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; -import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; -import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.NumUtil; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64.CPUFeature; import jdk.vm.ci.amd64.AMD64Kind; @@ -49,6 +31,25 @@ import jdk.vm.ci.code.Register; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.Value; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; +import org.graalvm.compiler.asm.amd64.AMD64Assembler; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; +import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; +import org.graalvm.compiler.asm.amd64.AMD64BaseAssembler.OperandSize; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.asm.amd64.AVXKind; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.core.common.NumUtil; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; /** * Emits code which compares two arrays of the same length. If the CPU supports any vector @@ -61,28 +62,39 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { private final JavaKind kind; private final int arrayBaseOffset; private final int arrayIndexScale; + private final int constantByteLength; - @Def({REG}) protected Value resultValue; - @Alive({REG}) protected Value array1Value; - @Alive({REG}) protected Value array2Value; - @Alive({REG}) protected Value lengthValue; - @Temp({REG}) protected Value temp1; - @Temp({REG}) protected Value temp2; - @Temp({REG}) protected Value temp3; - @Temp({REG}) protected Value temp4; + @Def({REG}) private Value resultValue; + @Alive({REG}) private Value array1Value; + @Alive({REG}) private Value array2Value; + @Alive({REG}) private Value lengthValue; + @Temp({REG}) private Value temp1; + @Temp({REG}) private Value temp2; + @Temp({REG}) private Value temp3; + @Temp({REG}) private Value temp4; - @Temp({REG, ILLEGAL}) protected Value temp5; - @Temp({REG, ILLEGAL}) protected Value tempXMM; + @Temp({REG, ILLEGAL}) private Value temp5; + @Temp({REG, ILLEGAL}) private Value tempXMM; - @Temp({REG, ILLEGAL}) protected Value vectorTemp1; - @Temp({REG, ILLEGAL}) protected Value vectorTemp2; + @Temp({REG, ILLEGAL}) private Value vectorTemp1; + @Temp({REG, ILLEGAL}) private Value vectorTemp2; + @Temp({REG, ILLEGAL}) private Value vectorTemp3; + @Temp({REG, ILLEGAL}) private Value vectorTemp4; - public AMD64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length) { + public AMD64ArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, Value result, Value array1, Value array2, Value length, + int constantLength, boolean directPointers, int maxVectorSize) { super(TYPE); this.kind = kind; - this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); - this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); + this.arrayBaseOffset = directPointers ? 0 : tool.getProviders().getMetaAccess().getArrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getMetaAccess().getArrayIndexScale(kind); + + if (constantLength >= 0 && arrayIndexScale > 1) { + // scale length + this.constantByteLength = constantLength << NumUtil.log2Ceil(arrayIndexScale); + } else { + this.constantByteLength = constantLength; + } this.resultValue = result; this.array1Value = array1; @@ -106,20 +118,35 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { // We only need the vector temporaries if we generate SSE code. if (supportsSSE41(tool.target())) { - this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); - this.vectorTemp2 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + if (canGenerateConstantLengthCompare(tool.target())) { + LIRKind lirKind = LIRKind.value(supportsAVX2(tool.target()) && (maxVectorSize < 0 || maxVectorSize >= 32) ? AMD64Kind.V256_BYTE : AMD64Kind.V128_BYTE); + this.vectorTemp1 = tool.newVariable(lirKind); + this.vectorTemp2 = tool.newVariable(lirKind); + this.vectorTemp3 = tool.newVariable(lirKind); + this.vectorTemp4 = tool.newVariable(lirKind); + } else { + this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.vectorTemp2 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE)); + this.vectorTemp3 = Value.ILLEGAL; + this.vectorTemp4 = Value.ILLEGAL; + } } else { this.vectorTemp1 = Value.ILLEGAL; this.vectorTemp2 = Value.ILLEGAL; + this.vectorTemp3 = Value.ILLEGAL; + this.vectorTemp4 = Value.ILLEGAL; } } + private boolean canGenerateConstantLengthCompare(TargetDescription target) { + return constantByteLength >= 0 && kind.isNumericInteger() && supportsSSE41(target); + } + @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { Register result = asRegister(resultValue); Register array1 = asRegister(temp1); Register array2 = asRegister(temp2); - Register length = asRegister(temp3); Label trueLabel = new Label(); Label falseLabel = new Label(); @@ -129,26 +156,25 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.leaq(array1, new AMD64Address(asRegister(array1Value), arrayBaseOffset)); masm.leaq(array2, new AMD64Address(asRegister(array2Value), arrayBaseOffset)); - // Get array length in bytes. - masm.movl(length, asRegister(lengthValue)); + if (canGenerateConstantLengthCompare(crb.target)) { + emitConstantLengthArrayCompareBytes(masm, array1, array2, asRegister(temp3), asRegister(temp4), + new Register[]{asRegister(vectorTemp1), asRegister(vectorTemp2), asRegister(vectorTemp3), asRegister(vectorTemp4)}, + falseLabel, constantByteLength, AVXKind.getRegisterSize(vectorTemp1).getBytes()); + } else { + Register length = asRegister(temp3); - if (arrayIndexScale > 1) { - masm.shll(length, NumUtil.log2Ceil(arrayIndexScale)); // scale length + // Get array length in bytes. + masm.movl(length, asRegister(lengthValue)); + + if (arrayIndexScale > 1) { + masm.shll(length, NumUtil.log2Ceil(arrayIndexScale)); // scale length + } + + masm.movl(result, length); // copy + + emitArrayCompare(crb, masm, kind, result, array1, array2, length, temp4, temp5, tempXMM, vectorTemp1, vectorTemp2, trueLabel, falseLabel); } - masm.movl(result, length); // copy - - if (supportsAVX2(crb.target)) { - emitAVXCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); - } else if (supportsSSE41(crb.target)) { - // this code is used for AVX as well because our backend correctly ensures that - // VEX-prefixed instructions are emitted if AVX is supported - emitSSE41Compare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); - } - - emit8ByteCompare(crb, masm, result, array1, array2, length, trueLabel, falseLabel); - emitTailCompares(masm, result, array1, array2, length, trueLabel, falseLabel); - // Return true masm.bind(trueLabel); masm.movl(result, 1); @@ -162,6 +188,21 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.bind(done); } + private static void emitArrayCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, JavaKind kind, + Register result, Register array1, Register array2, Register length, + Value temp4, Value temp5, Value tempXMM, Value vectorTemp1, Value vectorTemp2, + Label trueLabel, Label falseLabel) { + if (supportsAVX2(crb.target)) { + emitAVXCompare(crb, masm, kind, result, array1, array2, length, temp4, temp5, tempXMM, vectorTemp1, vectorTemp2, trueLabel, falseLabel); + } else if (supportsSSE41(crb.target)) { + // this code is used for AVX as well because our backend correctly ensures that + // VEX-prefixed instructions are emitted if AVX is supported + emitSSE41Compare(crb, masm, kind, result, array1, array2, length, temp4, temp5, tempXMM, vectorTemp1, vectorTemp2, trueLabel, falseLabel); + } + emit8ByteCompare(crb, masm, kind, result, array1, array2, length, temp4, tempXMM, trueLabel, falseLabel); + emitTailCompares(masm, kind, result, array1, array2, length, temp4, tempXMM, trueLabel, falseLabel); + } + /** * Returns if the underlying AMD64 architecture supports SSE 4.1 instructions. * @@ -181,11 +222,14 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code that uses SSE4.1 128-bit (16-byte) vector compares. */ - private void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + private static void emitSSE41Compare(CompilationResultBuilder crb, AMD64MacroAssembler masm, JavaKind kind, + Register result, Register array1, Register array2, Register length, + Value temp4, Value temp5, Value tempXMM, Value vectorTemp1, Value vectorTemp2, + Label trueLabel, Label falseLabel) { assert supportsSSE41(crb.target); - Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); - Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE); + Register vector1 = asRegister(vectorTemp1); + Register vector2 = asRegister(vectorTemp2); Label loop = new Label(); Label compareTail = new Label(); @@ -223,7 +267,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { Label unalignedCheck = new Label(); masm.jmpb(unalignedCheck); masm.bind(nanCheck); - emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, SSE4_1_VECTOR_SIZE); + emitFloatCompareWithinRange(crb, masm, kind, array1, array2, length, temp4, temp5, tempXMM, 0, falseLabel, SSE4_1_VECTOR_SIZE); masm.jmpb(loopCheck); masm.bind(unalignedCheck); } @@ -238,7 +282,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.ptest(vector1, vector1); if (requiresNaNCheck) { masm.jcc(ConditionFlag.Zero, trueLabel); - emitFloatCompareWithinRange(crb, masm, array1, array2, result, -SSE4_1_VECTOR_SIZE, falseLabel, SSE4_1_VECTOR_SIZE); + emitFloatCompareWithinRange(crb, masm, kind, array1, array2, result, temp4, temp5, tempXMM, -SSE4_1_VECTOR_SIZE, falseLabel, SSE4_1_VECTOR_SIZE); } else { masm.jcc(ConditionFlag.NotZero, falseLabel); } @@ -264,11 +308,14 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { */ private static final int AVX_VECTOR_SIZE = 32; - private void emitAVXCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + private static void emitAVXCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, JavaKind kind, Register result, + Register array1, Register array2, Register length, + Value temp4, Value temp5, Value tempXMM, Value vectorTemp1, Value vectorTemp2, + Label trueLabel, Label falseLabel) { assert supportsAVX2(crb.target); - Register vector1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE); - Register vector2 = asRegister(vectorTemp2, AMD64Kind.DOUBLE); + Register vector1 = asRegister(vectorTemp1); + Register vector2 = asRegister(vectorTemp2); Label loop = new Label(); Label compareTail = new Label(); @@ -306,7 +353,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { Label unalignedCheck = new Label(); masm.jmpb(unalignedCheck); masm.bind(nanCheck); - emitFloatCompareWithinRange(crb, masm, array1, array2, length, 0, falseLabel, AVX_VECTOR_SIZE); + emitFloatCompareWithinRange(crb, masm, kind, array1, array2, length, temp4, temp5, tempXMM, 0, falseLabel, AVX_VECTOR_SIZE); masm.jmpb(loopCheck); masm.bind(unalignedCheck); } @@ -321,7 +368,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.vptest(vector1, vector1); if (requiresNaNCheck) { masm.jcc(ConditionFlag.Zero, trueLabel); - emitFloatCompareWithinRange(crb, masm, array1, array2, result, -AVX_VECTOR_SIZE, falseLabel, AVX_VECTOR_SIZE); + emitFloatCompareWithinRange(crb, masm, kind, array1, array2, result, temp4, temp5, tempXMM, -AVX_VECTOR_SIZE, falseLabel, AVX_VECTOR_SIZE); } else { masm.jcc(ConditionFlag.NotZero, falseLabel); } @@ -339,7 +386,8 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code that uses 8-byte vector compares. */ - private void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + private static void emit8ByteCompare(CompilationResultBuilder crb, AMD64MacroAssembler masm, JavaKind kind, Register result, Register array1, Register array2, Register length, Value temp4, + Value tempXMM, Label trueLabel, Label falseLabel) { Label loop = new Label(); Label compareTail = new Label(); @@ -378,7 +426,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.bind(nanCheck); // At most two iterations, unroll in the emitted code. for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) { - emitFloatCompare(masm, array1, array2, length, offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); + emitFloatCompare(masm, kind, array1, array2, length, temp4, tempXMM, offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); } masm.jmpb(loopCheck); masm.bind(unalignedCheck); @@ -394,7 +442,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.jcc(ConditionFlag.Equal, trueLabel); // At most two iterations, unroll in the emitted code. for (int offset = 0; offset < VECTOR_SIZE; offset += kind.getByteCount()) { - emitFloatCompare(masm, array1, array2, result, -VECTOR_SIZE + offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); + emitFloatCompare(masm, kind, array1, array2, result, temp4, tempXMM, -VECTOR_SIZE + offset, falseLabel, kind.getByteCount() == VECTOR_SIZE); } } else { masm.jccb(ConditionFlag.NotEqual, falseLabel); @@ -408,7 +456,8 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code to compare the remaining 1 to 4 bytes. */ - private void emitTailCompares(AMD64MacroAssembler masm, Register result, Register array1, Register array2, Register length, Label trueLabel, Label falseLabel) { + private static void emitTailCompares(AMD64MacroAssembler masm, JavaKind kind, Register result, Register array1, Register array2, Register length, Value temp4, Value tempXMM, + Label trueLabel, Label falseLabel) { Label compare2Bytes = new Label(); Label compare1Byte = new Label(); @@ -422,7 +471,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.cmpl(temp, new AMD64Address(array2, 0)); if (kind == JavaKind.Float) { masm.jccb(ConditionFlag.Equal, trueLabel); - emitFloatCompare(masm, array1, array2, Register.None, 0, falseLabel, true); + emitFloatCompare(masm, kind, array1, array2, Register.None, temp4, tempXMM, 0, falseLabel, true); masm.jmpb(trueLabel); } else { masm.jccb(ConditionFlag.NotEqual, falseLabel); @@ -467,7 +516,7 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code to fall through if {@code src} is NaN, otherwise jump to {@code branchOrdered}. */ - private void emitNaNCheck(AMD64MacroAssembler masm, AMD64Address src, Label branchIfNonNaN) { + private static void emitNaNCheck(AMD64MacroAssembler masm, JavaKind kind, Value tempXMM, AMD64Address src, Label branchIfNonNaN) { assert kind.isNumericFloat(); Register tempXMMReg = asRegister(tempXMM); if (kind == JavaKind.Float) { @@ -482,7 +531,8 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code to compare if two floats are bitwise equal or both NaN. */ - private void emitFloatCompare(AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, boolean skipBitwiseCompare) { + private static void emitFloatCompare(AMD64MacroAssembler masm, JavaKind kind, Register base1, Register base2, Register index, Value temp4, Value tempXMM, int offset, Label falseLabel, + boolean skipBitwiseCompare) { AMD64Address address1 = new AMD64Address(base1, index, Scale.Times1, offset); AMD64Address address2 = new AMD64Address(base2, index, Scale.Times1, offset); @@ -502,8 +552,8 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { masm.jccb(ConditionFlag.Equal, bitwiseEqual); } - emitNaNCheck(masm, address1, falseLabel); - emitNaNCheck(masm, address2, falseLabel); + emitNaNCheck(masm, kind, tempXMM, address1, falseLabel); + emitNaNCheck(masm, kind, tempXMM, address2, falseLabel); masm.bind(bitwiseEqual); } @@ -511,7 +561,8 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { /** * Emits code to compare float equality within a range. */ - private void emitFloatCompareWithinRange(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register base1, Register base2, Register index, int offset, Label falseLabel, int range) { + private static void emitFloatCompareWithinRange(CompilationResultBuilder crb, AMD64MacroAssembler masm, JavaKind kind, Register base1, Register base2, Register index, Value temp4, Value temp5, + Value tempXMM, int offset, Label falseLabel, int range) { assert kind.isNumericFloat(); Label loop = new Label(); Register i = asRegister(temp5); @@ -521,11 +572,216 @@ public final class AMD64ArrayEqualsOp extends AMD64LIRInstruction { // Align the main loop masm.align(crb.target.wordSize * 2); masm.bind(loop); - emitFloatCompare(masm, base1, base2, index, offset, falseLabel, kind.getByteCount() == range); + emitFloatCompare(masm, kind, base1, base2, index, temp4, tempXMM, offset, falseLabel, kind.getByteCount() == range); masm.addq(index, kind.getByteCount()); masm.addq(i, kind.getByteCount()); masm.jccb(ConditionFlag.NotZero, loop); // Floats within the range are equal, revert change to the register index masm.subq(index, range); } + + /** + * Emits specialized assembly for checking equality of memory regions + * {@code arrayPtr1[0..nBytes]} and {@code arrayPtr2[0..nBytes]}. If they match, execution + * continues directly after the emitted code block, otherwise we jump to {@code noMatch}. + */ + private static void emitConstantLengthArrayCompareBytes( + AMD64MacroAssembler asm, + Register arrayPtr1, + Register arrayPtr2, + Register tmp1, + Register tmp2, + Register[] tmpVectors, + Label noMatch, + int nBytes, + int bytesPerVector) { + assert bytesPerVector >= 16; + if (nBytes == 0) { + // do nothing + return; + } + if (nBytes < 16) { + // array is shorter than any vector register, use regular CMP instructions + int movSize = (nBytes < 2) ? 1 : ((nBytes < 4) ? 2 : ((nBytes < 8) ? 4 : 8)); + emitMovBytes(asm, tmp1, new AMD64Address(arrayPtr1), movSize); + emitMovBytes(asm, tmp2, new AMD64Address(arrayPtr2), movSize); + emitCmpBytes(asm, tmp1, tmp2, movSize); + asm.jcc(AMD64Assembler.ConditionFlag.NotEqual, noMatch); + if (nBytes > movSize) { + emitMovBytes(asm, tmp1, new AMD64Address(arrayPtr1, nBytes - movSize), movSize); + emitMovBytes(asm, tmp2, new AMD64Address(arrayPtr2, nBytes - movSize), movSize); + emitCmpBytes(asm, tmp1, tmp2, movSize); + asm.jcc(AMD64Assembler.ConditionFlag.NotEqual, noMatch); + } + } else if (nBytes < 32 && bytesPerVector >= 32) { + // we could use YMM registers, but the array is too short, force XMM registers + int bytesPerXMMVector = AVXKind.AVXSize.XMM.getBytes(); + AMD64Assembler.VexMoveOp.VMOVDQU.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[0], new AMD64Address(arrayPtr1)); + AMD64Assembler.VexMoveOp.VMOVDQU.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[1], new AMD64Address(arrayPtr2)); + AMD64Assembler.VexRVMOp.VPXOR.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[0], tmpVectors[0], tmpVectors[1]); + if (nBytes > bytesPerXMMVector) { + AMD64Assembler.VexMoveOp.VMOVDQU.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[2], new AMD64Address(arrayPtr1, nBytes - bytesPerXMMVector)); + AMD64Assembler.VexMoveOp.VMOVDQU.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[3], new AMD64Address(arrayPtr2, nBytes - bytesPerXMMVector)); + AMD64Assembler.VexRVMOp.VPXOR.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[2], tmpVectors[2], tmpVectors[3]); + AMD64Assembler.VexRMOp.VPTEST.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + AMD64Assembler.VexRMOp.VPTEST.emit(asm, AVXKind.AVXSize.XMM, tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } else if (bytesPerVector >= 32) { + // AVX2 supported, use YMM vectors + assert asm.supports(CPUFeature.AVX2); + int loopCount = nBytes / (bytesPerVector * 2); + int rest = nBytes % (bytesPerVector * 2); + if (loopCount > 0) { + if (0 < rest && rest < bytesPerVector) { + loopCount--; + } + if (loopCount > 0) { + if (loopCount > 1) { + asm.movl(tmp1, loopCount); + } + Label loopBegin = new Label(); + asm.bind(loopBegin); + asm.vmovdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.vmovdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.vmovdqu(tmpVectors[2], new AMD64Address(arrayPtr1, bytesPerVector)); + asm.vmovdqu(tmpVectors[3], new AMD64Address(arrayPtr2, bytesPerVector)); + asm.vpxor(tmpVectors[0], tmpVectors[0], tmpVectors[1]); + asm.vpxor(tmpVectors[2], tmpVectors[2], tmpVectors[3]); + asm.vptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.vptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.addq(arrayPtr1, bytesPerVector * 2); + asm.addq(arrayPtr2, bytesPerVector * 2); + if (loopCount > 1) { + asm.decrementl(tmp1); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, loopBegin); + } + } + if (0 < rest && rest < bytesPerVector) { + asm.vmovdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.vmovdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.vmovdqu(tmpVectors[2], new AMD64Address(arrayPtr1, bytesPerVector)); + asm.vmovdqu(tmpVectors[3], new AMD64Address(arrayPtr2, bytesPerVector)); + asm.vpxor(tmpVectors[0], tmpVectors[0], tmpVectors[1]); + asm.vpxor(tmpVectors[2], tmpVectors[2], tmpVectors[3]); + asm.vptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.vptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.vmovdqu(tmpVectors[0], new AMD64Address(arrayPtr1, bytesPerVector + rest)); + asm.vmovdqu(tmpVectors[1], new AMD64Address(arrayPtr2, bytesPerVector + rest)); + asm.vpxor(tmpVectors[0], tmpVectors[0], tmpVectors[1]); + asm.vptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + } + if (rest >= bytesPerVector) { + asm.vmovdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.vmovdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.vpxor(tmpVectors[0], tmpVectors[0], tmpVectors[1]); + if (rest > bytesPerVector) { + asm.vmovdqu(tmpVectors[2], new AMD64Address(arrayPtr1, rest - bytesPerVector)); + asm.vmovdqu(tmpVectors[3], new AMD64Address(arrayPtr2, rest - bytesPerVector)); + asm.vpxor(tmpVectors[2], tmpVectors[2], tmpVectors[3]); + asm.vptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + asm.vptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + } else { + // on AVX or SSE, use XMM vectors + int loopCount = nBytes / (bytesPerVector * 2); + int rest = nBytes % (bytesPerVector * 2); + if (loopCount > 0) { + if (0 < rest && rest < bytesPerVector) { + loopCount--; + } + if (loopCount > 0) { + if (loopCount > 1) { + asm.movl(tmp1, loopCount); + } + Label loopBegin = new Label(); + asm.bind(loopBegin); + asm.movdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.movdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.movdqu(tmpVectors[2], new AMD64Address(arrayPtr1, bytesPerVector)); + asm.movdqu(tmpVectors[3], new AMD64Address(arrayPtr2, bytesPerVector)); + asm.pxor(tmpVectors[0], tmpVectors[1]); + asm.pxor(tmpVectors[2], tmpVectors[3]); + asm.ptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.ptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.addq(arrayPtr1, bytesPerVector * 2); + asm.addq(arrayPtr2, bytesPerVector * 2); + if (loopCount > 1) { + asm.decrementl(tmp1); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, loopBegin); + } + } + if (0 < rest && rest < bytesPerVector) { + asm.movdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.movdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.movdqu(tmpVectors[2], new AMD64Address(arrayPtr1, bytesPerVector)); + asm.movdqu(tmpVectors[3], new AMD64Address(arrayPtr2, bytesPerVector)); + asm.pxor(tmpVectors[0], tmpVectors[1]); + asm.pxor(tmpVectors[2], tmpVectors[3]); + asm.ptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.ptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + asm.movdqu(tmpVectors[0], new AMD64Address(arrayPtr1, bytesPerVector + rest)); + asm.movdqu(tmpVectors[1], new AMD64Address(arrayPtr2, bytesPerVector + rest)); + asm.pxor(tmpVectors[0], tmpVectors[1]); + asm.ptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + } + if (rest >= bytesPerVector) { + asm.movdqu(tmpVectors[0], new AMD64Address(arrayPtr1)); + asm.movdqu(tmpVectors[1], new AMD64Address(arrayPtr2)); + asm.pxor(tmpVectors[0], tmpVectors[1]); + if (rest > bytesPerVector) { + asm.movdqu(tmpVectors[2], new AMD64Address(arrayPtr1, rest - bytesPerVector)); + asm.movdqu(tmpVectors[3], new AMD64Address(arrayPtr2, rest - bytesPerVector)); + asm.pxor(tmpVectors[2], tmpVectors[3]); + asm.ptest(tmpVectors[2], tmpVectors[2]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + asm.ptest(tmpVectors[0], tmpVectors[0]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, noMatch); + } + } + } + + private static void emitMovBytes(AMD64MacroAssembler asm, Register dst, AMD64Address src, int size) { + switch (size) { + case 1: + asm.movzbl(dst, src); + break; + case 2: + asm.movzwl(dst, src); + break; + case 4: + asm.movl(dst, src); + break; + case 8: + asm.movq(dst, src); + break; + default: + throw new IllegalStateException(); + } + } + + private static void emitCmpBytes(AMD64MacroAssembler asm, Register dst, Register src, int size) { + if (size < 8) { + asm.cmpl(dst, src); + } else { + asm.cmpq(dst, src); + } + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java index a2d429315f..365b6e4da0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayIndexOfOp.java @@ -24,10 +24,12 @@ package org.graalvm.compiler.lir.amd64; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.amd64.AMD64.CPUFeature; +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; import org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.amd64.AMD64Address; import org.graalvm.compiler.asm.amd64.AMD64Assembler; @@ -43,12 +45,9 @@ import org.graalvm.compiler.lir.Opcode; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.gen.LIRGeneratorTool; -import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.amd64.AMD64.CPUFeature; -import jdk.vm.ci.amd64.AMD64Kind; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Value; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; /** */ @@ -58,175 +57,250 @@ public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction { private final JavaKind kind; private final int vmPageSize; + private final int nValues; + private final boolean findTwoConsecutive; + private final AMD64Kind vectorKind; @Def({REG}) protected Value resultValue; - @Alive({REG}) protected Value charArrayPtrValue; - @Use({REG}) protected Value charArrayLengthValue; - @Alive({REG}) protected Value searchCharValue; + @Alive({REG}) protected Value arrayPtrValue; + @Use({REG}) protected Value arrayLengthValue; + @Alive({REG}) protected Value searchValue1; + @Alive({REG, ILLEGAL}) protected Value searchValue2; + @Alive({REG, ILLEGAL}) protected Value searchValue3; + @Alive({REG, ILLEGAL}) protected Value searchValue4; @Temp({REG}) protected Value arraySlotsRemaining; @Temp({REG}) protected Value comparisonResult1; @Temp({REG}) protected Value comparisonResult2; @Temp({REG}) protected Value comparisonResult3; @Temp({REG}) protected Value comparisonResult4; - @Temp({REG, ILLEGAL}) protected Value vectorCompareVal; + @Temp({REG, ILLEGAL}) protected Value vectorCompareVal1; + @Temp({REG, ILLEGAL}) protected Value vectorCompareVal2; + @Temp({REG, ILLEGAL}) protected Value vectorCompareVal3; + @Temp({REG, ILLEGAL}) protected Value vectorCompareVal4; @Temp({REG, ILLEGAL}) protected Value vectorArray1; @Temp({REG, ILLEGAL}) protected Value vectorArray2; @Temp({REG, ILLEGAL}) protected Value vectorArray3; @Temp({REG, ILLEGAL}) protected Value vectorArray4; - public AMD64ArrayIndexOfOp( - JavaKind kind, - int vmPageSize, LIRGeneratorTool tool, - Value result, - Value arrayPtr, - Value arrayLength, - Value searchChar) { + public AMD64ArrayIndexOfOp(JavaKind kind, boolean findTwoConsecutive, int vmPageSize, int maxVectorSize, LIRGeneratorTool tool, Value result, Value arrayPtr, Value arrayLength, + Value... searchValues) { super(TYPE); this.kind = kind; + this.findTwoConsecutive = findTwoConsecutive; this.vmPageSize = vmPageSize; - assert byteMode() || charMode(); - assert supports(tool, CPUFeature.SSSE3) || supports(tool, CPUFeature.AVX) || supportsAVX2(tool); + assert 0 < searchValues.length && searchValues.length <= 4; + assert byteMode(kind) || charMode(kind); + assert supports(tool, CPUFeature.SSE2) || supports(tool, CPUFeature.AVX) || supportsAVX2(tool); + nValues = searchValues.length; + assert !findTwoConsecutive || nValues == 1; resultValue = result; - charArrayPtrValue = arrayPtr; - charArrayLengthValue = arrayLength; - searchCharValue = searchChar; - - this.arraySlotsRemaining = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); - this.comparisonResult1 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); - this.comparisonResult2 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); - this.comparisonResult3 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); - this.comparisonResult4 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); - AMD64Kind vectorKind = byteMode() ? supportsAVX2(tool) ? AMD64Kind.V256_BYTE : AMD64Kind.V128_BYTE : supportsAVX2(tool) ? AMD64Kind.V256_WORD : AMD64Kind.V128_WORD; - this.vectorCompareVal = tool.newVariable(LIRKind.value(vectorKind)); - this.vectorArray1 = tool.newVariable(LIRKind.value(vectorKind)); - this.vectorArray2 = tool.newVariable(LIRKind.value(vectorKind)); - this.vectorArray3 = tool.newVariable(LIRKind.value(vectorKind)); - this.vectorArray4 = tool.newVariable(LIRKind.value(vectorKind)); + arrayPtrValue = arrayPtr; + arrayLengthValue = arrayLength; + searchValue1 = searchValues[0]; + searchValue2 = nValues > 1 ? searchValues[1] : Value.ILLEGAL; + searchValue3 = nValues > 2 ? searchValues[2] : Value.ILLEGAL; + searchValue4 = nValues > 3 ? searchValues[3] : Value.ILLEGAL; + arraySlotsRemaining = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + comparisonResult1 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + comparisonResult2 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + comparisonResult3 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + comparisonResult4 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + vectorKind = supportsAVX2(tool) && (maxVectorSize < 0 || maxVectorSize >= 32) ? byteMode(kind) ? AMD64Kind.V256_BYTE : AMD64Kind.V256_WORD + : byteMode(kind) ? AMD64Kind.V128_BYTE : AMD64Kind.V128_WORD; + vectorCompareVal1 = tool.newVariable(LIRKind.value(vectorKind)); + vectorCompareVal2 = nValues > 1 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL; + vectorCompareVal3 = nValues > 2 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL; + vectorCompareVal4 = nValues > 3 ? tool.newVariable(LIRKind.value(vectorKind)) : Value.ILLEGAL; + vectorArray1 = tool.newVariable(LIRKind.value(vectorKind)); + vectorArray2 = tool.newVariable(LIRKind.value(vectorKind)); + vectorArray3 = tool.newVariable(LIRKind.value(vectorKind)); + vectorArray4 = tool.newVariable(LIRKind.value(vectorKind)); } - private boolean byteMode() { + private static boolean byteMode(JavaKind kind) { return kind == JavaKind.Byte; } - private boolean charMode() { + private static boolean charMode(JavaKind kind) { return kind == JavaKind.Char; } @Override public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) { - Register arrayPtr = asRegister(charArrayPtrValue); - Register arrayLength = asRegister(charArrayLengthValue); - Register searchValue = asRegister(searchCharValue); + Register arrayPtr = asRegister(arrayPtrValue); + Register arrayLength = asRegister(arrayLengthValue); Register result = asRegister(resultValue); - Register vecCmp = asRegister(vectorCompareVal); - Register vecArray1 = asRegister(vectorArray1); - Register vecArray2 = asRegister(vectorArray2); - Register vecArray3 = asRegister(vectorArray3); - Register vecArray4 = asRegister(vectorArray4); Register slotsRemaining = asRegister(arraySlotsRemaining); - Register cmpResult1 = asRegister(comparisonResult1); - Register cmpResult2 = asRegister(comparisonResult2); - Register cmpResult3 = asRegister(comparisonResult3); - Register cmpResult4 = asRegister(comparisonResult4); - - Label bulkVectorLoop = new Label(); - Label singleVectorLoop = new Label(); - Label vectorFound1 = new Label(); - Label vectorFound2 = new Label(); - Label vectorFound3 = new Label(); - Label vectorFound4 = new Label(); - Label lessThanVectorSizeRemaining = new Label(); - Label lessThanVectorSizeRemainingLoop = new Label(); + Register[] searchValue = { + nValues > 0 ? asRegister(searchValue1) : null, + nValues > 1 ? asRegister(searchValue2) : null, + nValues > 2 ? asRegister(searchValue3) : null, + nValues > 3 ? asRegister(searchValue4) : null, + }; + Register[] vecCmp = { + nValues > 0 ? asRegister(vectorCompareVal1) : null, + nValues > 1 ? asRegister(vectorCompareVal2) : null, + nValues > 2 ? asRegister(vectorCompareVal3) : null, + nValues > 3 ? asRegister(vectorCompareVal4) : null, + }; + Register[] vecArray = { + asRegister(vectorArray1), + asRegister(vectorArray2), + asRegister(vectorArray3), + asRegister(vectorArray4), + }; + Register[] cmpResult = { + asRegister(comparisonResult1), + asRegister(comparisonResult2), + asRegister(comparisonResult3), + asRegister(comparisonResult4), + }; Label retFound = new Label(); Label retNotFound = new Label(); Label end = new Label(); - AVXKind.AVXSize vectorSize = asm.supports(CPUFeature.AVX2) ? AVXKind.AVXSize.YMM : AVXKind.AVXSize.XMM; - int nVectors = 4; - int bytesPerVector = vectorSize.getBytes(); - int arraySlotsPerVector = vectorSize.getBytes() / kind.getByteCount(); - int bulkSize = arraySlotsPerVector * nVectors; - int bulkSizeBytes = bytesPerVector * nVectors; - assert bulkSizeBytes >= 64; + AVXKind.AVXSize vectorSize = AVXKind.getDataSize(vectorKind); + int nVectors = nValues == 1 ? 4 : nValues == 2 ? 2 : 1; // load array length - // important: this must be the first register manipulation, since charArrayLengthValue is + // important: this must be the first register manipulation, since arrayLengthValue is // annotated with @Use asm.movl(slotsRemaining, arrayLength); - // move search value to vector - if (asm.supports(CPUFeature.AVX)) { - VexMoveOp.VMOVD.emit(asm, AVXKind.AVXSize.DWORD, vecCmp, searchValue); - } else { - asm.movdl(vecCmp, searchValue); - } // load array pointer asm.movq(result, arrayPtr); - // load copy of low part of array pointer - asm.movl(cmpResult1, arrayPtr); + // move search values to vectors + for (int i = 0; i < nValues; i++) { + if (asm.supports(CPUFeature.AVX)) { + VexMoveOp.VMOVD.emit(asm, AVXKind.AVXSize.DWORD, vecCmp[i], searchValue[i]); + } else { + asm.movdl(vecCmp[i], searchValue[i]); + } + } // fill comparison vector with copies of the search value - emitBroadcast(asm, vecCmp, vecArray1, vectorSize); + for (int i = 0; i < nValues; i++) { + emitBroadcast(asm, findTwoConsecutive ? (byteMode(kind) ? JavaKind.Char : JavaKind.Int) : kind, vecCmp[i], vecArray[0], vectorSize); + } + + emitArrayIndexOfChars(crb, asm, kind, vectorSize, result, slotsRemaining, searchValue, vecCmp, vecArray, cmpResult, retFound, retNotFound, vmPageSize, nValues, nVectors, findTwoConsecutive); + + // return -1 (no match) + asm.bind(retNotFound); + asm.movq(result, -1); + asm.jmpb(end); + + asm.bind(retFound); + // convert array pointer to offset + asm.subq(result, arrayPtr); + if (charMode(kind)) { + asm.shrq(result, 1); + } + asm.bind(end); + } + + private static void emitArrayIndexOfChars(CompilationResultBuilder crb, AMD64MacroAssembler asm, JavaKind kind, AVXKind.AVXSize vectorSize, + Register arrayPtr, + Register slotsRemaining, + Register[] searchValue, + Register[] vecCmp, + Register[] vecArray, + Register[] cmpResult, + Label retFound, + Label retNotFound, + int vmPageSize, + int nValues, + int nVectors, + boolean findTwoCharPrefix) { + Label bulkVectorLoop = new Label(); + Label singleVectorLoop = new Label(); + Label[] vectorFound = { + new Label(), + new Label(), + new Label(), + new Label(), + }; + Label lessThanVectorSizeRemaining = new Label(); + Label lessThanVectorSizeRemainingLoop = new Label(); + Label bulkVectorLoopExit = nVectors == 1 ? lessThanVectorSizeRemaining : singleVectorLoop; + int bytesPerVector = vectorSize.getBytes(); + int arraySlotsPerVector = vectorSize.getBytes() / kind.getByteCount(); + int singleVectorLoopCondition = arraySlotsPerVector; + int bulkSize = arraySlotsPerVector * nVectors; + int bulkSizeBytes = bytesPerVector * nVectors; + int bulkLoopCondition = bulkSize; + int[] vectorOffsets; + JavaKind vectorCompareKind = kind; + if (findTwoCharPrefix) { + singleVectorLoopCondition++; + bulkLoopCondition++; + bulkSize /= 2; + bulkSizeBytes /= 2; + vectorOffsets = new int[]{0, kind.getByteCount(), bytesPerVector, bytesPerVector + kind.getByteCount()}; + vectorCompareKind = byteMode(kind) ? JavaKind.Char : JavaKind.Int; + } else { + vectorOffsets = new int[]{0, bytesPerVector, bytesPerVector * 2, bytesPerVector * 3}; + } + + // load copy of low part of array pointer + Register tmpArrayPtrLow = cmpResult[0]; + asm.movl(tmpArrayPtrLow, arrayPtr); // check if bulk vector load is in bounds - asm.cmpl(slotsRemaining, bulkSize); - asm.jcc(AMD64Assembler.ConditionFlag.Below, singleVectorLoop); + asm.cmpl(slotsRemaining, bulkLoopCondition); + asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit); - // check if array pointer is 64-byte aligned - asm.andl(cmpResult1, 63); + // check if array pointer is aligned to bulkSize + asm.andl(tmpArrayPtrLow, bulkSizeBytes - 1); asm.jcc(AMD64Assembler.ConditionFlag.Zero, bulkVectorLoop); // do one unaligned bulk comparison pass and adjust alignment afterwards - emitBulkCompare(asm, vectorSize, bytesPerVector, result, vecCmp, vecArray1, vecArray2, vecArray3, vecArray4, cmpResult1, cmpResult2, cmpResult3, cmpResult4, - vectorFound1, vectorFound2, vectorFound3, vectorFound4, false); + emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false); // load copy of low part of array pointer - asm.movl(cmpResult1, arrayPtr); + asm.movl(tmpArrayPtrLow, arrayPtr); // adjust array pointer - asm.addq(result, bulkSizeBytes); + asm.addq(arrayPtr, bulkSizeBytes); // adjust number of array slots remaining asm.subl(slotsRemaining, bulkSize); - // get offset to 64-byte alignment - asm.andl(cmpResult1, 63); - emitBytesToArraySlots(asm, cmpResult1); - // adjust array pointer to 64-byte alignment - asm.andq(result, ~63); + // get offset to bulk size alignment + asm.andl(tmpArrayPtrLow, bulkSizeBytes - 1); + emitBytesToArraySlots(asm, kind, tmpArrayPtrLow); + // adjust array pointer to bulk size alignment + asm.andq(arrayPtr, ~(bulkSizeBytes - 1)); // adjust number of array slots remaining - asm.addl(slotsRemaining, cmpResult1); + asm.addl(slotsRemaining, tmpArrayPtrLow); // check if there are enough array slots remaining for the bulk loop - asm.cmpl(slotsRemaining, bulkSize); - asm.jcc(AMD64Assembler.ConditionFlag.Below, singleVectorLoop); + asm.cmpl(slotsRemaining, bulkLoopCondition); + asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit); emitAlign(crb, asm); asm.bind(bulkVectorLoop); // memory-aligned bulk comparison - emitBulkCompare(asm, vectorSize, bytesPerVector, result, vecCmp, vecArray1, vecArray2, vecArray3, vecArray4, cmpResult1, cmpResult2, cmpResult3, cmpResult4, - vectorFound1, vectorFound2, vectorFound3, vectorFound4, true); + emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, nVectors, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, !findTwoCharPrefix); // adjust number of array slots remaining asm.subl(slotsRemaining, bulkSize); // adjust array pointer - asm.addq(result, bulkSizeBytes); + asm.addq(arrayPtr, bulkSizeBytes); // check if there are enough array slots remaining for the bulk loop - asm.cmpl(slotsRemaining, bulkSize); - asm.jcc(AMD64Assembler.ConditionFlag.Below, singleVectorLoop); + asm.cmpl(slotsRemaining, bulkLoopCondition); + asm.jcc(AMD64Assembler.ConditionFlag.Below, bulkVectorLoopExit); // continue loop - asm.jmpb(bulkVectorLoop); + asm.jmp(bulkVectorLoop); - emitAlign(crb, asm); - // same loop as bulkVectorLoop, with only one vector - asm.bind(singleVectorLoop); - // check if single vector load is in bounds - asm.cmpl(slotsRemaining, arraySlotsPerVector); - asm.jcc(AMD64Assembler.ConditionFlag.Below, lessThanVectorSizeRemaining); - // compare - emitSingleVectorCompare(asm, vectorSize, result, vecCmp, vecArray1, cmpResult1); - - // check if a match was found - asm.testl(cmpResult1, cmpResult1); - asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound1); - // adjust number of array slots remaining - asm.subl(slotsRemaining, arraySlotsPerVector); - // adjust array pointer - asm.addq(result, bytesPerVector); - // continue loop - asm.jmpb(singleVectorLoop); + if (nVectors > 1) { + emitAlign(crb, asm); + // same loop as bulkVectorLoop, with only one vector + asm.bind(singleVectorLoop); + // check if single vector load is in bounds + asm.cmpl(slotsRemaining, singleVectorLoopCondition); + asm.jcc(AMD64Assembler.ConditionFlag.Below, lessThanVectorSizeRemaining); + // compare + emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoCharPrefix ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, vectorFound, false); + // adjust number of array slots remaining + asm.subl(slotsRemaining, arraySlotsPerVector); + // adjust array pointer + asm.addq(arrayPtr, bytesPerVector); + // continue loop + asm.jmpb(singleVectorLoop); + } asm.bind(lessThanVectorSizeRemaining); // check if any array slots remain @@ -236,75 +310,133 @@ public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction { // a vector compare will read out of bounds of the input array. // check if the out-of-bounds read would cross a memory page boundary. // load copy of low part of array pointer - asm.movl(cmpResult1, result); + asm.movl(tmpArrayPtrLow, arrayPtr); // check if pointer + vector size would cross the page boundary - asm.andl(cmpResult1, (vmPageSize - 1)); - asm.cmpl(cmpResult1, (vmPageSize - bytesPerVector)); + asm.andl(tmpArrayPtrLow, (vmPageSize - 1)); + asm.cmpl(tmpArrayPtrLow, (vmPageSize - (findTwoCharPrefix ? bytesPerVector + kind.getByteCount() : bytesPerVector))); // if the page boundary would be crossed, do byte/character-wise comparison instead. asm.jccb(AMD64Assembler.ConditionFlag.Above, lessThanVectorSizeRemainingLoop); + + Label[] overBoundsMatch = {new Label(), new Label()}; // otherwise, do a vector compare that reads beyond array bounds - emitSingleVectorCompare(asm, vectorSize, result, vecCmp, vecArray1, cmpResult1); - // check if a match was found - asm.testl(cmpResult1, cmpResult1); - asm.jcc(AMD64Assembler.ConditionFlag.Zero, retNotFound); - // find match offset - asm.bsfq(cmpResult1, cmpResult1); - if (charMode()) { - // convert number of remaining characters to bytes - asm.shll(slotsRemaining, 1); + emitVectorCompare(asm, vectorCompareKind, vectorSize, nValues, findTwoCharPrefix ? 2 : 1, vectorOffsets, arrayPtr, vecCmp, vecArray, cmpResult, overBoundsMatch, false); + // no match + asm.jmp(retNotFound); + if (findTwoCharPrefix) { + Label overBoundsFinish = new Label(); + asm.bind(overBoundsMatch[1]); + // get match offset of second result + asm.bsfq(cmpResult[1], cmpResult[1]); + asm.addl(cmpResult[1], kind.getByteCount()); + // replace first result with second and continue + asm.movl(cmpResult[0], cmpResult[1]); + asm.jmpb(overBoundsFinish); + + asm.bind(overBoundsMatch[0]); + emitFindTwoCharPrefixMinResult(asm, kind, cmpResult, overBoundsFinish); + } else { + asm.bind(overBoundsMatch[0]); + // find match offset + asm.bsfq(cmpResult[0], cmpResult[0]); } + // adjust array pointer for match result - asm.addq(result, cmpResult1); + asm.addq(arrayPtr, cmpResult[0]); + if (charMode(kind)) { + // convert byte offset to chars + asm.shrl(cmpResult[0], 1); + } // check if offset of matched value is greater than number of bytes remaining / out of array // bounds - asm.cmpl(cmpResult1, slotsRemaining); + if (findTwoCharPrefix) { + asm.decrementl(slotsRemaining); + } + asm.cmpl(cmpResult[0], slotsRemaining); // match is out of bounds, return no match asm.jcc(AMD64Assembler.ConditionFlag.GreaterEqual, retNotFound); + // adjust number of array slots remaining + if (findTwoCharPrefix) { + asm.incrementl(slotsRemaining, 1); + } + asm.subl(slotsRemaining, cmpResult[0]); // match is in bounds, return offset - asm.jmpb(retFound); + asm.jmp(retFound); // compare remaining slots in the array one-by-one asm.bind(lessThanVectorSizeRemainingLoop); - // check if any array slots remain - asm.testl(slotsRemaining, slotsRemaining); - asm.jcc(AMD64Assembler.ConditionFlag.Zero, retNotFound); + // check if enough array slots remain + asm.cmpl(slotsRemaining, findTwoCharPrefix ? 1 : 0); + asm.jcc(AMD64Assembler.ConditionFlag.LessEqual, retNotFound); // load char / byte - AMD64Assembler.OperandSize operandSize = byteMode() ? AMD64Assembler.OperandSize.BYTE : AMD64Assembler.OperandSize.WORD; - if (byteMode()) { - AMD64Assembler.AMD64RMOp.MOVB.emit(asm, operandSize, cmpResult1, new AMD64Address(result)); + if (byteMode(kind)) { + if (findTwoCharPrefix) { + asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr)); + } else { + asm.movzbl(cmpResult[0], new AMD64Address(arrayPtr)); + } } else { - AMD64Assembler.AMD64RMOp.MOV.emit(asm, operandSize, cmpResult1, new AMD64Address(result)); + if (findTwoCharPrefix) { + asm.movl(cmpResult[0], new AMD64Address(arrayPtr)); + } else { + asm.movzwl(cmpResult[0], new AMD64Address(arrayPtr)); + } } // check for match - AMD64Assembler.AMD64BinaryArithmetic.CMP.getRMOpcode(operandSize).emit(asm, operandSize, cmpResult1, searchValue); - asm.jcc(AMD64Assembler.ConditionFlag.Equal, retFound); + for (int i = 0; i < nValues; i++) { + asm.cmpl(cmpResult[0], searchValue[i]); + asm.jcc(AMD64Assembler.ConditionFlag.Equal, retFound); + } // adjust number of array slots remaining asm.decrementl(slotsRemaining); // adjust array pointer - asm.addq(result, kind.getByteCount()); + asm.addq(arrayPtr, kind.getByteCount()); // continue loop asm.jmpb(lessThanVectorSizeRemainingLoop); - // return -1 (no match) - asm.bind(retNotFound); - asm.movl(result, -1); - asm.jmpb(end); + for (int i = 1; i < nVectors; i += (findTwoCharPrefix ? 2 : 1)) { + emitVectorFoundWithOffset(asm, kind, vectorOffsets[i], arrayPtr, cmpResult[i], slotsRemaining, vectorFound[i], retFound); + } - emitVectorFoundWithOffset(asm, bytesPerVector, result, cmpResult2, vectorFound2, retFound); - emitVectorFoundWithOffset(asm, bytesPerVector * 2, result, cmpResult3, vectorFound3, retFound); - emitVectorFoundWithOffset(asm, bytesPerVector * 3, result, cmpResult4, vectorFound4, retFound); - - asm.bind(vectorFound1); - // find index of first set bit in bit mask - asm.bsfq(cmpResult1, cmpResult1); + if (findTwoCharPrefix) { + asm.bind(vectorFound[2]); + asm.addq(arrayPtr, vectorOffsets[2]); + // adjust number of array slots remaining + asm.subl(slotsRemaining, charMode(kind) ? vectorOffsets[2] / 2 : vectorOffsets[2]); + asm.movl(cmpResult[0], cmpResult[2]); + asm.movl(cmpResult[1], cmpResult[3]); + asm.bind(vectorFound[0]); + emitFindTwoCharPrefixMinResult(asm, kind, cmpResult, new Label()); + } else { + asm.bind(vectorFound[0]); + // find index of first set bit in bit mask + asm.bsfq(cmpResult[0], cmpResult[0]); + } // add offset to array pointer - asm.addq(result, cmpResult1); + asm.addq(arrayPtr, cmpResult[0]); + if (charMode(kind)) { + // convert byte offset to chars + asm.shrl(cmpResult[0], 1); + } + // adjust number of array slots remaining + asm.subl(slotsRemaining, cmpResult[0]); + asm.jmpb(retFound); + } - asm.bind(retFound); - // convert array pointer to offset - asm.subq(result, arrayPtr); - emitBytesToArraySlots(asm, result); - asm.bind(end); + private static void emitFindTwoCharPrefixMinResult(AMD64MacroAssembler asm, JavaKind kind, Register[] cmpResult, Label done) { + // find match offset + asm.bsfq(cmpResult[0], cmpResult[0]); + // check if second result is also a match + asm.testl(cmpResult[1], cmpResult[1]); + asm.jcc(AMD64Assembler.ConditionFlag.Zero, done); + // get match offset of second result + asm.bsfq(cmpResult[1], cmpResult[1]); + asm.addl(cmpResult[1], kind.getByteCount()); + // check if first result is less than second + asm.cmpl(cmpResult[0], cmpResult[1]); + asm.jcc(AMD64Assembler.ConditionFlag.LessEqual, done); + // first result is greater than second, replace it with the second result + asm.movl(cmpResult[0], cmpResult[1]); + asm.bind(done); } private static void emitAlign(CompilationResultBuilder crb, AMD64MacroAssembler asm) { @@ -312,126 +444,132 @@ public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction { } /** - * Fills {@code vecDst} with copies of its lowest byte or word. + * Fills {@code vecDst} with copies of its lowest byte, word or dword. */ - private void emitBroadcast(AMD64MacroAssembler asm, Register vecDst, Register vecTmp, AVXKind.AVXSize vectorSize) { - if (asm.supports(CPUFeature.AVX2)) { - if (byteMode()) { - VexRMOp.VPBROADCASTB.emit(asm, vectorSize, vecDst, vecDst); - } else { - VexRMOp.VPBROADCASTW.emit(asm, vectorSize, vecDst, vecDst); - } - } else if (asm.supports(CPUFeature.AVX)) { - if (byteMode()) { - // fill vecTmp with zeroes - VexRVMOp.VPXOR.emit(asm, vectorSize, vecTmp, vecTmp, vecTmp); - // broadcast loaded search value - VexRVMOp.VPSHUFB.emit(asm, vectorSize, vecDst, vecDst, vecTmp); - } else { - // fill low qword - VexRMIOp.VPSHUFLW.emit(asm, vectorSize, vecDst, vecDst, 0); - // copy low qword to high qword - VexRMIOp.VPSHUFD.emit(asm, vectorSize, vecDst, vecDst, 0); - } - } else { - // SSE version - if (byteMode()) { - // fill vecTmp with zeroes - asm.pxor(vecTmp, vecTmp); - // broadcast loaded search value - asm.pshufb(vecDst, vecTmp); - } else { - // fill low qword - asm.pshuflw(vecDst, vecDst, 0); - // copy low qword to high qword - asm.pshufd(vecDst, vecDst, 0); - } + private static void emitBroadcast(AMD64MacroAssembler asm, JavaKind kind, Register vecDst, Register vecTmp, AVXKind.AVXSize vectorSize) { + switch (kind) { + case Byte: + if (asm.supports(CPUFeature.AVX2)) { + VexRMOp.VPBROADCASTB.emit(asm, vectorSize, vecDst, vecDst); + } else if (asm.supports(CPUFeature.AVX)) { + VexRVMOp.VPXOR.emit(asm, vectorSize, vecTmp, vecTmp, vecTmp); + VexRVMOp.VPSHUFB.emit(asm, vectorSize, vecDst, vecDst, vecTmp); + } else if (asm.supports(CPUFeature.SSSE3)) { + asm.pxor(vecTmp, vecTmp); + asm.pshufb(vecDst, vecTmp); + } else { // SSE2 + asm.punpcklbw(vecDst, vecDst); + asm.punpcklbw(vecDst, vecDst); + asm.pshufd(vecDst, vecDst, 0); + } + break; + case Short: + case Char: + if (asm.supports(CPUFeature.AVX2)) { + VexRMOp.VPBROADCASTW.emit(asm, vectorSize, vecDst, vecDst); + } else if (asm.supports(CPUFeature.AVX)) { + VexRMIOp.VPSHUFLW.emit(asm, vectorSize, vecDst, vecDst, 0); + VexRMIOp.VPSHUFD.emit(asm, vectorSize, vecDst, vecDst, 0); + } else { // SSE + asm.pshuflw(vecDst, vecDst, 0); + asm.pshufd(vecDst, vecDst, 0); + } + break; + case Int: + if (asm.supports(CPUFeature.AVX2)) { + VexRMOp.VPBROADCASTD.emit(asm, vectorSize, vecDst, vecDst); + } else if (asm.supports(CPUFeature.AVX)) { + VexRMIOp.VPSHUFD.emit(asm, vectorSize, vecDst, vecDst, 0); + } else { // SSE + asm.pshufd(vecDst, vecDst, 0); + } + break; + default: + throw new UnsupportedOperationException(); } } - /** - * Loads {@code vectorSize} bytes from the position pointed to by {@code arrayPtr} and compares - * them to the search value stored in {@code vecCmp}. {@code vecArray} is overwritten by this - * operation. The comparison result is stored in {@code cmpResult}. - */ - private void emitSingleVectorCompare(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, - Register arrayPtr, Register vecCmp, Register vecArray, Register cmpResult) { - // load array contents into vector - emitArrayLoad(asm, vectorSize, vecArray, arrayPtr, 0, false); - // compare all loaded bytes to the search value. - emitVectorCompare(asm, vectorSize, vecArray, vecCmp); - // create a 32-bit-mask from the most significant bit of every byte in the comparison - // result. - emitMOVMSK(asm, vectorSize, cmpResult, vecArray); - } - /** * Convert a byte offset stored in {@code bytes} to an array index offset. */ - private void emitBytesToArraySlots(AMD64MacroAssembler asm, Register bytes) { - if (charMode()) { + private static void emitBytesToArraySlots(AMD64MacroAssembler asm, JavaKind kind, Register bytes) { + if (charMode(kind)) { asm.shrl(bytes, 1); } else { - assert byteMode(); + assert byteMode(kind); } } - private void emitBulkCompare(AMD64MacroAssembler asm, + private static void emitVectorCompare(AMD64MacroAssembler asm, + JavaKind kind, AVXKind.AVXSize vectorSize, - int bytesPerVector, + int nValues, + int nVectors, + int[] vectorOffsets, Register arrayPtr, - Register vecCmp, - Register vecArray1, - Register vecArray2, - Register vecArray3, - Register vecArray4, - Register cmpResult1, - Register cmpResult2, - Register cmpResult3, - Register cmpResult4, - Label vectorFound1, - Label vectorFound2, - Label vectorFound3, - Label vectorFound4, + Register[] vecCmp, + Register[] vecArray, + Register[] cmpResult, + Label[] vectorFound, boolean alignedLoad) { // load array contents into vectors - emitArrayLoad(asm, vectorSize, vecArray1, arrayPtr, 0, alignedLoad); - emitArrayLoad(asm, vectorSize, vecArray2, arrayPtr, bytesPerVector, alignedLoad); - emitArrayLoad(asm, vectorSize, vecArray3, arrayPtr, bytesPerVector * 2, alignedLoad); - emitArrayLoad(asm, vectorSize, vecArray4, arrayPtr, bytesPerVector * 3, alignedLoad); + for (int i = 0; i < nValues; i++) { + for (int j = 0; j < nVectors; j++) { + emitArrayLoad(asm, vectorSize, vecArray[(i * nVectors) + j], arrayPtr, vectorOffsets[j], alignedLoad); + } + } // compare all loaded bytes to the search value. // matching bytes are set to 0xff, non-matching bytes are set to 0x00. - emitVectorCompare(asm, vectorSize, vecArray1, vecCmp); - emitVectorCompare(asm, vectorSize, vecArray2, vecCmp); - emitVectorCompare(asm, vectorSize, vecArray3, vecCmp); - emitVectorCompare(asm, vectorSize, vecArray4, vecCmp); + for (int i = 0; i < nValues; i++) { + for (int j = 0; j < nVectors; j++) { + emitVectorCompareInst(asm, kind, vectorSize, vecArray[(i * nVectors) + j], vecCmp[i]); + } + } // create 32-bit-masks from the most significant bit of every byte in the comparison // results. - emitMOVMSK(asm, vectorSize, cmpResult1, vecArray1); - emitMOVMSK(asm, vectorSize, cmpResult2, vecArray2); - emitMOVMSK(asm, vectorSize, cmpResult3, vecArray3); - emitMOVMSK(asm, vectorSize, cmpResult4, vecArray4); + for (int i = 0; i < nValues * nVectors; i++) { + emitMOVMSK(asm, vectorSize, cmpResult[i], vecArray[i]); + } + // join results of comparisons against multiple values + for (int stride = 1; stride < nValues; stride *= 2) { + for (int i = 0; i < nVectors; i++) { + for (int j = 0; j + stride < nValues; j += stride * 2) { + asm.orl(cmpResult[i + (j * nVectors)], cmpResult[i + ((j + stride) * nVectors)]); + } + } + } // check if a match was found - asm.testl(cmpResult1, cmpResult1); - asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound1); - asm.testl(cmpResult2, cmpResult2); - asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound2); - asm.testl(cmpResult3, cmpResult3); - asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound3); - asm.testl(cmpResult4, cmpResult4); - asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound4); + for (int i = 0; i < nVectors; i++) { + asm.testl(cmpResult[i], cmpResult[i]); + asm.jcc(AMD64Assembler.ConditionFlag.NotZero, vectorFound[i]); + } } - private static void emitVectorFoundWithOffset(AMD64MacroAssembler asm, int resultOffset, Register result, Register cmpResult, Label entry, Label ret) { + private static void emitVectorFoundWithOffset(AMD64MacroAssembler asm, + JavaKind kind, + int resultOffset, + Register result, + Register cmpResult, + Register slotsRemaining, + Label entry, + Label ret) { asm.bind(entry); if (resultOffset > 0) { // adjust array pointer asm.addq(result, resultOffset); + // adjust number of array slots remaining + asm.subl(slotsRemaining, charMode(kind) ? resultOffset / 2 : resultOffset); } // find index of first set bit in bit mask asm.bsfq(cmpResult, cmpResult); // add offset to array pointer asm.addq(result, cmpResult); + if (charMode(kind)) { + // convert byte offset to chars + asm.shrl(cmpResult, 1); + } + // adjust number of array slots remaining + asm.subl(slotsRemaining, cmpResult); asm.jmpb(ret); } @@ -446,22 +584,36 @@ public final class AMD64ArrayIndexOfOp extends AMD64LIRInstruction { } } - private void emitVectorCompare(AMD64MacroAssembler asm, AVXKind.AVXSize vectorSize, Register vecArray, Register vecCmp) { - // compare all loaded bytes to the search value. - // matching bytes are set to 0xff, non-matching bytes are set to 0x00. - if (asm.supports(CPUFeature.AVX)) { - if (byteMode()) { - VexRVMOp.VPCMPEQB.emit(asm, vectorSize, vecArray, vecCmp, vecArray); - } else { - VexRVMOp.VPCMPEQW.emit(asm, vectorSize, vecArray, vecCmp, vecArray); - } - } else { - // SSE - if (byteMode()) { - asm.pcmpeqb(vecArray, vecCmp); - } else { - asm.pcmpeqw(vecArray, vecCmp); - } + /** + * Compares all packed bytes/words/dwords in {@code vecArray} to {@code vecCmp}. Matching values + * are set to all ones (0xff, 0xffff, ...), non-matching values are set to zero. + */ + private static void emitVectorCompareInst(AMD64MacroAssembler asm, JavaKind kind, AVXKind.AVXSize vectorSize, Register vecArray, Register vecCmp) { + switch (kind) { + case Byte: + if (asm.supports(CPUFeature.AVX)) { + VexRVMOp.VPCMPEQB.emit(asm, vectorSize, vecArray, vecCmp, vecArray); + } else { // SSE + asm.pcmpeqb(vecArray, vecCmp); + } + break; + case Short: + case Char: + if (asm.supports(CPUFeature.AVX)) { + VexRVMOp.VPCMPEQW.emit(asm, vectorSize, vecArray, vecCmp, vecArray); + } else { // SSE + asm.pcmpeqw(vecArray, vecCmp); + } + break; + case Int: + if (asm.supports(CPUFeature.AVX)) { + VexRVMOp.VPCMPEQD.emit(asm, vectorSize, vecArray, vecCmp, vecArray); + } else { // SSE + asm.pcmpeqd(vecArray, vecCmp); + } + break; + default: + throw new UnsupportedOperationException(); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java index 5e1420b163..2456d3035c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64FrameMap.java @@ -81,25 +81,31 @@ public class AMD64FrameMap extends FrameMap { private StackSlot rbpSpillSlot; public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory) { + this(codeCache, registerConfig, referenceMapFactory, false); + } + + public AMD64FrameMap(CodeCacheProvider codeCache, RegisterConfig registerConfig, ReferenceMapBuilderFactory referenceMapFactory, boolean useBasePointer) { super(codeCache, registerConfig, referenceMapFactory); // (negative) offset relative to sp + total frame size - initialSpillSize = returnAddressSize(); + initialSpillSize = returnAddressSize() + (useBasePointer ? getTarget().arch.getWordSize() : 0); spillSize = initialSpillSize; } @Override public int totalFrameSize() { - return frameSize() + returnAddressSize(); + int result = frameSize() + initialSpillSize; + assert result % getTarget().stackAlignment == 0 : "Total frame size not aligned: " + result; + return result; } @Override public int currentFrameSize() { - return alignFrameSize(outgoingSize + spillSize - returnAddressSize()); + return alignFrameSize(outgoingSize + spillSize - initialSpillSize); } @Override protected int alignFrameSize(int size) { - return NumUtil.roundUp(size + returnAddressSize(), getTarget().stackAlignment) - returnAddressSize(); + return NumUtil.roundUp(size + initialSpillSize, getTarget().stackAlignment) - initialSpillSize; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringIndexOfOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringIndexOfOp.java deleted file mode 100644 index 5715a3a865..0000000000 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringIndexOfOp.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.graalvm.compiler.lir.amd64; - -import static jdk.vm.ci.amd64.AMD64.rax; -import static jdk.vm.ci.amd64.AMD64.rcx; -import static jdk.vm.ci.amd64.AMD64.rdx; -import static jdk.vm.ci.amd64.AMD64.rsp; -import static jdk.vm.ci.code.ValueUtil.asRegister; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL; -import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; - -import org.graalvm.compiler.asm.Label; -import org.graalvm.compiler.asm.amd64.AMD64Address; -import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; -import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag; -import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; -import org.graalvm.compiler.lir.LIRInstructionClass; -import org.graalvm.compiler.lir.Opcode; -import org.graalvm.compiler.lir.asm.CompilationResultBuilder; -import org.graalvm.compiler.lir.gen.LIRGeneratorTool; - -import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.amd64.AMD64.CPUFeature; -import jdk.vm.ci.code.Register; -import jdk.vm.ci.code.RegisterValue; -import jdk.vm.ci.meta.Value; - -/** - */ -@Opcode("AMD64_STRING_INDEX_OF") -public final class AMD64StringIndexOfOp extends AMD64LIRInstruction { - public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64StringIndexOfOp.class); - - @Def({REG}) protected Value resultValue; - @Alive({REG}) protected Value charPtr1Value; - @Alive({REG}) protected Value charPtr2Value; - @Use({REG}) protected RegisterValue cnt1Value; - @Temp({REG}) protected RegisterValue cnt1ValueT; - @Use({REG}) protected RegisterValue cnt2Value; - @Temp({REG}) protected RegisterValue cnt2ValueT; - @Temp({REG}) protected Value temp1; - @Temp({REG, ILLEGAL}) protected Value vectorTemp1; - - private final int intCnt2; - - private final int vmPageSize; - - public AMD64StringIndexOfOp(LIRGeneratorTool tool, Value result, Value charPtr1, Value charPtr2, RegisterValue cnt1, RegisterValue cnt2, RegisterValue temp1, RegisterValue vectorTemp1, - int intCnt2, int vmPageSize) { - super(TYPE); - assert ((AMD64) tool.target().arch).getFeatures().contains(CPUFeature.SSE4_2); - resultValue = result; - charPtr1Value = charPtr1; - charPtr2Value = charPtr2; - /* - * The count values are inputs but are also killed like temporaries so need both Use and - * Temp annotations, which will only work with fixed registers. - */ - cnt1Value = cnt1; - cnt1ValueT = cnt1; - cnt2Value = cnt2; - cnt2ValueT = cnt2; - assert asRegister(cnt1).equals(rdx) && asRegister(cnt2).equals(rax) && asRegister(temp1).equals(rcx) : "fixed register usage required"; - - this.temp1 = temp1; - this.vectorTemp1 = vectorTemp1; - this.intCnt2 = intCnt2; - this.vmPageSize = vmPageSize; - } - - @Override - public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { - Register charPtr1 = asRegister(charPtr1Value); - Register charPtr2 = asRegister(charPtr2Value); - Register cnt1 = asRegister(cnt1Value); - Register cnt2 = asRegister(cnt2Value); - Register result = asRegister(resultValue); - Register vec = asRegister(vectorTemp1); - Register tmp = asRegister(temp1); - if (intCnt2 >= 8) { - // IndexOf for constant substrings with size >= 8 chars which don't need to be loaded - // through stack. - stringIndexofC8(masm, charPtr1, charPtr2, cnt1, cnt2, result, vec, tmp); - } else { - // Small strings are loaded through stack if they cross page boundary. - stringIndexOf(masm, charPtr1, charPtr2, cnt1, cnt2, result, vec, tmp); - } - } - - private void stringIndexofC8(AMD64MacroAssembler masm, Register charPtr1, Register charPtr2, Register cnt1, Register cnt2, Register result, Register vec, Register tmp) { - // assert(UseSSE42Intrinsics, "SSE4.2 is required"); - - // This method uses pcmpestri inxtruction with bound registers - // inputs: - // xmm - substring - // rax - substring length (elements count) - // mem - scanned string - // rdx - string length (elements count) - // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) - // outputs: - // rcx - matched index in string - assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri"; - - Label reloadSubstr = new Label(); - Label scanToSubstr = new Label(); - Label scanSubstr = new Label(); - Label retFound = new Label(); - Label retNotFound = new Label(); - Label exit = new Label(); - Label foundSubstr = new Label(); - Label matchSubstrHead = new Label(); - Label reloadStr = new Label(); - Label foundCandidate = new Label(); - - // Note, inline_string_indexOf() generates checks: - // if (substr.count > string.count) return -1; - // if (substr.count == 0) return 0; - assert intCnt2 >= 8 : "this code isused only for cnt2 >= 8 chars"; - - // Load substring. - masm.movdqu(vec, new AMD64Address(charPtr2, 0)); - masm.movl(cnt2, intCnt2); - masm.movq(result, charPtr1); // string addr - - if (intCnt2 > 8) { - masm.jmpb(scanToSubstr); - - // Reload substr for rescan, this code - // is executed only for large substrings (> 8 chars) - masm.bind(reloadSubstr); - masm.movdqu(vec, new AMD64Address(charPtr2, 0)); - masm.negq(cnt2); // Jumped here with negative cnt2, convert to positive - - masm.bind(reloadStr); - // We came here after the beginning of the substring was - // matched but the rest of it was not so we need to search - // again. Start from the next element after the previous match. - - // cnt2 is number of substring reminding elements and - // cnt1 is number of string reminding elements when cmp failed. - // Restored cnt1 = cnt1 - cnt2 + int_cnt2 - masm.subl(cnt1, cnt2); - masm.addl(cnt1, intCnt2); - masm.movl(cnt2, intCnt2); // Now restore cnt2 - - masm.decrementl(cnt1, 1); // Shift to next element - masm.cmpl(cnt1, cnt2); - masm.jccb(ConditionFlag.Negative, retNotFound); // Left less then substring - - masm.addq(result, 2); - - } // (int_cnt2 > 8) - - // Scan string for start of substr in 16-byte vectors - masm.bind(scanToSubstr); - masm.pcmpestri(vec, new AMD64Address(result, 0), 0x0d); - masm.jccb(ConditionFlag.Below, foundCandidate); // CF == 1 - masm.subl(cnt1, 8); - masm.jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string - masm.cmpl(cnt1, cnt2); - masm.jccb(ConditionFlag.Negative, retNotFound); // Left less then substring - masm.addq(result, 16); - masm.jmpb(scanToSubstr); - - // Found a potential substr - masm.bind(foundCandidate); - // Matched whole vector if first element matched (tmp(rcx) == 0). - if (intCnt2 == 8) { - masm.jccb(ConditionFlag.Overflow, retFound); // OF == 1 - } else { // int_cnt2 > 8 - masm.jccb(ConditionFlag.Overflow, foundSubstr); - } - // After pcmpestri tmp(rcx) contains matched element index - // Compute start addr of substr - masm.leaq(result, new AMD64Address(result, tmp, Scale.Times2, 0)); - - // Make sure string is still long enough - masm.subl(cnt1, tmp); - masm.cmpl(cnt1, cnt2); - if (intCnt2 == 8) { - masm.jccb(ConditionFlag.GreaterEqual, scanToSubstr); - } else { // int_cnt2 > 8 - masm.jccb(ConditionFlag.GreaterEqual, matchSubstrHead); - } - // Left less then substring. - - masm.bind(retNotFound); - masm.movl(result, -1); - masm.jmpb(exit); - - if (intCnt2 > 8) { - // This code is optimized for the case when whole substring - // is matched if its head is matched. - masm.bind(matchSubstrHead); - masm.pcmpestri(vec, new AMD64Address(result, 0), 0x0d); - // Reload only string if does not match - masm.jccb(ConditionFlag.NoOverflow, reloadStr); // OF == 0 - - Label contScanSubstr = new Label(); - // Compare the rest of substring (> 8 chars). - masm.bind(foundSubstr); - // First 8 chars are already matched. - masm.negq(cnt2); - masm.addq(cnt2, 8); - - masm.bind(scanSubstr); - masm.subl(cnt1, 8); - masm.cmpl(cnt2, -8); // Do not read beyond substring - masm.jccb(ConditionFlag.LessEqual, contScanSubstr); - // Back-up strings to avoid reading beyond substring: - // cnt1 = cnt1 - cnt2 + 8 - masm.addl(cnt1, cnt2); // cnt2 is negative - masm.addl(cnt1, 8); - masm.movl(cnt2, 8); - masm.negq(cnt2); - masm.bind(contScanSubstr); - if (intCnt2 < 1024 * 1024 * 1024) { - masm.movdqu(vec, new AMD64Address(charPtr2, cnt2, Scale.Times2, intCnt2 * 2)); - masm.pcmpestri(vec, new AMD64Address(result, cnt2, Scale.Times2, intCnt2 * 2), 0x0d); - } else { - // calculate index in register to avoid integer overflow (int_cnt2*2) - masm.movl(tmp, intCnt2); - masm.addq(tmp, cnt2); - masm.movdqu(vec, new AMD64Address(charPtr2, tmp, Scale.Times2, 0)); - masm.pcmpestri(vec, new AMD64Address(result, tmp, Scale.Times2, 0), 0x0d); - } - // Need to reload strings pointers if not matched whole vector - masm.jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0 - masm.addq(cnt2, 8); - masm.jcc(ConditionFlag.Negative, scanSubstr); - // Fall through if found full substring - - } // (int_cnt2 > 8) - - masm.bind(retFound); - // Found result if we matched full small substring. - // Compute substr offset - masm.subq(result, charPtr1); - masm.shrl(result, 1); // index - masm.bind(exit); - } - - private void stringIndexOf(AMD64MacroAssembler masm, Register charPtr1, Register charPtr2, Register cnt1, Register cnt2, Register result, Register vec, Register tmp) { - // - // int_cnt2 is length of small (< 8 chars) constant substring - // or (-1) for non constant substring in which case its length - // is in cnt2 register. - // - // Note, inline_string_indexOf() generates checks: - // if (substr.count > string.count) return -1; - // if (substr.count == 0) return 0; - // - assert intCnt2 == -1 || (0 < intCnt2 && intCnt2 < 8) : "should be != 0"; - - // This method uses pcmpestri instruction with bound registers - // inputs: - // xmm - substring - // rax - substring length (elements count) - // mem - scanned string - // rdx - string length (elements count) - // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts) - // outputs: - // rcx - matched index in string - assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri"; - - Label reloadSubstr = new Label(); - Label scanToSubstr = new Label(); - Label scanSubstr = new Label(); - Label adjustStr = new Label(); - Label retFound = new Label(); - Label retNotFound = new Label(); - Label cleanup = new Label(); - Label foundSubstr = new Label(); - Label foundCandidate = new Label(); - - int wordSize = 8; - // We don't know where these strings are located - // and we can't read beyond them. Load them through stack. - Label bigStrings = new Label(); - Label checkStr = new Label(); - Label copySubstr = new Label(); - Label copyStr = new Label(); - - masm.movq(tmp, rsp); // save old SP - - if (intCnt2 > 0) { // small (< 8 chars) constant substring - if (intCnt2 == 1) { // One char - masm.movzwl(result, new AMD64Address(charPtr2, 0)); - masm.movdl(vec, result); // move 32 bits - } else if (intCnt2 == 2) { // Two chars - masm.movdl(vec, new AMD64Address(charPtr2, 0)); // move 32 bits - } else if (intCnt2 == 4) { // Four chars - masm.movq(vec, new AMD64Address(charPtr2, 0)); // move 64 bits - } else { // cnt2 = { 3, 5, 6, 7 } - // Array header size is 12 bytes in 32-bit VM - // + 6 bytes for 3 chars == 18 bytes, - // enough space to load vec and shift. - masm.movdqu(vec, new AMD64Address(charPtr2, (intCnt2 * 2) - 16)); - masm.psrldq(vec, 16 - (intCnt2 * 2)); - } - } else { // not constant substring - masm.cmpl(cnt2, 8); - masm.jccb(ConditionFlag.AboveEqual, bigStrings); // Both strings are big enough - - // We can read beyond string if str+16 does not cross page boundary - // since heaps are aligned and mapped by pages. - assert vmPageSize < 1024 * 1024 * 1024 : "default page should be small"; - masm.movl(result, charPtr2); // We need only low 32 bits - masm.andl(result, (vmPageSize - 1)); - masm.cmpl(result, (vmPageSize - 16)); - masm.jccb(ConditionFlag.BelowEqual, checkStr); - - // Move small strings to stack to allow load 16 bytes into vec. - masm.subq(rsp, 16); - int stackOffset = wordSize - 2; - masm.push(cnt2); - - masm.bind(copySubstr); - masm.movzwl(result, new AMD64Address(charPtr2, cnt2, Scale.Times2, -2)); - masm.movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result); - masm.decrementl(cnt2, 1); - masm.jccb(ConditionFlag.NotZero, copySubstr); - - masm.pop(cnt2); - masm.movq(charPtr2, rsp); // New substring address - } // non constant - - masm.bind(checkStr); - masm.cmpl(cnt1, 8); - masm.jccb(ConditionFlag.AboveEqual, bigStrings); - - // Check cross page boundary. - masm.movl(result, charPtr1); // We need only low 32 bits - masm.andl(result, (vmPageSize - 1)); - masm.cmpl(result, (vmPageSize - 16)); - masm.jccb(ConditionFlag.BelowEqual, bigStrings); - - masm.subq(rsp, 16); - int stackOffset = -2; - if (intCnt2 < 0) { // not constant - masm.push(cnt2); - stackOffset += wordSize; - } - masm.movl(cnt2, cnt1); - - masm.bind(copyStr); - masm.movzwl(result, new AMD64Address(charPtr1, cnt2, Scale.Times2, -2)); - masm.movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result); - masm.decrementl(cnt2, 1); - masm.jccb(ConditionFlag.NotZero, copyStr); - - if (intCnt2 < 0) { // not constant - masm.pop(cnt2); - } - masm.movq(charPtr1, rsp); // New string address - - masm.bind(bigStrings); - // Load substring. - if (intCnt2 < 0) { // -1 - masm.movdqu(vec, new AMD64Address(charPtr2, 0)); - masm.push(cnt2); // substr count - masm.push(charPtr2); // substr addr - masm.push(charPtr1); // string addr - } else { - // Small (< 8 chars) constant substrings are loaded already. - masm.movl(cnt2, intCnt2); - } - masm.push(tmp); // original SP - // Finished loading - - // ======================================================== - // Start search - // - - masm.movq(result, charPtr1); // string addr - - if (intCnt2 < 0) { // Only for non constant substring - masm.jmpb(scanToSubstr); - - // SP saved at sp+0 - // String saved at sp+1*wordSize - // Substr saved at sp+2*wordSize - // Substr count saved at sp+3*wordSize - - // Reload substr for rescan, this code - // is executed only for large substrings (> 8 chars) - masm.bind(reloadSubstr); - masm.movq(charPtr2, new AMD64Address(rsp, 2 * wordSize)); - masm.movl(cnt2, new AMD64Address(rsp, 3 * wordSize)); - masm.movdqu(vec, new AMD64Address(charPtr2, 0)); - // We came here after the beginning of the substring was - // matched but the rest of it was not so we need to search - // again. Start from the next element after the previous match. - masm.subq(charPtr1, result); // Restore counter - masm.shrl(charPtr1, 1); - masm.addl(cnt1, charPtr1); - masm.decrementl(cnt1); // Shift to next element - masm.cmpl(cnt1, cnt2); - masm.jccb(ConditionFlag.Negative, retNotFound); // Left less then substring - - masm.addq(result, 2); - } // non constant - - // Scan string for start of substr in 16-byte vectors - masm.bind(scanToSubstr); - assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri"; - masm.pcmpestri(vec, new AMD64Address(result, 0), 0x0d); - masm.jccb(ConditionFlag.Below, foundCandidate); // CF == 1 - masm.subl(cnt1, 8); - masm.jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string - masm.cmpl(cnt1, cnt2); - masm.jccb(ConditionFlag.Negative, retNotFound); // Left less then substring - masm.addq(result, 16); - - masm.bind(adjustStr); - masm.cmpl(cnt1, 8); // Do not read beyond string - masm.jccb(ConditionFlag.GreaterEqual, scanToSubstr); - // Back-up string to avoid reading beyond string. - masm.leaq(result, new AMD64Address(result, cnt1, Scale.Times2, -16)); - masm.movl(cnt1, 8); - masm.jmpb(scanToSubstr); - - // Found a potential substr - masm.bind(foundCandidate); - // After pcmpestri tmp(rcx) contains matched element index - - // Make sure string is still long enough - masm.subl(cnt1, tmp); - masm.cmpl(cnt1, cnt2); - masm.jccb(ConditionFlag.GreaterEqual, foundSubstr); - // Left less then substring. - - masm.bind(retNotFound); - masm.movl(result, -1); - masm.jmpb(cleanup); - - masm.bind(foundSubstr); - // Compute start addr of substr - masm.leaq(result, new AMD64Address(result, tmp, Scale.Times2)); - - if (intCnt2 > 0) { // Constant substring - // Repeat search for small substring (< 8 chars) - // from new point without reloading substring. - // Have to check that we don't read beyond string. - masm.cmpl(tmp, 8 - intCnt2); - masm.jccb(ConditionFlag.Greater, adjustStr); - // Fall through if matched whole substring. - } else { // non constant - assert intCnt2 == -1 : "should be != 0"; - masm.addl(tmp, cnt2); - // Found result if we matched whole substring. - masm.cmpl(tmp, 8); - masm.jccb(ConditionFlag.LessEqual, retFound); - - // Repeat search for small substring (<= 8 chars) - // from new point 'str1' without reloading substring. - masm.cmpl(cnt2, 8); - // Have to check that we don't read beyond string. - masm.jccb(ConditionFlag.LessEqual, adjustStr); - - Label checkNext = new Label(); - Label contScanSubstr = new Label(); - Label retFoundLong = new Label(); - // Compare the rest of substring (> 8 chars). - masm.movq(charPtr1, result); - - masm.cmpl(tmp, cnt2); - // First 8 chars are already matched. - masm.jccb(ConditionFlag.Equal, checkNext); - - masm.bind(scanSubstr); - masm.pcmpestri(vec, new AMD64Address(charPtr1, 0), 0x0d); - // Need to reload strings pointers if not matched whole vector - masm.jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0 - - masm.bind(checkNext); - masm.subl(cnt2, 8); - masm.jccb(ConditionFlag.LessEqual, retFoundLong); // Found full substring - masm.addq(charPtr1, 16); - masm.addq(charPtr2, 16); - masm.subl(cnt1, 8); - masm.cmpl(cnt2, 8); // Do not read beyond substring - masm.jccb(ConditionFlag.GreaterEqual, contScanSubstr); - // Back-up strings to avoid reading beyond substring. - masm.leaq(charPtr2, new AMD64Address(charPtr2, cnt2, Scale.Times2, -16)); - masm.leaq(charPtr1, new AMD64Address(charPtr1, cnt2, Scale.Times2, -16)); - masm.subl(cnt1, cnt2); - masm.movl(cnt2, 8); - masm.addl(cnt1, 8); - masm.bind(contScanSubstr); - masm.movdqu(vec, new AMD64Address(charPtr2, 0)); - masm.jmpb(scanSubstr); - - masm.bind(retFoundLong); - masm.movq(charPtr1, new AMD64Address(rsp, wordSize)); - } // non constant - - masm.bind(retFound); - // Compute substr offset - masm.subq(result, charPtr1); - masm.shrl(result, 1); // index - - masm.bind(cleanup); - masm.pop(rsp); // restore SP - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java new file mode 100644 index 0000000000..c079f98947 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringLatin1InflateOp.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2018, 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.lir.amd64; + +import static jdk.vm.ci.amd64.AMD64.k1; +import static jdk.vm.ci.amd64.AMD64.k2; +import static jdk.vm.ci.amd64.AMD64.rdi; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.rsi; + +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import jdk.vm.ci.amd64.AMD64; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.Value; + +@Opcode("AMD64_STRING_INFLATE") +public final class AMD64StringLatin1InflateOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64StringLatin1InflateOp.class); + + @Alive({REG}) private Value rsrc; + @Alive({REG}) private Value rdst; + @Alive({REG}) private Value rlen; + + @Temp({REG}) private Value vtmp1; + @Temp({REG}) private Value rtmp2; + + public AMD64StringLatin1InflateOp(LIRGeneratorTool tool, Value src, Value dst, Value len) { + super(TYPE); + + assert asRegister(src).equals(rsi); + assert asRegister(dst).equals(rdi); + assert asRegister(len).equals(rdx); + + rsrc = src; + rdst = dst; + rlen = len; + + vtmp1 = tool.newVariable(LIRKind.value(AMD64Kind.V512_BYTE)); + rtmp2 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register src = asRegister(rsrc); + Register dst = asRegister(rdst); + Register len = asRegister(rlen); + + Register tmp1 = asRegister(vtmp1); + Register tmp2 = asRegister(rtmp2); + + byteArrayInflate(masm, src, dst, len, tmp1, tmp2); + } + + /** + * Inflate a Latin1 string using a byte[] array representation into a UTF16 string using a + * char[] array representation. + * + * @param masm the assembler + * @param src (rsi) the start address of source byte[] to be inflated + * @param dst (rdi) the start address of destination char[] array + * @param len (rdx) the length + * @param vtmp (xmm) temporary xmm register + * @param tmp (gpr) temporary gpr register + */ + private static void byteArrayInflate(AMD64MacroAssembler masm, Register src, Register dst, Register len, Register vtmp, Register tmp) { + assert vtmp.getRegisterCategory().equals(AMD64.XMM); + + Label labelDone = new Label(); + Label labelBelowThreshold = new Label(); + + assert src.number != dst.number && src.number != len.number && src.number != tmp.number; + assert dst.number != len.number && dst.number != tmp.number; + assert len.number != tmp.number; + + if (masm.supports(AMD64.CPUFeature.AVX512BW) && + masm.supports(AMD64.CPUFeature.AVX512VL) && + masm.supports(AMD64.CPUFeature.BMI2)) { + + // If the length of the string is less than 16, we chose not to use the + // AVX512 instructions. + masm.testl(len, -16); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelBelowThreshold); + + Label labelAvx512Tail = new Label(); + // Test for suitable number chunks with respect to the size of the vector + // operation, mask off remaining number of chars (bytes) to inflate (such + // that 'len' will always hold the number of bytes left to inflate) after + // committing to the vector loop. + // Adjust vector pointers to upper address bounds and inverse loop index. + // This will keep the loop condition simple. + // + // NOTE: The above idiom/pattern is used in all the loops below. + + masm.movl(tmp, len); + masm.andl(tmp, -32); // The vector count (in chars). + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelAvx512Tail); + masm.andl(len, 32 - 1); // The tail count (in chars). + + masm.leaq(src, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.leaq(dst, new AMD64Address(dst, tmp, AMD64Address.Scale.Times2)); + masm.negq(tmp); + + Label labelAvx512Loop = new Label(); + // Inflate 32 chars per iteration, reading 256-bit compact vectors + // and writing 512-bit inflated ditto. + masm.bind(labelAvx512Loop); + masm.evpmovzxbw(vtmp, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.evmovdqu16(new AMD64Address(dst, tmp, AMD64Address.Scale.Times2), vtmp); + masm.addq(tmp, 32); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelAvx512Loop); + + masm.bind(labelAvx512Tail); + // All done if the tail count is zero. + masm.testl(len, len); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelDone); + + masm.kmovq(k2, k1); // Save k1 + + // Compute (1 << N) - 1 = ~(~0 << N), where N is the remaining number + // of characters to process. + masm.movl(tmp, -1); + masm.shlxl(tmp, tmp, len); + masm.notl(tmp); + + masm.kmovd(k1, tmp); + masm.evpmovzxbw(vtmp, k1, new AMD64Address(src)); + masm.evmovdqu16(new AMD64Address(dst), k1, vtmp); + masm.kmovq(k1, k2); // Restore k1 + masm.jmp(labelDone); + } + + if (masm.supports(AMD64.CPUFeature.SSE4_1)) { + + Label labelSSETail = new Label(); + + if (masm.supports(AMD64.CPUFeature.AVX2)) { + + Label labelAvx2Tail = new Label(); + + masm.movl(tmp, len); + masm.andl(tmp, -16); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelAvx2Tail); + masm.andl(len, 16 - 1); + + masm.leaq(src, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.leaq(dst, new AMD64Address(dst, tmp, AMD64Address.Scale.Times2)); + masm.negq(tmp); + + Label labelAvx2Loop = new Label(); + // Inflate 16 bytes (chars) per iteration, reading 128-bit compact vectors + // and writing 256-bit inflated ditto. + masm.bind(labelAvx2Loop); + masm.vpmovzxbw(vtmp, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.vmovdqu(new AMD64Address(dst, tmp, AMD64Address.Scale.Times2), vtmp); + masm.addq(tmp, 16); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelAvx2Loop); + + masm.bind(labelBelowThreshold); + masm.bind(labelAvx2Tail); + + masm.movl(tmp, len); + masm.andl(tmp, -8); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelSSETail); + masm.andl(len, 8 - 1); + + // Inflate another 8 bytes before final tail copy. + masm.pmovzxbw(vtmp, new AMD64Address(src)); + masm.movdqu(new AMD64Address(dst), vtmp); + masm.addq(src, 8); + masm.addq(dst, 16); + + // Fall-through to labelSSETail. + } else { + // When there is no AVX2 support available, we use AVX/SSE support to + // inflate into maximum 128-bits per operation. + + masm.movl(tmp, len); + masm.andl(tmp, -8); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelSSETail); + masm.andl(len, 8 - 1); + + masm.leaq(src, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.leaq(dst, new AMD64Address(dst, tmp, AMD64Address.Scale.Times2)); + masm.negq(tmp); + + Label labelSSECopy8Loop = new Label(); + // Inflate 8 bytes (chars) per iteration, reading 64-bit compact vectors + // and writing 128-bit inflated ditto. + masm.bind(labelSSECopy8Loop); + masm.pmovzxbw(vtmp, new AMD64Address(src, tmp, AMD64Address.Scale.Times1)); + masm.movdqu(new AMD64Address(dst, tmp, AMD64Address.Scale.Times2), vtmp); + masm.addq(tmp, 8); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelSSECopy8Loop); + + // Fall-through to labelSSETail. + } + + Label labelCopyChars = new Label(); + + masm.bind(labelSSETail); + masm.cmpl(len, 4); + masm.jccb(AMD64Assembler.ConditionFlag.Less, labelCopyChars); + + masm.movdl(vtmp, new AMD64Address(src)); + masm.pmovzxbw(vtmp, vtmp); + masm.movq(new AMD64Address(dst), vtmp); + masm.subq(len, 4); + masm.addq(src, 4); + masm.addq(dst, 8); + + masm.bind(labelCopyChars); + } + + // Inflate any remaining characters (bytes) using a vanilla implementation. + masm.testl(len, len); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelDone); + masm.leaq(src, new AMD64Address(src, len, AMD64Address.Scale.Times1)); + masm.leaq(dst, new AMD64Address(dst, len, AMD64Address.Scale.Times2)); + masm.negq(len); + + Label labelCopyCharsLoop = new Label(); + // Inflate a single byte (char) per iteration. + masm.bind(labelCopyCharsLoop); + masm.movzbl(tmp, new AMD64Address(src, len, AMD64Address.Scale.Times1)); + masm.movw(new AMD64Address(dst, len, AMD64Address.Scale.Times2), tmp); + masm.incrementq(len, 1); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelCopyCharsLoop); + + masm.bind(labelDone); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java new file mode 100644 index 0000000000..9e795179a2 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64StringUTF16CompressOp.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2018, 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.lir.amd64; + +import static jdk.vm.ci.amd64.AMD64.k1; +import static jdk.vm.ci.amd64.AMD64.k2; +import static jdk.vm.ci.amd64.AMD64.k3; +import static jdk.vm.ci.amd64.AMD64.rax; +import static jdk.vm.ci.amd64.AMD64.rdi; +import static jdk.vm.ci.amd64.AMD64.rdx; +import static jdk.vm.ci.amd64.AMD64.rsi; + +import static jdk.vm.ci.amd64.AMD64.rsp; +import static jdk.vm.ci.code.ValueUtil.asRegister; +import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG; + +import jdk.vm.ci.amd64.AMD64; +import org.graalvm.compiler.asm.Label; +import org.graalvm.compiler.asm.amd64.AMD64Address; +import org.graalvm.compiler.asm.amd64.AMD64Assembler; +import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; +import org.graalvm.compiler.core.common.LIRKind; +import org.graalvm.compiler.lir.LIRInstructionClass; +import org.graalvm.compiler.lir.Opcode; +import org.graalvm.compiler.lir.asm.CompilationResultBuilder; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; + +import jdk.vm.ci.amd64.AMD64Kind; +import jdk.vm.ci.code.Register; +import jdk.vm.ci.meta.Value; + +@Opcode("AMD64_STRING_COMPRESS") +public final class AMD64StringUTF16CompressOp extends AMD64LIRInstruction { + public static final LIRInstructionClass TYPE = LIRInstructionClass.create(AMD64StringUTF16CompressOp.class); + + @Def({REG}) private Value rres; + @Alive({REG}) private Value rsrc; + @Alive({REG}) private Value rdst; + @Alive({REG}) private Value rlen; + + @Temp({REG}) private Value vtmp1; + @Temp({REG}) private Value vtmp2; + @Temp({REG}) private Value vtmp3; + @Temp({REG}) private Value vtmp4; + @Temp({REG}) private Value rtmp5; + + public AMD64StringUTF16CompressOp(LIRGeneratorTool tool, Value res, Value src, Value dst, Value len) { + super(TYPE); + + assert asRegister(src).equals(rsi); + assert asRegister(dst).equals(rdi); + assert asRegister(len).equals(rdx); + assert asRegister(res).equals(rax); + + rres = res; + rsrc = src; + rdst = dst; + rlen = len; + + LIRKind vkind = LIRKind.value(AMD64Kind.V512_BYTE); + + vtmp1 = tool.newVariable(vkind); + vtmp2 = tool.newVariable(vkind); + vtmp3 = tool.newVariable(vkind); + vtmp4 = tool.newVariable(vkind); + + rtmp5 = tool.newVariable(LIRKind.value(AMD64Kind.DWORD)); + } + + @Override + public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { + Register res = asRegister(rres); + Register src = asRegister(rsrc); + Register dst = asRegister(rdst); + Register len = asRegister(rlen); + + Register tmp1 = asRegister(vtmp1); + Register tmp2 = asRegister(vtmp2); + Register tmp3 = asRegister(vtmp3); + Register tmp4 = asRegister(vtmp4); + Register tmp5 = asRegister(rtmp5); + + charArrayCompress(masm, src, dst, len, tmp1, tmp2, tmp3, tmp4, tmp5, res); + } + + /** + * Compress a UTF16 string which de facto is a Latin1 string into a byte array representation + * (buffer). + * + * @param masm the assembler + * @param src (rsi) the start address of source char[] to be compressed + * @param dst (rdi) the start address of destination byte[] vector + * @param len (rdx) the length + * @param tmp1 (xmm) temporary xmm register + * @param tmp2 (xmm) temporary xmm register + * @param tmp3 (xmm) temporary xmm register + * @param tmp4 (xmm) temporary xmm register + * @param tmp (gpr) temporary gpr register + * @param res (rax) the result code (length on success, zero otherwise) + */ + private static void charArrayCompress(AMD64MacroAssembler masm, Register src, Register dst, Register len, Register tmp1, + Register tmp2, Register tmp3, Register tmp4, Register tmp, Register res) { + assert tmp1.getRegisterCategory().equals(AMD64.XMM); + assert tmp2.getRegisterCategory().equals(AMD64.XMM); + assert tmp3.getRegisterCategory().equals(AMD64.XMM); + assert tmp4.getRegisterCategory().equals(AMD64.XMM); + + Label labelReturnLength = new Label(); + Label labelReturnZero = new Label(); + Label labelDone = new Label(); + Label labelBelowThreshold = new Label(); + + assert len.number != res.number; + + masm.push(len); // Save length for return. + + if (masm.supports(AMD64.CPUFeature.AVX512BW) && + masm.supports(AMD64.CPUFeature.AVX512VL) && + masm.supports(AMD64.CPUFeature.BMI2)) { + + Label labelRestoreK1ReturnZero = new Label(); + Label labelAvxPostAlignment = new Label(); + + // If the length of the string is less than 32, we chose not to use the + // AVX512 instructions. + masm.testl(len, -32); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelBelowThreshold); + + // First check whether a character is compressible (<= 0xff). + // Create mask to test for Unicode chars inside (zmm) vector. + masm.movl(res, 0x00ff); + masm.evpbroadcastw(tmp2, res); + + masm.kmovq(k3, k1); // Save k1 + + masm.testl(len, -64); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelAvxPostAlignment); + + masm.movl(tmp, dst); + masm.andl(tmp, (32 - 1)); + masm.negl(tmp); + masm.andl(tmp, (32 - 1)); + + // bail out when there is nothing to be done + masm.testl(tmp, tmp); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelAvxPostAlignment); + + // Compute (1 << N) - 1 = ~(~0 << N), where N is the remaining number + // of characters to process. + masm.movl(res, -1); + masm.shlxl(res, res, tmp); + masm.notl(res); + + masm.kmovd(k1, res); + masm.evmovdqu16(tmp1, k1, new AMD64Address(src)); + masm.evpcmpuw(k2, k1, tmp1, tmp2, 2 /* le */); + masm.ktestd(k2, k1); + masm.jcc(AMD64Assembler.ConditionFlag.CarryClear, labelRestoreK1ReturnZero); + + masm.evpmovwb(new AMD64Address(dst), k1, tmp1); + + masm.addq(src, tmp); + masm.addq(src, tmp); + masm.addq(dst, tmp); + masm.subl(len, tmp); + + masm.bind(labelAvxPostAlignment); + // end of alignment + Label labelAvx512LoopTail = new Label(); + + masm.movl(tmp, len); + masm.andl(tmp, -32); // The vector count (in chars). + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelAvx512LoopTail); + masm.andl(len, 32 - 1); // The tail count (in chars). + + masm.leaq(src, new AMD64Address(src, tmp, AMD64Address.Scale.Times2)); + masm.leaq(dst, new AMD64Address(dst, tmp, AMD64Address.Scale.Times1)); + masm.negq(tmp); + + Label labelAvx512Loop = new Label(); + // Test and compress 32 chars per iteration, reading 512-bit vectors and + // writing 256-bit compressed ditto. + masm.bind(labelAvx512Loop); + masm.evmovdqu16(tmp1, new AMD64Address(src, tmp, AMD64Address.Scale.Times2)); + masm.evpcmpuw(k2, tmp1, tmp2, 2 /* le */); + masm.kortestd(k2, k2); + masm.jcc(AMD64Assembler.ConditionFlag.CarryClear, labelRestoreK1ReturnZero); + + // All 32 chars in the current vector (chunk) are valid for compression, + // write truncated byte elements to memory. + masm.evpmovwb(new AMD64Address(dst, tmp, AMD64Address.Scale.Times1), tmp1); + masm.addq(tmp, 32); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelAvx512Loop); + + masm.bind(labelAvx512LoopTail); + masm.kmovq(k1, k3); // Restore k1 + + // All done if the tail count is zero. + masm.testl(len, len); + masm.jcc(AMD64Assembler.ConditionFlag.Zero, labelReturnLength); + + // Compute (1 << N) - 1 = ~(~0 << N), where N is the remaining number + // of characters to process. + masm.movl(res, -1); + masm.shlxl(res, res, len); + masm.notl(res); + + masm.kmovd(k1, res); + masm.evmovdqu16(tmp1, k1, new AMD64Address(src)); + masm.evpcmpuw(k2, k1, tmp1, tmp2, 2 /* le */); + masm.ktestd(k2, k1); + masm.jcc(AMD64Assembler.ConditionFlag.CarryClear, labelRestoreK1ReturnZero); + + masm.evpmovwb(new AMD64Address(dst), k1, tmp1); + + masm.kmovq(k1, k3); // Restore k1 + masm.jmp(labelReturnLength); + + masm.bind(labelRestoreK1ReturnZero); + masm.kmovq(k1, k3); // Restore k1 + masm.jmp(labelReturnZero); + } + + if (masm.supports(AMD64.CPUFeature.SSE4_2)) { + + Label labelSSETail = new Label(); + + masm.bind(labelBelowThreshold); + + masm.movl(tmp, 0xff00ff00); // Create mask to test for Unicode chars in vectors. + + masm.movl(res, len); + masm.andl(res, -16); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelSSETail); + masm.andl(len, 16 - 1); + + // Compress 16 chars per iteration. + masm.movdl(tmp1, tmp); + masm.pshufd(tmp1, tmp1, 0); // Store Unicode mask in 'vtmp1'. + masm.pxor(tmp4, tmp4); + + masm.leaq(src, new AMD64Address(src, res, AMD64Address.Scale.Times2)); + masm.leaq(dst, new AMD64Address(dst, res, AMD64Address.Scale.Times1)); + masm.negq(res); + + Label lSSELoop = new Label(); + // Test and compress 16 chars per iteration, reading 128-bit vectors and + // writing 64-bit compressed ditto. + masm.bind(lSSELoop); + masm.movdqu(tmp2, new AMD64Address(src, res, AMD64Address.Scale.Times2)); // load + // 1st 8 + // characters + masm.movdqu(tmp3, new AMD64Address(src, res, AMD64Address.Scale.Times2, 16)); // load + // next 8 + // characters + masm.por(tmp4, tmp2); + masm.por(tmp4, tmp3); + masm.ptest(tmp4, tmp1); // Check for Unicode chars in vector. + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelReturnZero); + + masm.packuswb(tmp2, tmp3); // Only ASCII chars; compress each to a byte. + masm.movdqu(new AMD64Address(dst, res, AMD64Address.Scale.Times1), tmp2); + masm.addq(res, 16); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, lSSELoop); + + Label labelCopyChars = new Label(); + // Test and compress another 8 chars before final tail copy. + masm.bind(labelSSETail); + masm.movl(res, len); + masm.andl(res, -8); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelCopyChars); + masm.andl(len, 8 - 1); + + masm.movdl(tmp1, tmp); + masm.pshufd(tmp1, tmp1, 0); // Store Unicode mask in 'vtmp1'. + masm.pxor(tmp3, tmp3); + + masm.movdqu(tmp2, new AMD64Address(src)); + masm.ptest(tmp2, tmp1); // Check for Unicode chars in vector. + masm.jccb(AMD64Assembler.ConditionFlag.NotZero, labelReturnZero); + masm.packuswb(tmp2, tmp3); // Only ASCII chars; compress each to a byte. + masm.movq(new AMD64Address(dst), tmp2); + masm.addq(src, 16); + masm.addq(dst, 8); + + masm.bind(labelCopyChars); + } + + // Compress any remaining characters using a vanilla implementation. + masm.testl(len, len); + masm.jccb(AMD64Assembler.ConditionFlag.Zero, labelReturnLength); + masm.leaq(src, new AMD64Address(src, len, AMD64Address.Scale.Times2)); + masm.leaq(dst, new AMD64Address(dst, len, AMD64Address.Scale.Times1)); + masm.negq(len); + + Label labelCopyCharsLoop = new Label(); + // Compress a single character per iteration. + masm.bind(labelCopyCharsLoop); + masm.movzwl(res, new AMD64Address(src, len, AMD64Address.Scale.Times2)); + masm.testl(res, 0xff00); // Check if Unicode character. + masm.jccb(AMD64Assembler.ConditionFlag.NotZero, labelReturnZero); + // An ASCII character; compress to a byte. + masm.movb(new AMD64Address(dst, len, AMD64Address.Scale.Times1), res); + masm.incrementq(len, 1); + masm.jcc(AMD64Assembler.ConditionFlag.NotZero, labelCopyCharsLoop); + + // If compression succeeded, return the length. + masm.bind(labelReturnLength); + masm.pop(res); + masm.jmpb(labelDone); + + // If compression failed, return 0. + masm.bind(labelReturnZero); + masm.xorl(res, res); + masm.addq(rsp, 8 /* wordSize */); + + masm.bind(labelDone); + } + +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java index 03b3458196..fffc3aa9f2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java @@ -74,14 +74,14 @@ public final class SPARCArrayEqualsOp extends SPARCLIRInstruction { @Temp({REG}) protected AllocatableValue temp4; @Temp({REG}) protected AllocatableValue temp5; - public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, AllocatableValue result, AllocatableValue array1, AllocatableValue array2, AllocatableValue length) { + public SPARCArrayEqualsOp(LIRGeneratorTool tool, JavaKind kind, AllocatableValue result, AllocatableValue array1, AllocatableValue array2, AllocatableValue length, boolean directPointers) { super(TYPE, SIZE); assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported"; this.kind = kind; - this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind); - this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind); + this.arrayBaseOffset = directPointers ? 0 : tool.getProviders().getMetaAccess().getArrayBaseOffset(kind); + this.arrayIndexScale = tool.getProviders().getMetaAccess().getArrayIndexScale(kind); this.resultValue = result; this.array1Value = array1; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java index 7300636a92..5584278fca 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanOptimizeSpillPositionPhase.java @@ -150,10 +150,10 @@ public final class LinearScanOptimizeSpillPositionPhase extends LinearScanAlloca debug.log("Better spill position found (Block %s)", spillBlock); } - if (defBlock.probability() <= spillBlock.probability()) { - debug.log(DebugContext.VERBOSE_LEVEL, "Definition has lower probability %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.probability(), spillBlock, - spillBlock.probability()); - // better spill block has the same probability -> do nothing + if (defBlock.getRelativeFrequency() <= spillBlock.getRelativeFrequency()) { + debug.log(DebugContext.VERBOSE_LEVEL, "Definition has lower frequency %s (%f) is lower than spill block %s (%f)", defBlock, defBlock.getRelativeFrequency(), spillBlock, + spillBlock.getRelativeFrequency()); + // better spill block has the same frequency -> do nothing interval.setSpillState(SpillState.StoreAtDefinition); return; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java index 1b3afd39c6..5bfafd1a6d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/DefaultTraceRegisterAllocationPolicy.java @@ -77,9 +77,9 @@ public final class DefaultTraceRegisterAllocationPolicy { public static final OptionKey TraceRAnumVariables = new OptionKey<>(null); @Option(help = "Use LSRA / BottomUp ratio", type = OptionType.Debug) public static final OptionKey TraceRAbottomUpRatio = new OptionKey<>(0.0); - @Option(help = "Probability Threshold", type = OptionType.Debug) - public static final OptionKey TraceRAprobalilityThreshold = new OptionKey<>(0.8); - @Option(help = "Sum Probability Budget Threshold", type = OptionType.Debug) + @Option(help = "Frequency Threshold", type = OptionType.Debug) + public static final OptionKey TraceRAfrequencyThreshold = new OptionKey<>(0.8); + @Option(help = "Sum Frequency Budget Threshold", type = OptionType.Debug) public static final OptionKey TraceRAsumBudget = new OptionKey<>(0.5); @Option(help = "TraceRA allocation policy to use.", type = OptionType.Debug) public static final EnumOptionKey TraceRAPolicy = new EnumOptionKey<>(TraceRAPolicies.Default); @@ -277,22 +277,22 @@ public final class DefaultTraceRegisterAllocationPolicy { public static final class BottomUpMaxFrequencyStrategy extends BottomUpStrategy { - private final double maxMethodProbability; - private final double probabilityThreshold; + private final double maxRelativeFrequency; + private final double frequencyThreshold; public BottomUpMaxFrequencyStrategy(TraceRegisterAllocationPolicy plan) { // explicitly specify the enclosing instance for the superclass constructor call super(plan); - maxMethodProbability = maxProbability(getLIR().getControlFlowGraph().getBlocks()); - probabilityThreshold = Options.TraceRAprobalilityThreshold.getValue(plan.getOptions()); + maxRelativeFrequency = maxRelativeFrequency(getLIR().getControlFlowGraph().getBlocks()); + frequencyThreshold = Options.TraceRAfrequencyThreshold.getValue(plan.getOptions()); } - private static double maxProbability(AbstractBlockBase[] blocks) { + private static double maxRelativeFrequency(AbstractBlockBase[] blocks) { double max = 0; for (AbstractBlockBase block : blocks) { - double probability = block.probability(); - if (probability > max) { - max = probability; + double frequency = block.getRelativeFrequency(); + if (frequency > max) { + max = frequency; } } return max; @@ -303,23 +303,23 @@ public final class DefaultTraceRegisterAllocationPolicy { if (!super.shouldApplyTo(trace)) { return false; } - return maxProbability(trace.getBlocks()) / maxMethodProbability <= probabilityThreshold; + return maxRelativeFrequency(trace.getBlocks()) / maxRelativeFrequency <= frequencyThreshold; } } public static final class BottomUpFrequencyBudgetStrategy extends BottomUpStrategy { - private final double[] cumulativeTraceProbability; + private final double[] cumulativeTraceFrequency; private final double budget; public BottomUpFrequencyBudgetStrategy(TraceRegisterAllocationPolicy plan) { // explicitly specify the enclosing instance for the superclass constructor call super(plan); ArrayList traces = getTraceBuilderResult().getTraces(); - this.cumulativeTraceProbability = new double[traces.size()]; - double sumMethodProbability = init(traces, this.cumulativeTraceProbability); - this.budget = sumMethodProbability * Options.TraceRAsumBudget.getValue(plan.getOptions()); + this.cumulativeTraceFrequency = new double[traces.size()]; + double sumMethodFrequency = init(traces, this.cumulativeTraceFrequency); + this.budget = sumMethodFrequency * Options.TraceRAsumBudget.getValue(plan.getOptions()); } private static double init(ArrayList traces, double[] sumTraces) { @@ -327,7 +327,7 @@ public final class DefaultTraceRegisterAllocationPolicy { for (Trace trace : traces) { double traceSum = 0; for (AbstractBlockBase block : trace.getBlocks()) { - traceSum += block.probability(); + traceSum += block.getRelativeFrequency(); } sumMethod += traceSum; // store cumulative sum for trace @@ -341,8 +341,8 @@ public final class DefaultTraceRegisterAllocationPolicy { if (!super.shouldApplyTo(trace)) { return false; } - double cumTraceProb = cumulativeTraceProbability[trace.getId()]; - return cumTraceProb > budget; + double cumTraceFrequency = cumulativeTraceFrequency[trace.getId()]; + return cumTraceFrequency > budget; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java index 341c19649d..35dcbeb1f8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/trace/lsra/TraceLinearScanWalker.java @@ -451,14 +451,14 @@ final class TraceLinearScanWalker { optimalSplitPos = allocator.getFirstLirInstructionId(maxBlock); } - // minimal block probability - double minProbability = maxBlock.probability(); + // minimal block frequency + double minFrequency = maxBlock.getRelativeFrequency(); for (int i = toBlockNr - 1; i >= fromBlockNr; i--) { AbstractBlockBase cur = blockAt(i); - if (cur.probability() < minProbability) { - // Block with lower probability found. Split at the end of this block. - minProbability = cur.probability(); + if (cur.getRelativeFrequency() < minFrequency) { + // Block with lower frequency found. Split at the end of this block. + minFrequency = cur.getRelativeFrequency(); optimalSplitPos = allocator.getLastLirInstructionId(cur) + 2; } } @@ -856,16 +856,16 @@ final class TraceLinearScanWalker { optimalSplitPos = maxSplitPos; } - // minimal block probability - double minProbability = maxBlock.probability(); + // minimal block frequency + double minFrequency = maxBlock.getRelativeFrequency(); for (int i = toBlockNr - 1; i >= fromBlockNr; i--) { AbstractBlockBase cur = blockAt(i); - if (cur.probability() < minProbability) { - // Block with lower probability found. Split at the end of this block. + if (cur.getRelativeFrequency() < minFrequency) { + // Block with lower frequency found. Split at the end of this block. int opIdBeforeBlockEnd = allocator.getLastLirInstructionId(cur) - 2; if (allocator.getLIR().getLIRforBlock(cur).size() > 2) { - minProbability = cur.probability(); + minFrequency = cur.getRelativeFrequency(); optimalSplitPos = opIdBeforeBlockEnd; } else { /* diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java index 794b12884e..596086af8c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantLoadOptimization.java @@ -65,8 +65,8 @@ import jdk.vm.ci.meta.ValueKind; /** * This optimization tries to improve the handling of constants by replacing a single definition of - * a constant, which is potentially scheduled into a block with high probability, with one or more - * definitions in blocks with a lower probability. + * a constant, which is potentially scheduled into a block with high frequency, with one or more + * definitions in blocks with a lower frequency. */ public final class ConstantLoadOptimization extends PreAllocationOptimizationPhase { @@ -271,13 +271,13 @@ public final class ConstantLoadOptimization extends PreAllocationOptimizationPha assert usageCount == tree.usageCount() : "Usage count differs: " + usageCount + " vs. " + tree.usageCount(); if (debug.isLogEnabled()) { - try (Indent i = debug.logAndIndent("Variable: %s, Block: %s, prob.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().probability())) { + try (Indent i = debug.logAndIndent("Variable: %s, Block: %s, freq.: %f", tree.getVariable(), tree.getBlock(), tree.getBlock().getRelativeFrequency())) { debug.log("Usages result: %s", cost); } } - if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().probability()) { + if (cost.getNumMaterializations() > 1 || cost.getBestCost() < tree.getBlock().getRelativeFrequency()) { try (DebugContext.Scope s = debug.scope("CLOmodify", constTree); Indent i = debug.logAndIndent("Replacing %s = %s", tree.getVariable(), tree.getConstant().toValueString())) { // mark original load for removal deleteInstruction(tree); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java index 86deb5ea03..f911e8d2ba 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTree.java @@ -133,7 +133,7 @@ public class ConstantTree extends PrintableDominatorOptimizationProblem block) { NodeCost cost = getCost(block); if (cost == null) { - cost = new NodeCost(block.probability(), blockMap.get(block), 1); + cost = new NodeCost(block.getRelativeFrequency(), blockMap.get(block), 1); setCost(block, cost); } return cost; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java index 240b92c850..49c4864734 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/constopt/ConstantTreeAnalyzer.java @@ -129,7 +129,7 @@ public final class ConstantTreeAnalyzer { // choose block List usagesBlock = tree.getUsages(block); - double probabilityBlock = block.probability(); + double probabilityBlock = block.getRelativeFrequency(); if (!usagesBlock.isEmpty() || shouldMaterializerInCurrentBlock(probabilityBlock, bestCost, numMat)) { // mark current block as potential materialization position diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java index 12e352965e..f89280f2eb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java @@ -60,7 +60,7 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF /** * Factory for creating moves. */ - public interface MoveFactory { + interface MoveFactory { /** * Checks whether the supplied constant can be used without loading it into a register for @@ -261,16 +261,31 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture"); } - Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length); + Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length, int constantLength, boolean directPointers); @SuppressWarnings("unused") - default Variable emitStringIndexOf(Value sourcePointer, Value sourceCount, Value targetPointer, Value targetCount, int constantTargetCount) { + default Variable emitArrayIndexOf(JavaKind kind, boolean findTwoConsecutive, Value sourcePointer, Value sourceCount, Value... searchValues) { throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture"); } + /* + * The routines emitStringLatin1Inflate/3 and emitStringUTF16Compress/3 models a simplified + * version of + * + * emitStringLatin1Inflate(Value src, Value src_ndx, Value dst, Value dst_ndx, Value len) and + * emitStringUTF16Compress(Value src, Value src_ndx, Value dst, Value dst_ndx, Value len) + * + * respectively, where we have hoisted the offset address computations in a method replacement + * snippet. + */ @SuppressWarnings("unused") - default Variable emitArrayIndexOf(JavaKind kind, Value sourcePointer, Value sourceCount, Value charValue) { - throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture"); + default void emitStringLatin1Inflate(Value src, Value dst, Value len) { + throw GraalError.unimplemented("StringLatin1.inflate substitution is not implemented on this architecture"); + } + + @SuppressWarnings("unused") + default Variable emitStringUTF16Compress(Value src, Value dst, Value len) { + throw GraalError.unimplemented("StringUTF16.compress substitution is not implemented on this architecture"); } void emitBlackhole(Value operand); @@ -292,4 +307,10 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF default void emitConvertZeroToNull(AllocatableValue result, Value input) { emitMove(result, input); } + + /** + * Emits an instruction that prevents speculative execution from proceeding: no instruction + * after this fence will execute until all previous instructions have retired. + */ + void emitSpeculationFence(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java index d483e9ccbb..37c0bdeae8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopPartialUnrollPhase.java @@ -24,13 +24,17 @@ package org.graalvm.compiler.loop.phases; +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.graph.Graph; import org.graalvm.compiler.loop.LoopEx; import org.graalvm.compiler.loop.LoopPolicies; import org.graalvm.compiler.loop.LoopsData; +import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.tiers.PhaseContext; public class LoopPartialUnrollPhase extends LoopPhase { @@ -46,8 +50,9 @@ public class LoopPartialUnrollPhase extends LoopPhase { @SuppressWarnings("try") protected void run(StructuredGraph graph, PhaseContext context) { if (graph.hasLoops()) { - HashSetNodeEventListener listener = new HashSetNodeEventListener(); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); boolean changed = true; + EconomicMap opaqueUnrolledStrides = null; while (changed) { changed = false; try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { @@ -66,7 +71,10 @@ public class LoopPartialUnrollPhase extends LoopPhase { LoopTransformations.insertPrePostLoops(loop); prePostInserted = true; } else { - LoopTransformations.partialUnroll(loop); + if (opaqueUnrolledStrides == null) { + opaqueUnrolledStrides = EconomicMap.create(Equivalence.IDENTITY); + } + LoopTransformations.partialUnroll(loop, opaqueUnrolledStrides); } changed = true; } @@ -81,6 +89,16 @@ public class LoopPartialUnrollPhase extends LoopPhase { assert !prePostInserted || checkCounted(graph, mark); } } + if (opaqueUnrolledStrides != null) { + try (Graph.NodeEventScope nes = graph.trackNodeEvents(listener)) { + for (OpaqueNode opaque : opaqueUnrolledStrides.getValues()) { + opaque.remove(); + } + if (!listener.getNodes().isEmpty()) { + canonicalizer.applyIncremental(graph, context, listener.getNodes()); + } + } + } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java index f009362428..3448116b26 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java @@ -25,22 +25,19 @@ package org.graalvm.compiler.loop.phases; import static org.graalvm.compiler.core.common.GraalOptions.MaximumDesiredSize; -import static org.graalvm.compiler.loop.MathUtil.add; -import static org.graalvm.compiler.loop.MathUtil.sub; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import jdk.internal.vm.compiler.collections.EconomicMap; import org.graalvm.compiler.core.common.RetryableBailoutException; import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph.Mark; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Position; import org.graalvm.compiler.loop.CountedLoopInfo; -import org.graalvm.compiler.loop.InductionVariable; import org.graalvm.compiler.loop.InductionVariable.Direction; import org.graalvm.compiler.loop.LoopEx; import org.graalvm.compiler.loop.LoopFragmentInside; @@ -50,7 +47,6 @@ import org.graalvm.compiler.nodes.AbstractBeginNode; import org.graalvm.compiler.nodes.AbstractEndNode; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.BeginNode; -import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.ControlSplitNode; import org.graalvm.compiler.nodes.EndNode; import org.graalvm.compiler.nodes.FixedNode; @@ -59,13 +55,16 @@ import org.graalvm.compiler.nodes.IfNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.PhiNode; import org.graalvm.compiler.nodes.SafepointNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.ConditionalNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.extended.SwitchNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.tiers.PhaseContext; @@ -150,12 +149,12 @@ public abstract class LoopTransformations { // TODO (gd) probabilities need some amount of fixup.. (probably also in other transforms) } - public static void partialUnroll(LoopEx loop) { + public static void partialUnroll(LoopEx loop, EconomicMap opaqueUnrolledStrides) { assert loop.loopBegin().isMainLoop(); loop.loopBegin().graph().getDebug().log("LoopPartialUnroll %s", loop); LoopFragmentInside newSegment = loop.inside().duplicate(); - newSegment.insertWithinAfter(loop); + newSegment.insertWithinAfter(loop, opaqueUnrolledStrides); } @@ -235,7 +234,6 @@ public abstract class LoopTransformations { IfNode preLimit = preCounted.getLimitTest(); assert preLimit != null; LoopBeginNode preLoopBegin = loop.loopBegin(); - InductionVariable preIv = preCounted.getCounter(); LoopExitNode preLoopExitNode = preLoopBegin.getSingleLoopExit(); FixedNode continuationNode = preLoopExitNode.next(); @@ -279,8 +277,7 @@ public abstract class LoopTransformations { cleanupMerge(mainMergeNode, mainLandingNode); // Change the preLoop to execute one iteration for now - updateMainLoopLimit(preLimit, preIv, mainLoop); - updatePreLoopLimit(preLimit, preIv, preCounted); + updatePreLoopLimit(preCounted); preLoopBegin.setLoopFrequency(1); mainLoopBegin.setLoopFrequency(Math.max(0.0, mainLoopBegin.loopFrequency() - 2)); postLoopBegin.setLoopFrequency(Math.max(0.0, postLoopBegin.loopFrequency() - 1)); @@ -354,63 +351,22 @@ public abstract class LoopTransformations { return (EndNode) curNode; } - private static void updateMainLoopLimit(IfNode preLimit, InductionVariable preIv, LoopFragmentWhole mainLoop) { - // Update the main loops limit test to be different than the post loop - StructuredGraph graph = preLimit.graph(); - IfNode mainLimit = mainLoop.getDuplicatedNode(preLimit); - LogicNode ifTest = mainLimit.condition(); - CompareNode compareNode = (CompareNode) ifTest; - ValueNode prePhi = preIv.valueNode(); - ValueNode mainPhi = mainLoop.getDuplicatedNode(prePhi); - ValueNode preStride = preIv.strideNode(); - ValueNode mainStride; - if (preStride instanceof ConstantNode) { - mainStride = preStride; - } else { - mainStride = mainLoop.getDuplicatedNode(preStride); - } - // Fetch the bounds to pose lowering the range by one - ValueNode ub = null; - if (compareNode.getX() == mainPhi) { - ub = compareNode.getY(); - } else if (compareNode.getY() == mainPhi) { - ub = compareNode.getX(); - } else { - throw GraalError.shouldNotReachHere(); - } - - // Preloop always performs at least one iteration, so remove that from the main loop. - ValueNode newLimit = sub(graph, ub, mainStride); - - // Re-wire the condition with the new limit - compareNode.replaceFirstInput(ub, newLimit); - } - - private static void updatePreLoopLimit(IfNode preLimit, InductionVariable preIv, CountedLoopInfo preCounted) { + private static void updatePreLoopLimit(CountedLoopInfo preCounted) { // Update the pre loops limit test - StructuredGraph graph = preLimit.graph(); - LogicNode ifTest = preLimit.condition(); - CompareNode compareNode = (CompareNode) ifTest; - ValueNode prePhi = preIv.valueNode(); // Make new limit one iteration - ValueNode initIv = preCounted.getStart(); - ValueNode newLimit = add(graph, initIv, preIv.strideNode()); - + ValueNode newLimit = AddNode.add(preCounted.getStart(), preCounted.getCounter().strideNode(), NodeView.DEFAULT); // Fetch the variable we are not replacing and configure the one we are - ValueNode ub; - if (compareNode.getX() == prePhi) { - ub = compareNode.getY(); - } else if (compareNode.getY() == prePhi) { - ub = compareNode.getX(); + ValueNode ub = preCounted.getLimit(); + LogicNode entryCheck; + if (preCounted.getDirection() == Direction.Up) { + entryCheck = IntegerLessThanNode.create(newLimit, ub, NodeView.DEFAULT); } else { - throw GraalError.shouldNotReachHere(); + entryCheck = IntegerLessThanNode.create(ub, newLimit, NodeView.DEFAULT); } + newLimit = ConditionalNode.create(entryCheck, newLimit, ub, NodeView.DEFAULT); // Re-wire the condition with the new limit - if (preIv.direction() == Direction.Up) { - compareNode.replaceFirstInput(ub, graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(newLimit, ub)), newLimit, ub))); - } else { - compareNode.replaceFirstInput(ub, graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(ub, newLimit)), newLimit, ub))); - } + CompareNode compareNode = (CompareNode) preCounted.getLimitTest().condition(); + compareNode.replaceFirstInput(ub, compareNode.graph().addOrUniqueWithInputs(newLimit)); } public static List findUnswitchable(LoopEx loop) { @@ -450,6 +406,7 @@ public abstract class LoopTransformations { if (!loop.isCounted() || !loop.counted().getCounter().isConstantStride() || !loop.loop().getChildren().isEmpty()) { return false; } + assert loop.counted().getDirection() != null; LoopBeginNode loopBegin = loop.loopBegin(); LogicNode condition = loop.counted().getLimitTest().condition(); if (!(condition instanceof CompareNode)) { @@ -459,6 +416,13 @@ public abstract class LoopTransformations { condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s condition unsupported %s ", loopBegin, ((CompareNode) condition).condition()); return false; } + long stride = loop.counted().getCounter().constantStride(); + try { + Math.addExact(stride, stride); + } catch (ArithmeticException ae) { + condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s doubling the stride overflows %d", loopBegin, stride); + return false; + } if (loopBegin.isMainLoop() || loopBegin.isSimpleLoop()) { // Flow-less loops to partial unroll for now. 3 blocks corresponds to an if that either // exits or continues the loop. There might be fixed and floating work within the loop diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java index 6a72e84551..68ee5c5c55 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.test/src/org/graalvm/compiler/loop/test/LoopPartialUnrollTest.java @@ -83,7 +83,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { @Ignore("equality limits aren't working properly") @Test public void testSumWithEqualityLimit() { - for (int i = 0; i < 128; i++) { + for (int i = -1; i < 128; i++) { int[] data = new int[i]; test("sumWithEqualityLimit", data); } @@ -91,7 +91,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { @Test public void testLoopCarried() { - for (int i = 0; i < 64; i++) { + for (int i = -1; i < 64; i++) { test("testLoopCarriedSnippet", i); } } @@ -103,7 +103,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { static volatile int volatileInt = 3; - public int testLoopCarriedSnippet(int iterations) { + public static int testLoopCarriedSnippet(int iterations) { int a = 0; int b = 0; int c = 0; @@ -119,7 +119,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { return c; } - public int testLoopCarriedReference(int iterations) { + public static int testLoopCarriedReference(int iterations) { int a = 0; int b = 0; int c = 0; @@ -140,6 +140,37 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { return c; } + @Test + public void testLoopCarried2() { + for (int i = -1; i < 64; i++) { + for (int j = -1; j < 64; j++) { + test("testLoopCarried2Snippet", i, j); + } + } + test("testLoopCarried2Snippet", Integer.MAX_VALUE - 32, Integer.MAX_VALUE); + test("testLoopCarried2Snippet", Integer.MAX_VALUE - 4, Integer.MAX_VALUE); + test("testLoopCarried2Snippet", Integer.MAX_VALUE, 0); + test("testLoopCarried2Snippet", Integer.MIN_VALUE, Integer.MIN_VALUE + 32); + test("testLoopCarried2Snippet", Integer.MIN_VALUE, Integer.MIN_VALUE + 4); + test("testLoopCarried2Snippet", 0, Integer.MIN_VALUE); + } + + public static int testLoopCarried2Snippet(int start, int end) { + int a = 0; + int b = 0; + int c = 0; + + for (int i = start; branchProbability(0.99, i < end); i++) { + int t1 = volatileInt; + int t2 = a + b; + c = b; + b = a; + a = t1 + t2; + } + + return c; + } + public static long init = Runtime.getRuntime().totalMemory(); private int x; private int z; @@ -164,7 +195,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { @Test public void testComplex() { - for (int i = 0; i < 10; i++) { + for (int i = -1; i < 10; i++) { test("testComplexSnippet", i); } test("testComplexSnippet", 10); @@ -240,7 +271,7 @@ public class LoopPartialUnrollTest extends GraalCompilerTest { dataCounted.detectedCountedLoops(); for (LoopEx loop : dataCounted.countedLoops()) { LoopFragmentInside newSegment = loop.inside().duplicate(); - newSegment.insertWithinAfter(loop, false); + newSegment.insertWithinAfter(loop, null); } canonicalizer.apply(graph, getDefaultMidTierContext()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java index 67acbd01a8..ffa489b373 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java @@ -61,6 +61,7 @@ public class CountedLoopInfo { private IfNode ifNode; CountedLoopInfo(LoopEx loop, InductionVariable iv, IfNode ifNode, ValueNode end, boolean oneOff, AbstractBeginNode body) { + assert iv.direction() != null; this.loop = loop; this.iv = iv; this.end = end; @@ -157,6 +158,7 @@ public class CountedLoopInfo { range = endValue - iv.constantInit(); absStride = iv.constantStride(); } else { + assert iv.direction() == Direction.Down; if (initValue < endValue) { return 0; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java index d9248bd035..21a6154e2e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DefaultLoopPolicies.java @@ -75,7 +75,7 @@ public class DefaultLoopPolicies implements LoopPolicies { @Override public boolean shouldPeel(LoopEx loop, ControlFlowGraph cfg, MetaAccessProvider metaAccess) { LoopBeginNode loopBegin = loop.loopBegin(); - double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).probability(); + double entryProbability = cfg.blockFor(loopBegin.forwardEnd()).getRelativeFrequency(); OptionValues options = cfg.graph.getOptions(); if (entryProbability > MinimumPeelProbability.getValue(options) && loop.size() + loopBegin.graph().getNodeCount() < MaximumDesiredSize.getValue(options)) { // check whether we're allowed to peel this loop diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java index ca9b0ed5dd..9cb1662751 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/DerivedScaledInductionVariable.java @@ -63,13 +63,17 @@ public class DerivedScaledInductionVariable extends DerivedInductionVariable { @Override public Direction direction() { + Direction baseDirection = base.direction(); + if (baseDirection == null) { + return null; + } Stamp stamp = scale.stamp(NodeView.DEFAULT); if (stamp instanceof IntegerStamp) { IntegerStamp integerStamp = (IntegerStamp) stamp; if (integerStamp.isStrictlyPositive()) { - return base.direction(); + return baseDirection; } else if (integerStamp.isStrictlyNegative()) { - return base.direction().opposite(); + return baseDirection.opposite(); } } return null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java index ebbad1f5f8..e9f4bc8422 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java @@ -30,6 +30,7 @@ import java.util.List; import jdk.internal.vm.compiler.collections.EconomicMap; import jdk.internal.vm.compiler.collections.Equivalence; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; @@ -64,10 +65,15 @@ import org.graalvm.compiler.nodes.ValuePhiNode; import org.graalvm.compiler.nodes.VirtualState.NodeClosure; import org.graalvm.compiler.nodes.calc.AddNode; import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.SubNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.nodes.util.GraphUtil; +import jdk.vm.ci.code.CodeUtil; + public class LoopFragmentInside extends LoopFragment { /** @@ -150,20 +156,8 @@ public class LoopFragmentInside extends LoopFragment { /** * Duplicate the body within the loop after the current copy copy of the body, updating the * iteration limit to account for the duplication. - * - * @param loop */ - public void insertWithinAfter(LoopEx loop) { - insertWithinAfter(loop, true); - } - - /** - * Duplicate the body within the loop after the current copy copy of the body. - * - * @param loop - * @param updateLimit true if the iteration limit should be adjusted. - */ - public void insertWithinAfter(LoopEx loop, boolean updateLimit) { + public void insertWithinAfter(LoopEx loop, EconomicMap opaqueUnrolledStrides) { assert isDuplicate() && original().loop() == loop; patchNodes(dataFixWithinAfter); @@ -201,32 +195,43 @@ public class LoopFragmentInside extends LoopFragment { graph().removeFixed(safepoint); } - int unrollFactor = mainLoopBegin.getUnrollFactor(); StructuredGraph graph = mainLoopBegin.graph(); - if (updateLimit) { - // Now use the previous unrollFactor to update the exit condition to power of two - InductionVariable iv = loop.counted().getCounter(); - CompareNode compareNode = (CompareNode) loop.counted().getLimitTest().condition(); - ValueNode compareBound; - if (compareNode.getX() == iv.valueNode()) { - compareBound = compareNode.getY(); - } else if (compareNode.getY() == iv.valueNode()) { - compareBound = compareNode.getX(); + if (opaqueUnrolledStrides != null) { + OpaqueNode opaque = opaqueUnrolledStrides.get(loop.loopBegin()); + CountedLoopInfo counted = loop.counted(); + ValueNode counterStride = counted.getCounter().strideNode(); + if (opaque == null) { + opaque = new OpaqueNode(AddNode.add(counterStride, counterStride, NodeView.DEFAULT)); + ValueNode limit = counted.getLimit(); + int bits = ((IntegerStamp) limit.stamp(NodeView.DEFAULT)).getBits(); + ValueNode newLimit = SubNode.create(limit, opaque, NodeView.DEFAULT); + LogicNode overflowCheck; + ConstantNode extremum; + if (counted.getDirection() == InductionVariable.Direction.Up) { + // limit - counterStride could overflow negatively if limit - min < + // counterStride + extremum = ConstantNode.forIntegerBits(bits, CodeUtil.minValue(bits)); + overflowCheck = IntegerBelowNode.create(SubNode.create(limit, extremum, NodeView.DEFAULT), opaque, NodeView.DEFAULT); + } else { + assert counted.getDirection() == InductionVariable.Direction.Down; + // limit - counterStride could overflow if max - limit < -counterStride + // i.e., counterStride < limit - max + extremum = ConstantNode.forIntegerBits(bits, CodeUtil.maxValue(bits)); + overflowCheck = IntegerBelowNode.create(opaque, SubNode.create(limit, extremum, NodeView.DEFAULT), NodeView.DEFAULT); + } + newLimit = ConditionalNode.create(overflowCheck, extremum, newLimit, NodeView.DEFAULT); + CompareNode compareNode = (CompareNode) counted.getLimitTest().condition(); + compareNode.replaceFirstInput(limit, graph.addOrUniqueWithInputs(newLimit)); + opaqueUnrolledStrides.put(loop.loopBegin(), opaque); } else { - throw GraalError.shouldNotReachHere(); - } - long originalStride = unrollFactor == 1 ? iv.constantStride() : iv.constantStride() / unrollFactor; - if (iv.direction() == InductionVariable.Direction.Up) { - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(NodeView.DEFAULT), unrollFactor * originalStride)); - ValueNode newLimit = graph.addWithoutUnique(new SubNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); - } else if (iv.direction() == InductionVariable.Direction.Down) { - ConstantNode aboveVal = graph.unique(ConstantNode.forIntegerStamp(iv.initNode().stamp(NodeView.DEFAULT), unrollFactor * -originalStride)); - ValueNode newLimit = graph.addWithoutUnique(new AddNode(compareBound, aboveVal)); - compareNode.replaceFirstInput(compareBound, newLimit); + assert counted.getCounter().isConstantStride(); + assert Math.addExact(counted.getCounter().constantStride(), counted.getCounter().constantStride()) == counted.getCounter().constantStride() * 2; + ValueNode previousValue = opaque.getValue(); + opaque.setValue(graph.addOrUniqueWithInputs(AddNode.add(counterStride, previousValue, NodeView.DEFAULT))); + GraphUtil.tryKillUnused(previousValue); } } - mainLoopBegin.setUnrollFactor(unrollFactor * 2); + mainLoopBegin.setUnrollFactor(mainLoopBegin.getUnrollFactor() * 2); mainLoopBegin.setLoopFrequency(mainLoopBegin.loopFrequency() / 2); graph.getDebug().dump(DebugContext.DETAILED_LEVEL, graph, "LoopPartialUnroll %s", loop); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java index b19ad52f8a..81a6ed6077 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java @@ -129,7 +129,7 @@ public class GraphNodeProcessor extends AbstractProcessor { } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return false; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java index ef9356488f..ced7ccfc48 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java @@ -45,6 +45,8 @@ public abstract class AbstractBeginNode extends FixedWithNextNode implements LIR public static final NodeClass TYPE = NodeClass.create(AbstractBeginNode.class); + private boolean withSpeculationFence; + protected AbstractBeginNode(NodeClass c) { this(c, StampFactory.forVoid()); } @@ -91,7 +93,9 @@ public abstract class AbstractBeginNode extends FixedWithNextNode implements LIR @Override public void generate(NodeLIRBuilderTool gen) { - // nop + if (withSpeculationFence) { + gen.getLIRGeneratorTool().emitSpeculationFence(); + } } public NodeIterable guards() { @@ -112,6 +116,14 @@ public abstract class AbstractBeginNode extends FixedWithNextNode implements LIR }; } + /** + * Set this begin node to be a speculation fence. This will prevent speculative execution of + * this block. + */ + public void setWithSpeculationFence() { + this.withSpeculationFence = true; + } + private static class BlockNodeIterator implements Iterator { private FixedNode current; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Cancellable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Cancellable.java index 58bfe087fe..32c98b42f0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Cancellable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/Cancellable.java @@ -33,5 +33,8 @@ import org.graalvm.compiler.core.common.CancellationBailoutException; * {@link CancellationBailoutException}. */ public interface Cancellable { + /** + * Determines if this task has been cancelled. + */ boolean isCancelled(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java index d44de431cc..c294dbe9a8 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java @@ -905,23 +905,68 @@ public final class IfNode extends ControlSplitNode implements Simplifiable, LIRL double shortCutProbability = probability(trueSuccessor()); LogicNode newCondition = LogicNode.or(condition(), negateCondition, conditional.condition(), negateConditionalCondition, shortCutProbability); return graph().unique(new ConditionalNode(newCondition, constant, otherValue)); - } else if (!negateCondition && constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant()) { - IntegerLessThanNode lessThan = null; - IntegerEqualsNode equals = null; - if (condition() instanceof IntegerLessThanNode && conditional.condition() instanceof IntegerEqualsNode && constant.asJavaConstant().asLong() == -1 && - conditional.trueValue().asJavaConstant().asLong() == 0 && conditional.falseValue().asJavaConstant().asLong() == 1) { - lessThan = (IntegerLessThanNode) condition(); - equals = (IntegerEqualsNode) conditional.condition(); - } else if (condition() instanceof IntegerEqualsNode && conditional.condition() instanceof IntegerLessThanNode && constant.asJavaConstant().asLong() == 0 && - conditional.trueValue().asJavaConstant().asLong() == -1 && conditional.falseValue().asJavaConstant().asLong() == 1) { - lessThan = (IntegerLessThanNode) conditional.condition(); - equals = (IntegerEqualsNode) condition(); + } else if (constant.isJavaConstant() && conditional.trueValue().isJavaConstant() && conditional.falseValue().isJavaConstant() && condition() instanceof CompareNode && + conditional.condition() instanceof CompareNode) { + Condition cond1 = ((CompareNode) condition()).condition().asCondition(); + if (negateCondition) { + cond1 = cond1.negate(); } - if (lessThan != null) { - assert equals != null; - NodeView view = NodeView.from(tool); - if ((lessThan.getX() == equals.getX() && lessThan.getY() == equals.getY()) || (lessThan.getX() == equals.getY() && lessThan.getY() == equals.getX())) { - return graph().unique(new NormalizeCompareNode(lessThan.getX(), lessThan.getY(), conditional.trueValue().stamp(view).getStackKind(), false)); + // cond1 is EQ, NE, LT, or GE + Condition cond2 = ((CompareNode) conditional.condition()).condition().asCondition(); + ValueNode x = ((CompareNode) condition()).getX(); + ValueNode y = ((CompareNode) condition()).getY(); + ValueNode x2 = ((CompareNode) conditional.condition()).getX(); + ValueNode y2 = ((CompareNode) conditional.condition()).getY(); + // `x cond1 y ? c1 : (x2 cond2 y2 ? c2 : c3)` + boolean sameVars = x == x2 && y == y2; + if (!sameVars && x == y2 && y == x2) { + sameVars = true; + cond2 = cond2.mirror(); + } + // cond2 is EQ, LT, or GT + if (sameVars) { + JavaKind stackKind = conditional.trueValue().stamp(NodeView.from(tool)).getStackKind(); + assert !stackKind.isNumericFloat(); + long c1 = constant.asJavaConstant().asLong(); + long c2 = conditional.trueValue().asJavaConstant().asLong(); + long c3 = conditional.falseValue().asJavaConstant().asLong(); + // `x cond1 y ? c1 : (x cond2 y ? c2 : c3)` + if (cond1 == Condition.GE && cond2 == Condition.LT) { + // x >= y ? v1 : (x < y ? v2 : v3) => x >= y ? v1 : v2 + return graph().unique(new ConditionalNode(condition(), conditional.trueValue(), constant)); + } else if (cond1 == Condition.GE && cond2 == Condition.GT) { + // x >= y ? v1 : (x > y ? v2 : v3) => x >= y ? v1 : v3 + return graph().unique(new ConditionalNode(condition(), conditional.falseValue(), constant)); + } else if (cond1 == Condition.EQ && cond2 == Condition.EQ) { + // x == y ? v1 : (x == y ? v2 : v3) => x == y ? v1 : v3 + return graph().unique(new ConditionalNode(condition(), conditional.falseValue(), constant)); + } else if (cond1 == Condition.NE && cond2 == Condition.LT) { + // x != y ? v1 : (x < y ? v2 : v3) => x != y ? v1 : v3 + return graph().unique(new ConditionalNode(condition(), conditional.falseValue(), constant)); + } else if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == -1 && c2 == 0 && c3 == 1) { + // x < y ? -1 : (x == y ? 0 : 1) => x cmp y + return graph().unique(new NormalizeCompareNode(x, y, stackKind, false)); + } else if (cond1 == Condition.LT && cond2 == Condition.EQ && c1 == 1 && c2 == 0 && c3 == -1) { + // x < y ? 1 : (x == y ? 0 : -1) => y cmp x + return graph().unique(new NormalizeCompareNode(y, x, stackKind, false)); + } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == -1 && c3 == 1) { + // x == y ? 0 : (x < y ? -1 : 1) => x cmp y + return graph().unique(new NormalizeCompareNode(x, y, stackKind, false)); + } else if (cond1 == Condition.EQ && cond2 == Condition.LT && c1 == 0 && c2 == 1 && c3 == -1) { + // x == y ? 0 : (x < y ? 1 : -1) => y cmp x + return graph().unique(new NormalizeCompareNode(y, x, stackKind, false)); + } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == -1 && c3 == 1) { + // x == y ? 0 : (x > y ? -1 : 1) => y cmp x + return graph().unique(new NormalizeCompareNode(y, x, stackKind, false)); + } else if (cond1 == Condition.EQ && cond2 == Condition.GT && c1 == 0 && c2 == 1 && c3 == -1) { + // x == y ? 0 : (x > y ? 1 : -1) => x cmp y + return graph().unique(new NormalizeCompareNode(x, y, stackKind, false)); + } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == 1 && c2 == -1 && c3 == 0) { + // x < y ? 1 : (x > y ? -1 : 0) => y cmp x + return graph().unique(new NormalizeCompareNode(y, x, stackKind, false)); + } else if (cond1 == Condition.LT && cond2 == Condition.GT && c1 == -1 && c2 == 1 && c3 == 0) { + // x < y ? -1 : (x > y ? 1 : 0) => x cmp y + return graph().unique(new NormalizeCompareNode(x, y, stackKind, false)); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java index 90ceedd753..3c371fb306 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InvokeNode.java @@ -24,7 +24,19 @@ package org.graalvm.compiler.nodes; -import jdk.vm.ci.meta.JavaKind; +import static org.graalvm.compiler.nodeinfo.InputType.Extension; +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.InputType.State; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; + +import java.util.Map; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.Node; @@ -45,19 +57,7 @@ import org.graalvm.compiler.nodes.spi.UncheckedInterfaceProvider; import org.graalvm.compiler.nodes.util.GraphUtil; import jdk.internal.vm.compiler.word.LocationIdentity; -import java.util.Map; - -import static org.graalvm.compiler.nodeinfo.InputType.Extension; -import static org.graalvm.compiler.nodeinfo.InputType.Memory; -import static org.graalvm.compiler.nodeinfo.InputType.State; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_64; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; +import jdk.vm.ci.meta.JavaKind; /** * The {@code InvokeNode} represents all kinds of method calls. @@ -250,7 +250,10 @@ public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke @Override public NodeCycles estimatedNodeCycles() { - switch (callTarget().invokeKind()) { + if (callTarget == null) { + return CYCLES_UNKNOWN; + } + switch (callTarget.invokeKind()) { case Interface: return CYCLES_64; case Special: @@ -265,7 +268,10 @@ public final class InvokeNode extends AbstractMemoryCheckpoint implements Invoke @Override public NodeSize estimatedNodeSize() { - switch (callTarget().invokeKind()) { + if (callTarget == null) { + return SIZE_UNKNOWN; + } + switch (callTarget.invokeKind()) { case Interface: return SIZE_64; case Special: diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java index e765db6706..373b7cad9f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopEndNode.java @@ -27,7 +27,10 @@ package org.graalvm.compiler.nodes; import static org.graalvm.compiler.nodeinfo.InputType.Association; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN; import java.util.Collections; @@ -143,6 +146,9 @@ public final class LoopEndNode extends AbstractEndNode { @Override public NodeCycles estimatedNodeCycles() { + if (loopBegin() == null) { + return CYCLES_UNKNOWN; + } if (canSafepoint()) { // jmp+read return CYCLES_2; @@ -152,8 +158,11 @@ public final class LoopEndNode extends AbstractEndNode { @Override public NodeSize estimatedNodeSize() { + if (loopBegin() == null) { + return SIZE_UNKNOWN; + } if (canSafepoint()) { - return NodeSize.SIZE_2; + return SIZE_2; } return super.estimatedNodeSize(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java index 0a14d008a5..cc8f853b8f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java @@ -135,4 +135,8 @@ public class NamedLocationIdentity extends LocationIdentity implements FormatWit } return result; } + + public static boolean isArrayLocation(LocationIdentity l) { + return ARRAY_LOCATIONS.containsValue(l); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java index d770285939..8bcb6bd506 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java @@ -28,15 +28,22 @@ import static org.graalvm.compiler.nodeinfo.InputType.Condition; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; +import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.IterableNodeType; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Canonicalizable; import org.graalvm.compiler.graph.spi.CanonicalizerTool; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.calc.CompareNode; import org.graalvm.compiler.nodes.calc.IntegerBelowNode; import org.graalvm.compiler.nodes.calc.IntegerLessThanNode; +import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.meta.Assumptions; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.TriState; @NodeInfo(cycles = CYCLES_0, size = SIZE_0) @@ -57,6 +64,10 @@ public final class ShortCircuitOrNode extends LogicNode implements IterableNodeT this.shortCircuitProbability = shortCircuitProbability; } + public static LogicNode create(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, double shortCircuitProbability) { + return new ShortCircuitOrNode(x, xNegated, y, yNegated, shortCircuitProbability); + } + @Override public LogicNode getX() { return x; @@ -111,6 +122,7 @@ public final class ShortCircuitOrNode extends LogicNode implements IterableNodeT if (ret != this) { return ret; } + NodeView view = NodeView.from(tool); if (forX == forY) { // @formatter:off @@ -203,7 +215,7 @@ public final class ShortCircuitOrNode extends LogicNode implements IterableNodeT IntegerLessThanNode yNode = (IntegerLessThanNode) forY; ValueNode xxNode = xNode.getX(); // X >= 0 ValueNode yxNode = yNode.getX(); // X >= 0 - if (xxNode == yxNode && ((IntegerStamp) xxNode.stamp(NodeView.DEFAULT)).isPositive()) { + if (xxNode == yxNode && ((IntegerStamp) xxNode.stamp(view)).isPositive()) { ValueNode xyNode = xNode.getY(); // u ValueNode yyNode = yNode.getY(); // u if (xyNode == yyNode) { @@ -226,9 +238,92 @@ public final class ShortCircuitOrNode extends LogicNode implements IterableNodeT } } + if (forX instanceof CompareNode && forY instanceof CompareNode) { + CompareNode xCompare = (CompareNode) forX; + CompareNode yCompare = (CompareNode) forY; + + if (xCompare.getX() == yCompare.getX() || xCompare.getX() == yCompare.getY()) { + + Stamp succeedingStampX = xCompare.getSucceedingStampForX(!xNegated, xCompare.getX().stamp(view), xCompare.getY().stamp(view)); + // Try to canonicalize the other comparison using the knowledge gained from assuming + // the first part of the short circuit or is false (which is the only relevant case + // for the second part of the short circuit or). + if (succeedingStampX != null && !succeedingStampX.isUnrestricted()) { + CanonicalizerTool proxyTool = new ProxyCanonicalizerTool(succeedingStampX, xCompare.getX(), tool, view); + ValueNode result = yCompare.canonical(proxyTool); + if (result != yCompare) { + return ShortCircuitOrNode.create(forX, xNegated, (LogicNode) result, yNegated, this.shortCircuitProbability); + } + } + } + } + return this; } + private static class ProxyCanonicalizerTool implements CanonicalizerTool, NodeView { + + private final Stamp stamp; + private final ValueNode node; + private final CanonicalizerTool tool; + private final NodeView view; + + ProxyCanonicalizerTool(Stamp stamp, ValueNode node, CanonicalizerTool tool, NodeView view) { + this.stamp = stamp; + this.node = node; + this.tool = tool; + this.view = view; + } + + @Override + public Stamp stamp(ValueNode n) { + if (n == node) { + return stamp; + } + return view.stamp(n); + } + + @Override + public Assumptions getAssumptions() { + return tool.getAssumptions(); + } + + @Override + public MetaAccessProvider getMetaAccess() { + return tool.getMetaAccess(); + } + + @Override + public ConstantReflectionProvider getConstantReflection() { + return tool.getConstantReflection(); + } + + @Override + public ConstantFieldProvider getConstantFieldProvider() { + return tool.getConstantFieldProvider(); + } + + @Override + public boolean canonicalizeReads() { + return tool.canonicalizeReads(); + } + + @Override + public boolean allUsagesAvailable() { + return tool.allUsagesAvailable(); + } + + @Override + public Integer smallestCompareWidth() { + return tool.smallestCompareWidth(); + } + + @Override + public OptionValues getOptions() { + return tool.getOptions(); + } + } + private static LogicNode simplifyComparison(LogicNode forX, LogicNode forY) { LogicNode sym = simplifyComparisonOrdered(forX, forY); if (sym == null) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java index dfbda6b8f4..55d3bbb7d9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValueNode.java @@ -134,6 +134,11 @@ public abstract class ValueNode extends org.graalvm.compiler.graph.Node implemen return value != null && value.isNull(); } + public final boolean isDefaultConstant() { + Constant value = asConstant(); + return value != null && value.isDefaultForKind(); + } + /** * Convert this value to a constant if it is a constant, otherwise return null. * diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java index 5531a1e06b..47ed90d692 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/AddNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -27,6 +27,7 @@ package org.graalvm.compiler.nodes.calc; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; @@ -38,7 +39,9 @@ import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.Value; @NodeInfo(shortName = "+") @@ -99,6 +102,54 @@ public class AddNode extends BinaryArithmeticNode implements NarrowableArit return reassociated; } } + + // Attempt to optimize the pattern of an extend node between two add nodes. + if (c instanceof JavaConstant && (forX instanceof SignExtendNode || forX instanceof ZeroExtendNode)) { + IntegerConvertNode integerConvertNode = (IntegerConvertNode) forX; + ValueNode valueNode = integerConvertNode.getValue(); + long constant = ((JavaConstant) c).asLong(); + if (valueNode instanceof AddNode) { + AddNode addBeforeExtend = (AddNode) valueNode; + if (addBeforeExtend.getY().isConstant()) { + // There is a second add before the extend node that also has a constant as + // second operand. Therefore there will be canonicalizations triggered if we + // can move the add above the extension. For this we need to check whether + // the result of the addition is the same before the extension (which can be + // either zero extend or sign extend). + IntegerStamp beforeExtendStamp = (IntegerStamp) addBeforeExtend.stamp(view); + int bits = beforeExtendStamp.getBits(); + if (constant >= CodeUtil.minValue(bits) && constant <= CodeUtil.maxValue(bits)) { + IntegerStamp narrowConstantStamp = IntegerStamp.create(bits, constant, constant); + + if (!IntegerStamp.addCanOverflow(narrowConstantStamp, beforeExtendStamp)) { + ConstantNode constantNode = ConstantNode.forIntegerStamp(narrowConstantStamp, constant); + if (forX instanceof SignExtendNode) { + return SignExtendNode.create(AddNode.create(addBeforeExtend, constantNode, view), integerConvertNode.getResultBits(), view); + } else { + assert forX instanceof ZeroExtendNode; + + // Must check to not cross zero with the new add. + boolean crossesZeroPoint = true; + if (constant > 0) { + if (beforeExtendStamp.lowerBound() >= 0 || beforeExtendStamp.upperBound() < -constant) { + // We are good here. + crossesZeroPoint = false; + } + } else { + if (beforeExtendStamp.lowerBound() >= -constant || beforeExtendStamp.upperBound() < 0) { + // We are good here as well. + crossesZeroPoint = false; + } + } + if (!crossesZeroPoint) { + return ZeroExtendNode.create(AddNode.create(addBeforeExtend, constantNode, view), integerConvertNode.getResultBits(), view); + } + } + } + } + } + } + } } if (forX instanceof NegateNode) { return BinaryArithmeticNode.sub(forY, ((NegateNode) forX).getValue(), view); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java index 6b1f7bb10e..ab857e4e00 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/BinaryArithmeticNode.java @@ -32,6 +32,7 @@ import java.util.function.Function; import org.graalvm.compiler.core.common.type.ArithmeticOpTable; import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp; +import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Graph; @@ -133,6 +134,35 @@ public abstract class BinaryArithmeticNode extends BinaryNode implements Ari return SubNode.create(v1, v2, view); } + public static ValueNode branchlessMin(ValueNode v1, ValueNode v2, NodeView view) { + if (v1.isDefaultConstant() && !v2.isDefaultConstant()) { + return branchlessMin(v2, v1, view); + } + int bits = ((IntegerStamp) v1.stamp(view)).getBits(); + assert ((IntegerStamp) v2.stamp(view)).getBits() == bits; + ValueNode t1 = sub(v1, v2, view); + ValueNode t2 = RightShiftNode.create(t1, bits - 1, view); + ValueNode t3 = AndNode.create(t1, t2, view); + return add(v2, t3, view); + } + + public static ValueNode branchlessMax(ValueNode v1, ValueNode v2, NodeView view) { + if (v1.isDefaultConstant() && !v2.isDefaultConstant()) { + return branchlessMax(v2, v1, view); + } + int bits = ((IntegerStamp) v1.stamp(view)).getBits(); + assert ((IntegerStamp) v2.stamp(view)).getBits() == bits; + if (v2.isDefaultConstant()) { + // prefer a & ~(a>>31) to a - (a & (a>>31)) + return AndNode.create(v1, NotNode.create(RightShiftNode.create(v1, bits - 1, view)), view); + } else { + ValueNode t1 = sub(v1, v2, view); + ValueNode t2 = RightShiftNode.create(t1, bits - 1, view); + ValueNode t3 = AndNode.create(t1, t2, view); + return sub(v1, t3, view); + } + } + private enum ReassociateMatch { x, y; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java index 0e04daaf34..a6541fd29e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -136,15 +136,38 @@ public abstract class CompareNode extends BinaryOpLogicNode implements Canonical boolean supported = true; if (convertX.getValue().stamp(view) instanceof IntegerStamp) { IntegerStamp intStamp = (IntegerStamp) convertX.getValue().stamp(view); - supported = smallestCompareWidth != null && intStamp.getBits() >= smallestCompareWidth; + boolean isConversionCompatible = convertX.getClass() == convertY.getClass(); + supported = smallestCompareWidth != null && intStamp.getBits() >= smallestCompareWidth && isConversionCompatible; } if (supported) { - boolean multiUsage = (convertX.asNode().hasMoreThanOneUsage() || convertY.asNode().hasMoreThanOneUsage()); - if ((forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) && multiUsage) { - // Do not perform for zero or sign extend if there are multiple usages - // of the value. - return null; + + ValueNode xValue = convertX.getValue(); + ValueNode yValue = convertY.getValue(); + + if (forX instanceof ZeroExtendNode || forX instanceof SignExtendNode) { + + int introducedUsages = 0; + int eliminatedNodes = 0; + + if (convertX.asNode().hasExactlyOneUsage()) { + eliminatedNodes++; + } else if (xValue.hasExactlyOneUsage()) { + introducedUsages++; + } + + if (convertY.asNode().hasExactlyOneUsage()) { + eliminatedNodes++; + } else if (yValue.hasExactlyOneUsage()) { + introducedUsages++; + } + + if (introducedUsages > eliminatedNodes) { + // Only perform the optimization if there is + // a good trade-off between introduced new usages and + // eliminated nodes. + return null; + } } return duplicateModified(convertX.getValue(), convertY.getValue(), unorderedIsTrue, view); } @@ -175,7 +198,7 @@ public abstract class CompareNode extends BinaryOpLogicNode implements Canonical boolean supported = true; if (convert.getValue().stamp(view) instanceof IntegerStamp) { IntegerStamp intStamp = (IntegerStamp) convert.getValue().stamp(view); - supported = smallestCompareWidth != null && intStamp.getBits() > smallestCompareWidth; + supported = smallestCompareWidth != null && intStamp.getBits() >= smallestCompareWidth; } if (supported) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java index bade2d9262..8e0c7bb607 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java @@ -230,7 +230,7 @@ public final class ConditionalNode extends FloatingNode implements Canonicalizab * 1)))) to avoid the test. */ IntegerLessThanNode lt = (IntegerLessThanNode) condition; - if (lt.getY().isConstant() && lt.getY().asConstant().isDefaultForKind()) { + if (lt.getY().isDefaultConstant()) { if (falseValue == lt.getX()) { if (trueValue instanceof AddNode) { AddNode add = (AddNode) trueValue; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java index a8b755a720..cdfe52f9fc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java @@ -84,6 +84,24 @@ public final class IntegerBelowNode extends IntegerLowerThanNode { return new IntegerBelowNode(newX, newY); } + @Override + protected LogicNode findSynonym(ValueNode forX, ValueNode forY, NodeView view) { + LogicNode result = super.findSynonym(forX, forY, view); + if (result != null) { + return result; + } + if (forX.stamp(view) instanceof IntegerStamp) { + assert forY.stamp(view) instanceof IntegerStamp; + int bits = ((IntegerStamp) forX.stamp(view)).getBits(); + assert ((IntegerStamp) forY.stamp(view)).getBits() == bits; + LogicNode logic = canonicalizeRangeFlip(forX, forY, bits, false, view); + if (logic != null) { + return logic; + } + } + return null; + } + @Override protected long upperBound(IntegerStamp stamp) { return stamp.unsignedUpperBound(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java index 86e67696b0..e5187f2ef6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java @@ -199,7 +199,7 @@ public final class IntegerEqualsNode extends CompareNode implements BinaryCommut // execution // on specific platforms. return LogicNegationNode.create( - IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, nonConstant, ConstantNode.forIntegerKind(nonConstant.getStackKind(), 0), + IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, nonConstant, ConstantNode.forIntegerStamp(nonConstantStamp, 0), view)); } else if (primitiveConstant.asLong() == 0) { if (nonConstant instanceof AndNode) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java index a80218e7df..0fe622c44f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -47,7 +47,6 @@ import org.graalvm.compiler.options.OptionValues; import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.PrimitiveConstant; @@ -175,35 +174,58 @@ public final class IntegerLessThanNode extends IntegerLowerThanNode { return new IntegerBelowNode(forX, forY); } } - if (forY.isConstant() && forX instanceof SubNode) { - SubNode sub = (SubNode) forX; - ValueNode xx = null; - ValueNode yy = null; - boolean negate = false; - if (forY.asConstant().isDefaultForKind()) { - // (x - y) < 0 when x - y is known not to underflow <=> x < y - xx = sub.getX(); - yy = sub.getY(); - } else if (forY.isJavaConstant() && forY.asJavaConstant().asLong() == 1) { - // (x - y) < 1 when x - y is known not to underflow <=> !(y < x) - xx = sub.getY(); - yy = sub.getX(); - negate = true; - } - if (xx != null) { - assert yy != null; - IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp(view); - IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp(view); - long minValue = CodeUtil.minValue(xStamp.getBits()); - long maxValue = CodeUtil.maxValue(xStamp.getBits()); - if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) { - LogicNode logic = new IntegerLessThanNode(xx, yy); - if (negate) { - logic = LogicNegationNode.create(logic); - } - return logic; + // Attempt to optimize the case where we can fold a constant from the left side (either + // from an add or sub) into the constant on the right side. + if (forY.isConstant()) { + if (forX instanceof SubNode) { + SubNode sub = (SubNode) forX; + ValueNode xx = null; + ValueNode yy = null; + boolean negate = false; + if (forY.asConstant().isDefaultForKind()) { + // (x - y) < 0 when x - y is known not to underflow <=> x < y + xx = sub.getX(); + yy = sub.getY(); + } else if (forY.isJavaConstant() && forY.asJavaConstant().asLong() == 1) { + // (x - y) < 1 when x - y is known not to underflow <=> !(y < x) + xx = sub.getY(); + yy = sub.getX(); + negate = true; } + if (xx != null) { + assert yy != null; + IntegerStamp xStamp = (IntegerStamp) sub.getX().stamp(view); + IntegerStamp yStamp = (IntegerStamp) sub.getY().stamp(view); + long minValue = CodeUtil.minValue(xStamp.getBits()); + long maxValue = CodeUtil.maxValue(xStamp.getBits()); + + if (!subtractMayUnderflow(xStamp.lowerBound(), yStamp.upperBound(), minValue) && !subtractMayOverflow(xStamp.upperBound(), yStamp.lowerBound(), maxValue)) { + LogicNode logic = new IntegerLessThanNode(xx, yy); + if (negate) { + logic = LogicNegationNode.create(logic); + } + return logic; + } + } + } else if (forX instanceof AddNode) { + + // (x + xConstant) < forY => x < (forY - xConstant) + AddNode addNode = (AddNode) forX; + if (addNode.getY().isJavaConstant()) { + IntegerStamp xStamp = (IntegerStamp) addNode.getX().stamp(view); + if (!IntegerStamp.addCanOverflow(xStamp, (IntegerStamp) addNode.getY().stamp(view))) { + long minValue = CodeUtil.minValue(xStamp.getBits()); + long maxValue = CodeUtil.maxValue(xStamp.getBits()); + long yConstant = forY.asJavaConstant().asLong(); + long xConstant = addNode.getY().asJavaConstant().asLong(); + if (!subtractMayUnderflow(yConstant, xConstant, minValue) && !subtractMayOverflow(yConstant, xConstant, maxValue)) { + long newConstant = yConstant - xConstant; + return IntegerLessThanNode.create(addNode.getX(), ConstantNode.forIntegerStamp(xStamp, newConstant), view); + } + } + } + } } @@ -211,49 +233,9 @@ public final class IntegerLessThanNode extends IntegerLowerThanNode { assert forY.stamp(view) instanceof IntegerStamp; int bits = ((IntegerStamp) forX.stamp(view)).getBits(); assert ((IntegerStamp) forY.stamp(view)).getBits() == bits; - long min = OP.minValue(bits); - long xResidue = 0; - ValueNode left = null; - JavaConstant leftCst = null; - if (forX instanceof AddNode) { - AddNode xAdd = (AddNode) forX; - if (xAdd.getY().isJavaConstant()) { - long xCst = xAdd.getY().asJavaConstant().asLong(); - xResidue = xCst - min; - left = xAdd.getX(); - } - } else if (forX.isJavaConstant()) { - leftCst = forX.asJavaConstant(); - } - if (left != null || leftCst != null) { - long yResidue = 0; - ValueNode right = null; - JavaConstant rightCst = null; - if (forY instanceof AddNode) { - AddNode yAdd = (AddNode) forY; - if (yAdd.getY().isJavaConstant()) { - long yCst = yAdd.getY().asJavaConstant().asLong(); - yResidue = yCst - min; - right = yAdd.getX(); - } - } else if (forY.isJavaConstant()) { - rightCst = forY.asJavaConstant(); - } - if (right != null || rightCst != null) { - if ((xResidue == 0 && left != null) || (yResidue == 0 && right != null)) { - if (left == null) { - left = ConstantNode.forIntegerBits(bits, leftCst.asLong() - min); - } else if (xResidue != 0) { - left = AddNode.create(left, ConstantNode.forIntegerBits(bits, xResidue), view); - } - if (right == null) { - right = ConstantNode.forIntegerBits(bits, rightCst.asLong() - min); - } else if (yResidue != 0) { - right = AddNode.create(right, ConstantNode.forIntegerBits(bits, yResidue), view); - } - return new IntegerBelowNode(left, right); - } - } + LogicNode logic = canonicalizeRangeFlip(forX, forY, bits, true, view); + if (logic != null) { + return logic; } } return null; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java index 61ee1c0645..c7e28991f0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -40,7 +40,9 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.options.OptionValues; +import jdk.vm.ci.code.CodeUtil; import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.TriState; @@ -89,7 +91,7 @@ public abstract class IntegerLowerThanNode extends CompareNode { aStamp = (IntegerStamp) addNode.getX().stamp(NodeView.DEFAULT); } if (aStamp != null) { - IntegerStamp result = getOp().getSucceedingStampForXLowerXPlusA(mirror, strict, aStamp); + IntegerStamp result = getOp().getSucceedingStampForXLowerXPlusA(mirror, strict, aStamp, xStamp); result = (IntegerStamp) xStamp.tryImproveWith(result); if (result != null) { if (s != null) { @@ -185,7 +187,8 @@ public abstract class IntegerLowerThanNode extends CompareNode { if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { return LogicConstantNode.contradiction(); } - TriState fold = tryFold(forX.stamp(view), forY.stamp(view)); + Stamp xStampGeneric = forX.stamp(view); + TriState fold = tryFold(xStampGeneric, forY.stamp(view)); if (fold.isTrue()) { return LogicConstantNode.tautology(); } else if (fold.isFalse()) { @@ -193,6 +196,7 @@ public abstract class IntegerLowerThanNode extends CompareNode { } if (forY.stamp(view) instanceof IntegerStamp) { IntegerStamp yStamp = (IntegerStamp) forY.stamp(view); + IntegerStamp xStamp = (IntegerStamp) xStampGeneric; int bits = yStamp.getBits(); if (forX.isJavaConstant() && !forY.isConstant()) { // bring the constant on the right @@ -204,14 +208,23 @@ public abstract class IntegerLowerThanNode extends CompareNode { } if (forY.isJavaConstant()) { long yValue = forY.asJavaConstant().asLong(); + + // x < MAX <=> x != MAX if (yValue == maxValue(bits)) { - // x < MAX <=> x != MAX return LogicNegationNode.create(IntegerEqualsNode.create(forX, forY, view)); } + + // x < MIN + 1 <=> x <= MIN <=> x == MIN if (yValue == minValue(bits) + 1) { - // x < MIN + 1 <=> x <= MIN <=> x == MIN return IntegerEqualsNode.create(forX, ConstantNode.forIntegerStamp(yStamp, minValue(bits)), view); } + + // (x < c && x >= c - 1) => x == c - 1 + // If the constant is negative, only signed comparison is allowed. + if (yValue != minValue(bits) && xStamp.lowerBound() == yValue - 1 && (yValue > 0 || getCondition() == CanonicalCondition.LT)) { + return IntegerEqualsNode.create(forX, ConstantNode.forIntegerStamp(yStamp, yValue - 1), view); + } + } else if (forY instanceof AddNode) { AddNode addNode = (AddNode) forY; LogicNode canonical = canonicalizeXLowerXPlusA(forX, addNode, false, true, view); @@ -230,17 +243,83 @@ public abstract class IntegerLowerThanNode extends CompareNode { return null; } + /** + * Exploit the fact that adding the (signed) MIN_VALUE on both side flips signed and + * unsigned comparison. + * + * In particular: + *
    + *
  • {@code x + MIN_VALUE < y + MIN_VALUE <=> x |<| y}
  • + *
  • {@code x + MIN_VALUE |<| y + MIN_VALUE <=> x < y}
  • + *
+ */ + protected static LogicNode canonicalizeRangeFlip(ValueNode forX, ValueNode forY, int bits, boolean signed, NodeView view) { + long min = CodeUtil.minValue(bits); + long xResidue = 0; + ValueNode left = null; + JavaConstant leftCst = null; + if (forX instanceof AddNode) { + AddNode xAdd = (AddNode) forX; + if (xAdd.getY().isJavaConstant() && !xAdd.getY().asJavaConstant().isDefaultForKind()) { + long xCst = xAdd.getY().asJavaConstant().asLong(); + xResidue = xCst - min; + left = xAdd.getX(); + } + } else if (forX.isJavaConstant()) { + leftCst = forX.asJavaConstant(); + } + if (left == null && leftCst == null) { + return null; + } + long yResidue = 0; + ValueNode right = null; + JavaConstant rightCst = null; + if (forY instanceof AddNode) { + AddNode yAdd = (AddNode) forY; + if (yAdd.getY().isJavaConstant() && !yAdd.getY().asJavaConstant().isDefaultForKind()) { + long yCst = yAdd.getY().asJavaConstant().asLong(); + yResidue = yCst - min; + right = yAdd.getX(); + } + } else if (forY.isJavaConstant()) { + rightCst = forY.asJavaConstant(); + } + if (right == null && rightCst == null) { + return null; + } + if ((xResidue == 0 && left != null) || (yResidue == 0 && right != null)) { + if (left == null) { + left = ConstantNode.forIntegerBits(bits, leftCst.asLong() - min); + } else if (xResidue != 0) { + left = AddNode.create(left, ConstantNode.forIntegerBits(bits, xResidue), view); + } + if (right == null) { + right = ConstantNode.forIntegerBits(bits, rightCst.asLong() - min); + } else if (yResidue != 0) { + right = AddNode.create(right, ConstantNode.forIntegerBits(bits, yResidue), view); + } + if (signed) { + return new IntegerBelowNode(left, right); + } else { + return new IntegerLessThanNode(left, right); + } + } + return null; + } + private LogicNode canonicalizeXLowerXPlusA(ValueNode forX, AddNode addNode, boolean mirrored, boolean strict, NodeView view) { // x < x + a + // x |<| x + a + IntegerStamp xStamp = (IntegerStamp) forX.stamp(view); IntegerStamp succeedingXStamp; boolean exact; if (addNode.getX() == forX && addNode.getY().stamp(view) instanceof IntegerStamp) { IntegerStamp aStamp = (IntegerStamp) addNode.getY().stamp(view); - succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp); + succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp, xStamp); exact = aStamp.lowerBound() == aStamp.upperBound(); } else if (addNode.getY() == forX && addNode.getX().stamp(view) instanceof IntegerStamp) { IntegerStamp aStamp = (IntegerStamp) addNode.getX().stamp(view); - succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp); + succeedingXStamp = getSucceedingStampForXLowerXPlusA(mirrored, strict, aStamp, xStamp); exact = aStamp.lowerBound() == aStamp.upperBound(); } else { return null; @@ -250,7 +329,6 @@ public abstract class IntegerLowerThanNode extends CompareNode { } else if (exact && !succeedingXStamp.isEmpty()) { int bits = succeedingXStamp.getBits(); if (compare(lowerBound(succeedingXStamp), minValue(bits)) > 0) { - assert upperBound(succeedingXStamp) == maxValue(bits); // x must be in [L..MAX] <=> x >= L <=> !(x < L) return LogicNegationNode.create(create(forX, ConstantNode.forIntegerStamp(succeedingXStamp, lowerBound(succeedingXStamp)), view)); } else if (compare(upperBound(succeedingXStamp), maxValue(bits)) < 0) { @@ -305,10 +383,11 @@ public abstract class IntegerLowerThanNode extends CompareNode { return null; } - protected IntegerStamp getSucceedingStampForXLowerXPlusA(boolean mirrored, boolean strict, IntegerStamp a) { - int bits = a.getBits(); + protected IntegerStamp getSucceedingStampForXLowerXPlusA(boolean mirrored, boolean strict, IntegerStamp aStamp, IntegerStamp xStamp) { + int bits = aStamp.getBits(); long min = minValue(bits); long max = maxValue(bits); + /* * if x < x + a <=> x + a didn't overflow: * @@ -324,14 +403,14 @@ public abstract class IntegerLowerThanNode extends CompareNode { * addition not the comparison. */ if (mirrored) { - if (a.contains(0)) { + if (aStamp.contains(0)) { // a may be zero - return a.unrestricted(); + return aStamp.unrestricted(); } - return forInteger(bits, min(max - a.lowerBound() + 1, max - a.upperBound() + 1, bits), max); + return forInteger(bits, min(max - aStamp.lowerBound() + 1, max - aStamp.upperBound() + 1, bits), min(max, upperBound(xStamp))); } else { - long aLower = a.lowerBound(); - long aUpper = a.upperBound(); + long aLower = aStamp.lowerBound(); + long aUpper = aStamp.upperBound(); if (strict) { if (aLower == 0) { aLower = 1; @@ -341,12 +420,12 @@ public abstract class IntegerLowerThanNode extends CompareNode { } if (aLower > aUpper) { // impossible - return a.empty(); + return aStamp.empty(); } } if (aLower < 0 && aUpper > 0) { // a may be zero - return a.unrestricted(); + return aStamp.unrestricted(); } return forInteger(bits, min, max(max - aLower, max - aUpper, bits)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java index fd1b6506bc..c21ea0b9df 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NegateNode.java @@ -71,6 +71,8 @@ public final class NegateNode extends UnaryArithmeticNode implements Narrow protected static ValueNode findSynonym(ValueNode forValue, NodeView view) { ArithmeticOpTable.UnaryOp negOp = ArithmeticOpTable.forStamp(forValue.stamp(view)).getNeg(); + + // Folds constants ValueNode synonym = UnaryArithmeticNode.findSynonym(forValue, negOp); if (synonym != null) { return synonym; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java index bd9e6067f2..0f0ef8f621 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.LogicConstantNode; import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.extended.GetClassNode; import org.graalvm.compiler.nodes.java.InstanceOfNode; @@ -125,39 +126,37 @@ public final class ObjectEqualsNode extends PointerEqualsNode implements Virtual } } - private void virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, VirtualizerTool tool) { + private static LogicNode virtualizeNonVirtualComparison(VirtualObjectNode virtual, ValueNode other, StructuredGraph graph, VirtualizerTool tool) { if (virtual instanceof VirtualBoxingNode && other.isConstant()) { VirtualBoxingNode virtualBoxingNode = (VirtualBoxingNode) virtual; if (virtualBoxingNode.getBoxingKind() == JavaKind.Boolean) { - JavaConstant otherUnboxed = tool.getConstantReflectionProvider().unboxPrimitive(other.asJavaConstant()); + JavaConstant otherUnboxed = tool.getConstantReflection().unboxPrimitive(other.asJavaConstant()); if (otherUnboxed != null && otherUnboxed.getJavaKind() == JavaKind.Boolean) { int expectedValue = otherUnboxed.asBoolean() ? 1 : 0; - IntegerEqualsNode equals = new IntegerEqualsNode(virtualBoxingNode.getBoxedValue(tool), ConstantNode.forInt(expectedValue, graph())); - tool.addNode(equals); - tool.replaceWithValue(equals); + return new IntegerEqualsNode(virtualBoxingNode.getBoxedValue(tool), ConstantNode.forInt(expectedValue, graph)); } else { - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + return LogicConstantNode.contradiction(graph); } } } if (virtual.hasIdentity()) { // one of them is virtual: they can never be the same objects - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + return LogicConstantNode.contradiction(graph); } + return null; } - @Override - public void virtualize(VirtualizerTool tool) { - ValueNode xAlias = tool.getAlias(getX()); - ValueNode yAlias = tool.getAlias(getY()); + public static LogicNode virtualizeComparison(ValueNode x, ValueNode y, StructuredGraph graph, VirtualizerTool tool) { + ValueNode xAlias = tool.getAlias(x); + ValueNode yAlias = tool.getAlias(y); VirtualObjectNode xVirtual = xAlias instanceof VirtualObjectNode ? (VirtualObjectNode) xAlias : null; VirtualObjectNode yVirtual = yAlias instanceof VirtualObjectNode ? (VirtualObjectNode) yAlias : null; if (xVirtual != null && yVirtual == null) { - virtualizeNonVirtualComparison(xVirtual, yAlias, tool); + return virtualizeNonVirtualComparison(xVirtual, yAlias, graph, tool); } else if (xVirtual == null && yVirtual != null) { - virtualizeNonVirtualComparison(yVirtual, xAlias, tool); + return virtualizeNonVirtualComparison(yVirtual, xAlias, graph, tool); } else if (xVirtual != null && yVirtual != null) { if (xVirtual.hasIdentity() ^ yVirtual.hasIdentity()) { /* @@ -167,24 +166,35 @@ public final class ObjectEqualsNode extends PointerEqualsNode implements Virtual * In other words: an object created via valueOf can never be equal to one created * by new in the same compilation unit. */ - tool.replaceWithValue(LogicConstantNode.contradiction(graph())); + return LogicConstantNode.contradiction(graph); } else if (!xVirtual.hasIdentity() && !yVirtual.hasIdentity()) { ResolvedJavaType type = xVirtual.type(); if (type.equals(yVirtual.type())) { - MetaAccessProvider metaAccess = tool.getMetaAccessProvider(); + MetaAccessProvider metaAccess = tool.getMetaAccess(); if (type.equals(metaAccess.lookupJavaType(Integer.class)) || type.equals(metaAccess.lookupJavaType(Long.class))) { // both are virtual without identity: check contents assert xVirtual.entryCount() == 1 && yVirtual.entryCount() == 1; assert xVirtual.entryKind(0).getStackKind() == JavaKind.Int || xVirtual.entryKind(0) == JavaKind.Long; - IntegerEqualsNode equals = new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0)); - tool.addNode(equals); - tool.replaceWithValue(equals); + return new IntegerEqualsNode(tool.getEntry(xVirtual, 0), tool.getEntry(yVirtual, 0)); } } } else { // both are virtual with identity: check if they refer to the same object - tool.replaceWithValue(LogicConstantNode.forBoolean(xVirtual == yVirtual, graph())); + return LogicConstantNode.forBoolean(xVirtual == yVirtual, graph); } } + return null; + } + + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode node = virtualizeComparison(getX(), getY(), graph(), tool); + if (node == null) { + return; + } + if (!node.isAlive()) { + tool.addNode(node); + } + tool.replaceWithValue(node); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java index 07cf345c4c..30083bb6d2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/RightShiftNode.java @@ -48,6 +48,13 @@ public final class RightShiftNode extends ShiftNode { super(TYPE, ArithmeticOpTable::getShr, x, y); } + public static ValueNode create(ValueNode x, int y, NodeView view) { + if (y == 0) { + return x; + } + return create(x, ConstantNode.forInt(y), view); + } + public static ValueNode create(ValueNode x, ValueNode y, NodeView view) { ArithmeticOpTable.ShiftOp op = ArithmeticOpTable.forStamp(x.stamp(view)).getShr(); Stamp stamp = op.foldStamp(x.stamp(view), (IntegerStamp) y.stamp(view)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnpackEndianHalfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnpackEndianHalfNode.java index 5ab074a320..af68c601b0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnpackEndianHalfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnpackEndianHalfNode.java @@ -69,7 +69,7 @@ public final class UnpackEndianHalfNode extends UnaryNode implements Lowerable { @Override public Node canonical(CanonicalizerTool tool, ValueNode forValue) { - if (forValue.isConstant() && forValue.asConstant().isDefaultForKind()) { + if (forValue.isDefaultConstant()) { return ConstantNode.defaultForKind(stamp.getStackKind()); } return this; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java index e19b0182d0..01607ccac3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java @@ -50,7 +50,7 @@ public final class Block extends AbstractBlockBase { protected FixedNode endNode; - protected double probability; + protected double relativeFrequency; private Loop loop; protected Block postdominator; @@ -236,14 +236,18 @@ public final class Block extends AbstractBlockBase { return sb.toString(); } + /** + * The execution frequency of this block relative to the start block as estimated by the + * profiling information. + */ @Override - public double probability() { - return probability; + public double getRelativeFrequency() { + return relativeFrequency; } - public void setProbability(double probability) { - assert probability >= 0 && Double.isFinite(probability); - this.probability = probability; + public void setRelativeFrequency(double relativeFrequency) { + assert relativeFrequency >= 0 && Double.isFinite(relativeFrequency); + this.relativeFrequency = relativeFrequency; } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java index df7013c168..f86b829a27 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/ControlFlowGraph.java @@ -53,14 +53,14 @@ import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; public final class ControlFlowGraph implements AbstractControlFlowGraph { /** - * Don't allow probability values to be become too small or too high as this makes frequency - * calculations over- or underflow the range of a double. This commonly happens with infinite - * loops within infinite loops. The value is chosen a bit lower than half the maximum exponent - * supported by double. That way we can never overflow to infinity when multiplying two - * probability values. + * Don't allow relative frequency values to be become too small or too high as this makes + * frequency calculations over- or underflow the range of a double. This commonly happens with + * infinite loops within infinite loops. The value is chosen a bit lower than half the maximum + * exponent supported by double. That way we can never overflow to infinity when multiplying two + * relative frequency values. */ - public static final double MIN_PROBABILITY = 0x1.0p-500; - public static final double MAX_PROBABILITY = 1 / MIN_PROBABILITY; + public static final double MIN_RELATIVE_FREQUENCY = 0x1.0p-500; + public static final double MAX_RELATIVE_FREQUENCY = 1 / MIN_RELATIVE_FREQUENCY; public final StructuredGraph graph; @@ -78,7 +78,7 @@ public final class ControlFlowGraph implements AbstractControlFlowGraph { public static ControlFlowGraph compute(StructuredGraph graph, boolean connectBlocks, boolean computeLoops, boolean computeDominators, boolean computePostdominators) { ControlFlowGraph cfg = new ControlFlowGraph(graph); cfg.identifyBlocks(); - cfg.computeProbabilities(); + cfg.computeFrequencies(); if (computeLoops) { cfg.computeLoopInformation(); @@ -424,7 +424,7 @@ public final class ControlFlowGraph implements AbstractControlFlowGraph { private void identifyBlock(Block block) { FixedWithNextNode cur = block.getBeginNode(); while (true) { - assert !cur.isDeleted(); + assert cur.isAlive() : cur; assert nodeToBlock.get(cur) == null; nodeToBlock.set(cur, block); FixedNode next = cur.next(); @@ -550,39 +550,44 @@ public final class ControlFlowGraph implements AbstractControlFlowGraph { block.setPredecessors(predecessors); } - private void computeProbabilities() { + /** + * Computes the frequencies of all blocks relative to the start block. It uses the probability + * information attached to control flow splits to calculate the frequency of a block based on + * the frequency of its predecessor and the probability of its incoming control flow branch. + */ + private void computeFrequencies() { for (Block block : reversePostOrder) { Block[] predecessors = block.getPredecessors(); - double probability; + double relativeFrequency; if (predecessors.length == 0) { - probability = 1D; + relativeFrequency = 1D; } else if (predecessors.length == 1) { Block pred = predecessors[0]; - probability = pred.probability; + relativeFrequency = pred.relativeFrequency; if (pred.getSuccessorCount() > 1) { assert pred.getEndNode() instanceof ControlSplitNode; ControlSplitNode controlSplit = (ControlSplitNode) pred.getEndNode(); - probability = multiplyProbabilities(probability, controlSplit.probability(block.getBeginNode())); + relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, controlSplit.probability(block.getBeginNode())); } } else { - probability = predecessors[0].probability; + relativeFrequency = predecessors[0].relativeFrequency; for (int i = 1; i < predecessors.length; ++i) { - probability += predecessors[i].probability; + relativeFrequency += predecessors[i].relativeFrequency; } if (block.getBeginNode() instanceof LoopBeginNode) { LoopBeginNode loopBegin = (LoopBeginNode) block.getBeginNode(); - probability = multiplyProbabilities(probability, loopBegin.loopFrequency()); + relativeFrequency = multiplyRelativeFrequencies(relativeFrequency, loopBegin.loopFrequency()); } } - if (probability < MIN_PROBABILITY) { - probability = MIN_PROBABILITY; - } else if (probability > MAX_PROBABILITY) { - probability = MAX_PROBABILITY; + if (relativeFrequency < MIN_RELATIVE_FREQUENCY) { + relativeFrequency = MIN_RELATIVE_FREQUENCY; + } else if (relativeFrequency > MAX_RELATIVE_FREQUENCY) { + relativeFrequency = MAX_RELATIVE_FREQUENCY; } - block.setProbability(probability); + block.setRelativeFrequency(relativeFrequency); } } @@ -763,17 +768,17 @@ public final class ControlFlowGraph implements AbstractControlFlowGraph { } /** - * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_PROBABILITY} and - * {@link ControlFlowGraph#MAX_PROBABILITY}. + * Multiplies a and b and clamps the between {@link ControlFlowGraph#MIN_RELATIVE_FREQUENCY} and + * {@link ControlFlowGraph#MAX_RELATIVE_FREQUENCY}. */ - public static double multiplyProbabilities(double a, double b) { + public static double multiplyRelativeFrequencies(double a, double b) { assert !Double.isNaN(a) && !Double.isNaN(b) && Double.isFinite(a) && Double.isFinite(b) : a + " " + b; double r = a * b; - if (r > MAX_PROBABILITY) { - return MAX_PROBABILITY; + if (r > MAX_RELATIVE_FREQUENCY) { + return MAX_RELATIVE_FREQUENCY; } - if (r < MIN_PROBABILITY) { - return MIN_PROBABILITY; + if (r < MIN_RELATIVE_FREQUENCY) { + return MIN_RELATIVE_FREQUENCY; } return r; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java index dd169ab9d9..90817af881 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/DynamicCounterNode.java @@ -68,12 +68,35 @@ public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerabl this(TYPE, group, name, increment, withContext); } + public static final long MIN_INCREMENT = 0; + public static final long MAX_INCREMENT = 10_000; + + /** + * Clamps {@code value} to a value between {@link #MIN_INCREMENT} and {@link #MAX_INCREMENT}. + * This mitigates the possibility of overflowing benchmark counters. + */ + public static long clampIncrement(long value) { + return Math.min(Math.max(value, MIN_INCREMENT), MAX_INCREMENT); + } + + private boolean checkIncrement() { + if (increment.isJavaConstant()) { + long incValue = increment.asJavaConstant().asLong(); + if (incValue < MIN_INCREMENT || incValue > MAX_INCREMENT) { + String message = String.format("Benchmark counter %s:%s has increment out of range [%d .. %d]: %d", group, getNameWithContext(), MIN_INCREMENT, MAX_INCREMENT, incValue); + assert false : message; + } + } + return true; + } + protected DynamicCounterNode(NodeClass c, String group, String name, ValueNode increment, boolean withContext) { super(c, StampFactory.forVoid()); this.group = group; this.name = name; this.increment = increment; this.withContext = withContext; + assert checkIncrement(); } public ValueNode getIncrement() { @@ -103,6 +126,16 @@ public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerabl @Override public void generate(NodeLIRBuilderTool generator) { LIRGeneratorTool lirGen = generator.getLIRGeneratorTool(); + String nameWithContext = getNameWithContext(); + LIRInstruction counterOp = lirGen.createBenchmarkCounter(nameWithContext, getGroup(), generator.operand(increment)); + if (counterOp != null) { + lirGen.append(counterOp); + } else { + throw GraalError.unimplemented("Benchmark counters not enabled or not implemented by the back end."); + } + } + + private String getNameWithContext() { String nameWithContext; if (isWithContext()) { nameWithContext = getName() + " @ "; @@ -121,12 +154,6 @@ public class DynamicCounterNode extends FixedWithNextNode implements LIRLowerabl } else { nameWithContext = getName(); } - LIRInstruction counterOp = lirGen.createBenchmarkCounter(nameWithContext, getGroup(), generator.operand(increment)); - if (counterOp != null) { - lirGen.append(counterOp); - } else { - throw GraalError.unimplemented("Benchmark counters not enabled or not implemented by the back end."); - } + return nameWithContext; } - } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java index 339e2a461f..0f11a76072 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java @@ -93,8 +93,8 @@ public final class GetClassNode extends FloatingNode implements Lowerable, Canon ValueNode alias = tool.getAlias(getObject()); if (alias instanceof VirtualObjectNode) { VirtualObjectNode virtual = (VirtualObjectNode) alias; - Constant javaClass = tool.getConstantReflectionProvider().asJavaClass(virtual.type()); - tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), javaClass, tool.getMetaAccessProvider(), graph())); + Constant javaClass = tool.getConstantReflection().asJavaClass(virtual.type()); + tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), javaClass, tool.getMetaAccess(), graph())); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java index a3aaef281d..6b5d9bb883 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadHubNode.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.nodes.extended; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; - import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; @@ -121,7 +120,7 @@ public final class LoadHubNode extends FloatingNode implements Lowerable, Canoni ValueNode alias = tool.getAlias(getValue()); TypeReference type = StampTool.typeReferenceOrNull(alias); if (type != null && type.isExact()) { - tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflectionProvider().asObjectHub(type.getType()), tool.getMetaAccessProvider(), graph())); + tool.replaceWithValue(ConstantNode.forConstant(stamp(NodeView.DEFAULT), tool.getConstantReflection().asObjectHub(type.getType()), tool.getMetaAccess(), graph())); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MultiGuardNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MultiGuardNode.java new file mode 100644 index 0000000000..052ae77d18 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/MultiGuardNode.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.nodes.extended; + +import static org.graalvm.compiler.nodeinfo.InputType.Guard; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.graph.spi.Simplifiable; +import org.graalvm.compiler.graph.spi.SimplifierTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.FloatingNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import org.graalvm.compiler.nodes.util.GraphUtil; + +@NodeInfo(allowedUsageTypes = Guard, cycles = CYCLES_0, size = SIZE_0) +public final class MultiGuardNode extends FloatingNode implements GuardingNode, LIRLowerable, Simplifiable, Node.ValueNumberable { + public static final NodeClass TYPE = NodeClass.create(MultiGuardNode.class); + + @OptionalInput(Guard) NodeInputList guards; + + public MultiGuardNode(ValueNode... guards) { + super(TYPE, StampFactory.forVoid()); + this.guards = new NodeInputList<>(this, guards); + } + + @Override + public void generate(NodeLIRBuilderTool generator) { + } + + @Override + public void simplify(SimplifierTool tool) { + if (usages().filter(node -> node instanceof ValueAnchorNode).isNotEmpty()) { + /* + * For ValueAnchorNode usages, we can optimize MultiGuardNodes away if they depend on + * zero or one floating nodes (as opposed to fixed nodes). + */ + Node singleFloatingGuard = null; + for (ValueNode guard : guards) { + if (GraphUtil.isFloatingNode(guard)) { + if (singleFloatingGuard == null) { + singleFloatingGuard = guard; + } else if (singleFloatingGuard != guard) { + return; + } + } + } + for (Node usage : usages().snapshot()) { + if (usage instanceof ValueAnchorNode) { + usage.replaceFirstInput(this, singleFloatingGuard); + tool.addToWorkList(usage); + } + } + if (usages().isEmpty()) { + GraphUtil.killWithUnusedFloatingInputs(this); + } + } + } + + public void addGuard(GuardingNode g) { + this.guards.add(g.asNode()); + } + + public static GuardingNode combine(GuardingNode first, GuardingNode second) { + if (first == null) { + return second; + } else if (second == null) { + return first; + } else { + StructuredGraph graph = first.asNode().graph(); + return graph.unique(new MultiGuardNode(first.asNode(), second.asNode())); + } + } + + public static GuardingNode addGuard(GuardingNode first, GuardingNode second) { + if (first instanceof MultiGuardNode && second != null) { + MultiGuardNode multi = (MultiGuardNode) first; + multi.addGuard(second); + return multi; + } else { + return combine(first, second); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OpaqueNode.java similarity index 88% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OpaqueNode.java index 2e5048bba7..c967f097c0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OpaqueNode.java @@ -22,7 +22,7 @@ */ -package org.graalvm.compiler.nodes.debug; +package org.graalvm.compiler.nodes.extended; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; @@ -37,9 +37,10 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; @NodeInfo(cycles = CYCLES_0, size = SIZE_0) public final class OpaqueNode extends FloatingNode implements LIRLowerable { - public static final NodeClass TYPE = NodeClass.create(OpaqueNode.class); + @Input protected ValueNode value; + protected Object noGVN = new Object(); public OpaqueNode(ValueNode value) { super(TYPE, value.stamp(NodeView.DEFAULT).unrestricted()); @@ -50,6 +51,15 @@ public final class OpaqueNode extends FloatingNode implements LIRLowerable { return value; } + public void setValue(ValueNode value) { + this.updateUsages(this.value, value); + this.value = value; + } + + public void remove() { + replaceAndDelete(getValue()); + } + @Override public void generate(NodeLIRBuilderTool gen) { gen.setResult(this, gen.operand(value)); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java index e6147cdfc5..f4bf68a12f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java @@ -99,7 +99,7 @@ public class RawLoadNode extends UnsafeAccessNode implements Lowerable, Virtuali ValueNode offsetValue = tool.getAlias(offset()); if (offsetValue.isConstant()) { long off = offsetValue.asJavaConstant().asLong(); - int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(tool.getMetaAccess(), off, accessKind()); if (entryIndex != -1) { ValueNode entry = tool.getEntry(virtual, entryIndex); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java index d0a2af70f0..eb1db20322 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java @@ -121,7 +121,7 @@ public final class RawStoreNode extends UnsafeAccessNode implements StateSplit, ValueNode indexValue = tool.getAlias(offset()); if (indexValue.isConstant()) { long off = indexValue.asJavaConstant().asLong(); - int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind()); + int entryIndex = virtual.entryIndexForOffset(tool.getMetaAccess(), off, accessKind()); if (entryIndex != -1 && tool.setVirtualEntry(virtual, entryIndex, value(), accessKind(), off)) { tool.delete(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java index 5955e0f855..56430e72fa 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/UnboxNode.java @@ -89,7 +89,7 @@ public final class UnboxNode extends FixedWithNextNode implements Virtualizable, if (alias instanceof VirtualObjectNode) { VirtualObjectNode virtual = (VirtualObjectNode) alias; ResolvedJavaType objectType = virtual.type(); - ResolvedJavaType expectedType = tool.getMetaAccessProvider().lookupJavaType(boxingKind.toBoxedJavaClass()); + ResolvedJavaType expectedType = tool.getMetaAccess().lookupJavaType(boxingKind.toBoxedJavaClass()); if (objectType.equals(expectedType)) { tool.replaceWithValue(tool.getEntry(virtual, 0)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java index 932e4c5d5f..94042eea57 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/IntrinsicContext.java @@ -37,6 +37,7 @@ import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.AbstractMergeNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.Invoke; +import org.graalvm.compiler.nodes.LoopExitNode; import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.java.ExceptionObjectNode; @@ -216,7 +217,7 @@ public class IntrinsicContext { } return frameState; } else { - if (forStateSplit instanceof AbstractMergeNode) { + if (forStateSplit instanceof AbstractMergeNode || forStateSplit instanceof LoopExitNode) { // Merge nodes always need a frame state if (sideEffects.isAfterSideEffect()) { // A merge after one or more side effects diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java new file mode 100644 index 0000000000..07cdbdb424 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractUnsafeCompareAndSwapNode.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.nodes.java; + +import static org.graalvm.compiler.core.common.calc.CanonicalCondition.EQ; +import static org.graalvm.compiler.debug.DebugContext.DETAILED_LEVEL; +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.InputType.Value; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; + +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.LogicConstantNode; +import org.graalvm.compiler.nodes.LogicNode; +import org.graalvm.compiler.nodes.NodeView; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.calc.CompareNode; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.calc.ObjectEqualsNode; +import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.spi.Lowerable; +import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.Virtualizable; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; +import org.graalvm.compiler.nodes.virtual.VirtualArrayNode; +import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; +import jdk.internal.vm.compiler.word.LocationIdentity; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.ResolvedJavaField; + +@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8) +public abstract class AbstractUnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, Virtualizable { + public static final NodeClass TYPE = NodeClass.create(AbstractUnsafeCompareAndSwapNode.class); + @Input ValueNode object; + @Input ValueNode offset; + @Input ValueNode expected; + @Input ValueNode newValue; + protected final JavaKind valueKind; + protected final LocationIdentity locationIdentity; + + public AbstractUnsafeCompareAndSwapNode(NodeClass c, Stamp stamp, ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, + JavaKind valueKind, LocationIdentity locationIdentity) { + super(c, stamp); + this.object = object; + this.offset = offset; + this.expected = expected; + this.newValue = newValue; + this.valueKind = valueKind; + this.locationIdentity = locationIdentity; + } + + public ValueNode object() { + return object; + } + + public ValueNode offset() { + return offset; + } + + public ValueNode expected() { + return expected; + } + + public ValueNode newValue() { + return newValue; + } + + public JavaKind getValueKind() { + return valueKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + return locationIdentity; + } + + @Override + public void lower(LoweringTool tool) { + tool.getLowerer().lower(this, tool); + } + + @Override + public void virtualize(VirtualizerTool tool) { + ValueNode offsetAlias = tool.getAlias(offset); + if (!offsetAlias.isJavaConstant()) { + return; + } + long constantOffset = offsetAlias.asJavaConstant().asLong(); + ValueNode objectAlias = tool.getAlias(object); + int index; + if (objectAlias instanceof VirtualInstanceNode) { + VirtualInstanceNode obj = (VirtualInstanceNode) objectAlias; + + ResolvedJavaField field = obj.type().findInstanceFieldWithOffset(constantOffset, expected.getStackKind()); + if (field == null) { + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown field", this); + return; + } + index = obj.fieldIndex(field); + } else if (objectAlias instanceof VirtualArrayNode) { + VirtualArrayNode array = (VirtualArrayNode) objectAlias; + index = array.entryIndexForOffset(tool.getMetaAccess(), constantOffset, valueKind); + } else { + return; + } + if (index < 0) { + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown index", this); + return; + } + VirtualObjectNode obj = (VirtualObjectNode) objectAlias; + ValueNode currentValue = tool.getEntry(obj, index); + ValueNode expectedAlias = tool.getAlias(this.expected); + + LogicNode equalsNode = null; + if (valueKind.isObject()) { + equalsNode = ObjectEqualsNode.virtualizeComparison(expectedAlias, currentValue, graph(), tool); + } + if (equalsNode == null && !(expectedAlias instanceof VirtualObjectNode) && !(currentValue instanceof VirtualObjectNode)) { + equalsNode = CompareNode.createCompareNode(EQ, expectedAlias, currentValue, tool.getConstantReflection(), NodeView.DEFAULT); + } + if (equalsNode == null) { + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Expected and/or current values are virtual and the comparison can not be folded", this); + return; + } + + ValueNode newValueAlias = tool.getAlias(this.newValue); + ValueNode fieldValue; + if (equalsNode instanceof LogicConstantNode) { + fieldValue = ((LogicConstantNode) equalsNode).getValue() ? newValue : currentValue; + } else { + if (currentValue instanceof VirtualObjectNode || newValueAlias instanceof VirtualObjectNode) { + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Unknown outcome and current or new value is virtual", this); + return; + } + fieldValue = ConditionalNode.create(equalsNode, newValueAlias, currentValue, NodeView.DEFAULT); + } + if (!tool.setVirtualEntry(obj, index, fieldValue, valueKind, constantOffset)) { + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Could not set virtual entry", this); + return; + } + tool.getDebug().log(DETAILED_LEVEL, "%s.virtualize() -> Success: virtualizing", this); + if (!equalsNode.isAlive()) { + tool.addNode(equalsNode); + } + if (!fieldValue.isAlive() && !(fieldValue instanceof VirtualObjectNode)) { + tool.addNode(fieldValue); + } + finishVirtualize(tool, equalsNode, currentValue); + } + + protected abstract void finishVirtualize(VirtualizerTool tool, LogicNode equalsNode, ValueNode currentValue); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java index 2509006f3a..8e2e139a64 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java @@ -106,7 +106,7 @@ public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonic return this; } ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant()); - if (type != null && !throwsIllegalArgumentException(type)) { + if (type != null && type.getArrayClass() != null && !throwsIllegalArgumentException(type)) { return createNewArrayNode(type); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java index 1be356d93b..353be027de 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java @@ -56,7 +56,7 @@ public final class LogicCompareAndSwapNode extends AbstractCompareAndSwapNode { } public LogicCompareAndSwapNode(AddressNode address, LocationIdentity location, ValueNode expectedValue, ValueNode newValue, BarrierType barrierType) { - super(TYPE, address, location, expectedValue, newValue, barrierType, StampFactory.forKind(JavaKind.Boolean.getStackKind())); + super(TYPE, address, location, expectedValue, newValue, barrierType, StampFactory.forInteger(JavaKind.Int, 0, 1)); } @Override diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java index d6c8e9f262..10895ff2eb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewInstanceNode.java @@ -79,7 +79,7 @@ public class NewInstanceNode extends AbstractNewObjectNode implements Virtualiza * Reference objects can escape into their ReferenceQueue at any safepoint, therefore * they're excluded from escape analysis. */ - if (!tool.getMetaAccessProvider().lookupJavaType(Reference.class).isAssignableFrom(instanceClass)) { + if (!tool.getMetaAccess().lookupJavaType(Reference.class).isAssignableFrom(instanceClass)) { VirtualInstanceNode virtualObject = createVirtualInstanceNode(true); ResolvedJavaField[] fields = virtualObject.getFields(); ValueNode[] state = new ValueNode[fields.length]; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndExchangeNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndExchangeNode.java index c000b4bdbc..65250622a9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndExchangeNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndExchangeNode.java @@ -24,47 +24,28 @@ package org.graalvm.compiler.nodes.java; -import jdk.vm.ci.meta.JavaKind; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; -import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; import jdk.internal.vm.compiler.word.LocationIdentity; -import static org.graalvm.compiler.nodeinfo.InputType.Memory; -import static org.graalvm.compiler.nodeinfo.InputType.Value; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; +import jdk.vm.ci.meta.JavaKind; /** * Represents an atomic compare-and-swap operation. The result is the current value of the memory * location that was compared. */ -@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8) -public final class UnsafeCompareAndExchangeNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { +@NodeInfo +public final class UnsafeCompareAndExchangeNode extends AbstractUnsafeCompareAndSwapNode { public static final NodeClass TYPE = NodeClass.create(UnsafeCompareAndExchangeNode.class); - @Input ValueNode object; - @Input ValueNode offset; - @Input ValueNode expected; - @Input ValueNode newValue; - - private final JavaKind valueKind; - private final LocationIdentity locationIdentity; public UnsafeCompareAndExchangeNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) { - super(TYPE, meetInputs(expected.stamp(NodeView.DEFAULT), newValue.stamp(NodeView.DEFAULT))); - this.object = object; - this.offset = offset; - this.expected = expected; - this.newValue = newValue; - this.valueKind = valueKind; - this.locationIdentity = locationIdentity; + super(TYPE, meetInputs(expected.stamp(NodeView.DEFAULT), newValue.stamp(NodeView.DEFAULT)), object, offset, expected, newValue, valueKind, locationIdentity); } private static Stamp meetInputs(Stamp expected, Stamp newValue) { @@ -72,33 +53,8 @@ public final class UnsafeCompareAndExchangeNode extends AbstractMemoryCheckpoint return expected.unrestricted().meet(newValue.unrestricted()); } - public ValueNode object() { - return object; - } - - public ValueNode offset() { - return offset; - } - - public ValueNode expected() { - return expected; - } - - public ValueNode newValue() { - return newValue; - } - - public JavaKind getValueKind() { - return valueKind; - } - @Override - public LocationIdentity getLocationIdentity() { - return locationIdentity; - } - - @Override - public void lower(LoweringTool tool) { - tool.getLowerer().lower(this, tool); + protected void finishVirtualize(VirtualizerTool tool, LogicNode equalsNode, ValueNode currentValue) { + tool.replaceWith(currentValue); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java index 778521c64a..2725543e30 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,20 +24,15 @@ package org.graalvm.compiler.nodes.java; -import static org.graalvm.compiler.nodeinfo.InputType.Memory; -import static org.graalvm.compiler.nodeinfo.InputType.Value; -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; - import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.LogicNode; import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint; -import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.compiler.nodes.spi.Lowerable; -import org.graalvm.compiler.nodes.spi.LoweringTool; +import org.graalvm.compiler.nodes.calc.ConditionalNode; +import org.graalvm.compiler.nodes.spi.VirtualizerTool; import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.vm.ci.meta.JavaKind; @@ -46,56 +41,22 @@ import jdk.vm.ci.meta.JavaKind; * Represents an atomic compare-and-swap operation. The result is a boolean that contains whether * the value matched the expected value. */ -@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8) -public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single { +@NodeInfo +public final class UnsafeCompareAndSwapNode extends AbstractUnsafeCompareAndSwapNode { public static final NodeClass TYPE = NodeClass.create(UnsafeCompareAndSwapNode.class); - @Input ValueNode object; - @Input ValueNode offset; - @Input ValueNode expected; - @Input ValueNode newValue; - - private final JavaKind valueKind; - private final LocationIdentity locationIdentity; public UnsafeCompareAndSwapNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) { - super(TYPE, StampFactory.forKind(JavaKind.Boolean.getStackKind())); + super(TYPE, StampFactory.forKind(JavaKind.Boolean.getStackKind()), object, offset, expected, newValue, valueKind, locationIdentity); assert expected.stamp(NodeView.DEFAULT).isCompatible(newValue.stamp(NodeView.DEFAULT)); - this.object = object; - this.offset = offset; - this.expected = expected; - this.newValue = newValue; - this.valueKind = valueKind; - this.locationIdentity = locationIdentity; - } - - public ValueNode object() { - return object; - } - - public ValueNode offset() { - return offset; - } - - public ValueNode expected() { - return expected; - } - - public ValueNode newValue() { - return newValue; - } - - public JavaKind getValueKind() { - return valueKind; } @Override - public LocationIdentity getLocationIdentity() { - return locationIdentity; - } - - @Override - public void lower(LoweringTool tool) { - tool.getLowerer().lower(this, tool); + protected void finishVirtualize(VirtualizerTool tool, LogicNode equalsNode, ValueNode currentValue) { + ValueNode result = ConditionalNode.create(equalsNode, ConstantNode.forBoolean(true, graph()), ConstantNode.forBoolean(false, graph()), NodeView.DEFAULT); + if (!result.isAlive()) { + tool.addNode(result); + } + tool.replaceWith(result); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java new file mode 100644 index 0000000000..67044b4521 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/DelegatingReplacements.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.nodes.spi; + +import org.graalvm.compiler.api.replacements.SnippetTemplateCache; +import org.graalvm.compiler.bytecode.Bytecode; +import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.options.OptionValues; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A convenience class when want to subclass and override just a portion of the Replacements API. + */ +public class DelegatingReplacements implements Replacements { + protected final Replacements delegate; + + public DelegatingReplacements(Replacements delegate) { + this.delegate = delegate; + } + + @Override + public OptionValues getOptions() { + return delegate.getOptions(); + } + + @Override + public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() { + return delegate.getGraphBuilderPlugins(); + } + + @Override + public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { + return delegate.getSnippet(method, args, trackNodeSourcePosition, replaceePosition); + } + + @Override + public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { + return delegate.getSnippet(method, recursiveEntry, args, trackNodeSourcePosition, replaceePosition); + } + + @Override + public void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition) { + delegate.registerSnippet(method, trackNodeSourcePosition); + } + + @Override + public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) { + return delegate.getSubstitution(method, invokeBci, trackNodeSourcePosition, replaceePosition); + } + + @Override + public Bytecode getSubstitutionBytecode(ResolvedJavaMethod method) { + return delegate.getSubstitutionBytecode(method); + } + + @Override + public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) { + return delegate.getIntrinsicGraph(method, compilationId, debug); + } + + @Override + public boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) { + return delegate.hasSubstitution(method, invokeBci); + } + + @Override + public BytecodeProvider getDefaultReplacementBytecodeProvider() { + return delegate.getDefaultReplacementBytecodeProvider(); + } + + @Override + public void registerSnippetTemplateCache(SnippetTemplateCache snippetTemplates) { + delegate.registerSnippetTemplateCache(snippetTemplates); + } + + @Override + public T getSnippetTemplateCache(Class templatesClass) { + return delegate.getSnippetTemplateCache(templatesClass); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java index 503984777c..aeb8a647f3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.nodes.spi; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.memory.address.AddressNode; @@ -34,7 +33,7 @@ import jdk.vm.ci.meta.JavaKind; /** * Provides a capability for replacing a higher node with one or more lower level nodes. */ -public interface LoweringProvider extends ArrayOffsetProvider { +public interface LoweringProvider { void lower(Node n, LoweringTool tool); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java index 28b22213ca..61162c638d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/Replacements.java @@ -28,6 +28,8 @@ import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.api.replacements.SnippetTemplateCache; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; @@ -93,6 +95,17 @@ public interface Replacements { */ Bytecode getSubstitutionBytecode(ResolvedJavaMethod method); + /** + * Gets a graph produced from the intrinsic for a given method that can be compiled and + * installed for the method. + * + * @param method + * @param compilationId + * @param debug + * @return an intrinsic graph that can be compiled and installed for {@code method} or null + */ + StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug); + /** * Determines if there may be a * {@linkplain #getSubstitution(ResolvedJavaMethod, int, boolean, NodeSourcePosition) diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java index aad6488e79..4848cd1fd7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java @@ -26,7 +26,6 @@ package org.graalvm.compiler.nodes.spi; import java.util.List; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.graph.Node; @@ -51,15 +50,13 @@ public interface VirtualizerTool { /** * @return the {@link MetaAccessProvider} associated with the current compilation. */ - MetaAccessProvider getMetaAccessProvider(); + MetaAccessProvider getMetaAccess(); /** * @return the {@link ConstantReflectionProvider} associated with the current compilation, which * can be used to access {@link JavaConstant}s. */ - ConstantReflectionProvider getConstantReflectionProvider(); - - ArrayOffsetProvider getArrayOffsetProvider(); + ConstantReflectionProvider getConstantReflection(); /** * This method should be used to query the maximum size of virtualized objects before attempting diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java index 352bcf42b8..1d211019ba 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/type/NarrowOopStamp.java @@ -32,7 +32,6 @@ import org.graalvm.compiler.core.common.type.ObjectStamp; import org.graalvm.compiler.core.common.type.Stamp; import jdk.vm.ci.meta.Constant; -import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.MemoryAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @@ -107,9 +106,6 @@ public abstract class NarrowOopStamp extends AbstractObjectStamp { return super.equals(other); } - @Override - public abstract JavaConstant asConstant(); - @Override public abstract boolean isCompatible(Constant other); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java index d5cc2cf7fb..3ee60054dd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/CommitAllocationNode.java @@ -247,7 +247,11 @@ public final class CommitAllocationNode extends FixedWithNextNode implements Vir List v = getVirtualObjects(); int fieldWriteCount = 0; for (int i = 0; i < v.size(); i++) { - fieldWriteCount += v.get(i).entryCount(); + VirtualObjectNode node = v.get(i); + if (node == null) { + return CYCLES_UNKNOWN; + } + fieldWriteCount += node.entryCount(); } int rawValueWrites = NodeCycles.compute(WriteNode.TYPE.cycles(), fieldWriteCount).value; int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.cycles().value; @@ -259,7 +263,11 @@ public final class CommitAllocationNode extends FixedWithNextNode implements Vir List v = getVirtualObjects(); int fieldWriteCount = 0; for (int i = 0; i < v.size(); i++) { - fieldWriteCount += v.get(i).entryCount(); + VirtualObjectNode node = v.get(i); + if (node == null) { + return SIZE_UNKNOWN; + } + fieldWriteCount += node.entryCount(); } int rawValueWrites = NodeSize.compute(WriteNode.TYPE.size(), fieldWriteCount).value; int rawValuesTlabBumps = AbstractNewObjectNode.TYPE.size().value; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java index 4b8bc6c4a0..45364fc4d2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java @@ -26,8 +26,6 @@ package org.graalvm.compiler.nodes.virtual; import java.nio.ByteOrder; -import jdk.vm.ci.meta.ConstantReflectionProvider; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -37,7 +35,9 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.spi.ArrayLengthProvider; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @NodeInfo(nameTemplate = "VirtualArray({p#objectId}) {p#componentType/s}[{p#length}]") @@ -91,13 +91,13 @@ public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthPr } @Override - public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) { - return entryIndexForOffset(arrayOffsetProvider, constantOffset, expectedEntryKind, componentType, length); + public int entryIndexForOffset(MetaAccessProvider metaAccess, long constantOffset, JavaKind expectedEntryKind) { + return entryIndexForOffset(metaAccess, constantOffset, expectedEntryKind, componentType, length); } - public static int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) { - int baseOffset = arrayOffsetProvider.arrayBaseOffset(componentType.getJavaKind()); - int indexScale = arrayOffsetProvider.arrayScalingFactor(componentType.getJavaKind()); + public static int entryIndexForOffset(MetaAccessProvider metaAccess, long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) { + int baseOffset = metaAccess.getArrayBaseOffset(componentType.getJavaKind()); + int indexScale = metaAccess.getArrayIndexScale(componentType.getJavaKind()); long offset; if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java index 9f12b9ca0b..92706ad345 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.nodes.virtual; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.NodeClass; import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.Verbosity; @@ -32,6 +31,7 @@ import org.graalvm.compiler.nodes.FixedNode; import org.graalvm.compiler.nodes.ValueNode; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; @@ -103,7 +103,7 @@ public class VirtualInstanceNode extends VirtualObjectNode { } @Override - public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) { + public int entryIndexForOffset(MetaAccessProvider metaAccess, long constantOffset, JavaKind expectedEntryKind) { return fieldIndex(type.findInstanceFieldWithOffset(constantOffset, expectedEntryKind)); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java index 9e20fae415..1fea61012b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java @@ -27,7 +27,6 @@ package org.graalvm.compiler.nodes.virtual; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.TypeReference; import org.graalvm.compiler.graph.IterableNodeType; @@ -40,6 +39,7 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable; import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaType; @NodeInfo(cycles = CYCLES_0, size = SIZE_0) @@ -96,9 +96,8 @@ public abstract class VirtualObjectNode extends ValueNode implements LIRLowerabl * * @param constantOffset offset, where the value is placed. * @param expectedEntryKind Specifies which type is expected at this offset (Is important when - * doing implicit casts, especially on big endian systems. */ - public abstract int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind); + public abstract int entryIndexForOffset(MetaAccessProvider metaAccess, long constantOffset, JavaKind expectedEntryKind); /** * Returns the {@link JavaKind} of the entry at the given index. diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java index 0ad4bbd01c..731bc99bad 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java @@ -37,6 +37,7 @@ import java.util.Map; import java.util.Set; import javax.annotation.processing.Filer; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.lang.model.SourceVersion; @@ -44,7 +45,6 @@ import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; -import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; @@ -156,7 +156,7 @@ public class OptionProcessor extends AbstractProcessor { originatingElementsList.add(field); PackageElement enclosingPackage = null; while (enclosing != null) { - if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) { + if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE || enclosing.getKind() == ElementKind.ENUM) { if (enclosing.getModifiers().contains(Modifier.PRIVATE)) { String msg = String.format("Option field cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing); processingEnv.getMessager().printMessage(Kind.ERROR, msg, element); @@ -167,6 +167,10 @@ public class OptionProcessor extends AbstractProcessor { separator = "."; } else if (enclosing.getKind() == ElementKind.PACKAGE) { enclosingPackage = (PackageElement) enclosing; + break; + } else { + processingEnv.getMessager().printMessage(Kind.ERROR, "Unexpected enclosing element kind: " + enclosing.getKind(), element); + return; } enclosing = enclosing.getEnclosingElement(); } @@ -221,34 +225,27 @@ public class OptionProcessor extends AbstractProcessor { } String optionTypeName = getAnnotationValue(annotation, "type", VariableElement.class).getSimpleName().toString(); - info.options.add(new OptionInfo(optionName, optionTypeName, help, extraHelp, optionType, declaringClass, field)); + info.options.add(new OptionInfo(optionName, optionTypeName, help, extraHelp, optionType, declaringClass, field.getSimpleName().toString())); } - private void createFiles(OptionsInfo info) { - String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); - Name topDeclaringClass = info.topDeclaringType.getSimpleName(); + public static void createOptionsDescriptorsFile(ProcessingEnvironment processingEnv, OptionsInfo info) { Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]); - - createOptionsDescriptorsFile(info, pkg, topDeclaringClass, originatingElements); - } - - private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) { - String optionsClassName = topDeclaringClass + "_" + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME); + String optionsDescriptorsClassName = info.className + "_" + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME); Filer filer = processingEnv.getFiler(); - try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) { + try (PrintWriter out = createSourceFile(info.packageName, optionsDescriptorsClassName, filer, originatingElements)) { out.println("// CheckStyle: stop header check"); out.println("// CheckStyle: stop line length check"); out.println("// GENERATED CONTENT - DO NOT EDIT"); - out.println("// Source: " + topDeclaringClass + ".java"); - out.println("package " + pkg + ";"); + out.println("// Source: " + info.className + ".java"); + out.println("package " + info.packageName + ";"); out.println(""); out.println("import java.util.*;"); out.println("import " + getPackageName(OPTION_DESCRIPTORS_CLASS_NAME) + ".*;"); out.println("import " + OPTION_TYPE_CLASS_NAME + ";"); out.println(""); - out.println("public class " + optionsClassName + " implements " + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME) + " {"); + out.println("public class " + optionsDescriptorsClassName + " implements " + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME) + " {"); String desc = getSimpleName(OPTION_DESCRIPTOR_CLASS_NAME); @@ -260,19 +257,14 @@ public class OptionProcessor extends AbstractProcessor { out.println(" // CheckStyle: stop line length check"); for (OptionInfo option : info.options) { String name = option.name; - String optionField; - if (option.field.getModifiers().contains(Modifier.PRIVATE)) { - throw new InternalError(); - } else { - optionField = option.declaringClass + "." + option.field.getSimpleName(); - } + String optionField = option.declaringClass + "." + option.field; out.println(" case \"" + name + "\": {"); String optionType = option.optionType; String type = option.type; String help = option.help; List extraHelp = option.extraHelp; String declaringClass = option.declaringClass; - Name fieldName = option.field.getSimpleName(); + String fieldName = option.field; out.printf(" return " + desc + ".create(\n"); out.printf(" /*name*/ \"%s\",\n", name); out.printf(" /*optionType*/ %s.%s,\n", getSimpleName(OPTION_TYPE_CLASS_NAME), optionType); @@ -319,10 +311,11 @@ public class OptionProcessor extends AbstractProcessor { } } - protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { + public static PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) { try { // Ensure Unix line endings to comply with code style guide checked by Checkstyle - JavaFileObject sourceFile = filer.createSourceFile(pkg + "." + relativeName, originatingElements); + String className = pkg + "." + relativeName; + JavaFileObject sourceFile = filer.createSourceFile(className, originatingElements); return new PrintWriter(sourceFile.openWriter()) { @Override @@ -335,17 +328,17 @@ public class OptionProcessor extends AbstractProcessor { } } - static class OptionInfo implements Comparable { + public static class OptionInfo implements Comparable { - final String name; - final String optionType; - final String help; - final List extraHelp; - final String type; - final String declaringClass; - final VariableElement field; + public final String name; + public final String optionType; + public final String help; + public final List extraHelp; + public final String type; + public final String declaringClass; + public final String field; - OptionInfo(String name, String optionType, String help, List extraHelp, String type, String declaringClass, VariableElement field) { + public OptionInfo(String name, String optionType, String help, List extraHelp, String type, String declaringClass, String field) { this.name = name; this.optionType = optionType; this.help = help; @@ -366,14 +359,16 @@ public class OptionProcessor extends AbstractProcessor { } } - static class OptionsInfo { + public static class OptionsInfo { - final Element topDeclaringType; - final List options = new ArrayList<>(); - final Set originatingElements = new HashSet<>(); + public final String packageName; + public final String className; + public final List options = new ArrayList<>(); + public final Set originatingElements = new HashSet<>(); - OptionsInfo(Element topDeclaringType) { - this.topDeclaringType = topDeclaringType; + public OptionsInfo(String packageName, String className) { + this.packageName = packageName; + this.className = className; } } @@ -387,7 +382,7 @@ public class OptionProcessor extends AbstractProcessor { } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return true; } @@ -404,7 +399,9 @@ public class OptionProcessor extends AbstractProcessor { Element topDeclaringType = topDeclaringType(element); OptionsInfo options = map.get(topDeclaringType); if (options == null) { - options = new OptionsInfo(topDeclaringType); + String pkg = ((PackageElement) topDeclaringType.getEnclosingElement()).getQualifiedName().toString(); + String topDeclaringClass = topDeclaringType.getSimpleName().toString(); + options = new OptionsInfo(pkg, topDeclaringClass); map.put(topDeclaringType, options); } if (!element.getEnclosingElement().getSimpleName().toString().endsWith("Options")) { @@ -416,11 +413,12 @@ public class OptionProcessor extends AbstractProcessor { boolean ok = true; Map uniqueness = new HashMap<>(); - for (OptionsInfo info : map.values()) { + for (Map.Entry e : map.entrySet()) { + OptionsInfo info = e.getValue(); for (OptionInfo option : info.options) { OptionInfo conflict = uniqueness.put(option.name, option); if (conflict != null) { - processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, option.field); + processingEnv.getMessager().printMessage(Kind.ERROR, "Duplicate option names for " + option + " and " + conflict, e.getKey()); ok = false; } } @@ -428,7 +426,7 @@ public class OptionProcessor extends AbstractProcessor { if (ok) { for (OptionsInfo info : map.values()) { - createFiles(info); + createOptionsDescriptorsFile(processingEnv, info); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java index ff01feea1f..f7e7b4d0d5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java @@ -60,6 +60,7 @@ import org.graalvm.compiler.nodes.calc.UnaryNode; import org.graalvm.compiler.nodes.cfg.Block; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.nodes.cfg.ControlFlowGraph.RecursiveVisitor; +import org.graalvm.compiler.nodes.extended.GuardingNode; import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; import org.graalvm.compiler.nodes.memory.FixedAccessNode; import org.graalvm.compiler.nodes.memory.FloatingAccessNode; @@ -114,6 +115,11 @@ public class FixReadsPhase extends BasePhase { } else if (node instanceof FloatingAccessNode) { FloatingAccessNode floatingAccessNode = (FloatingAccessNode) node; floatingAccessNode.setLastLocationAccess(null); + GuardingNode guard = floatingAccessNode.getGuard(); + if (guard != null) { + floatingAccessNode.setGuard(null); + GraphUtil.tryKillUnused(guard.asNode()); + } FixedAccessNode fixedAccess = floatingAccessNode.asFixedNode(); replaceCurrent(fixedAccess); } else if (node instanceof PiNode) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java index c93423c7e5..83495e6f70 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java @@ -69,7 +69,7 @@ import org.graalvm.compiler.nodes.memory.MemoryPhiNode; import org.graalvm.compiler.nodes.memory.ReadNode; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.phases.Phase; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo; import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure; @@ -221,7 +221,7 @@ public class FloatingReadPhase extends Phase { } } - HashSetNodeEventListener listener = new HashSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES)); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(EnumSet.of(NODE_ADDED, ZERO_USAGES)); try (NodeEventScope nes = graph.trackNodeEvents(listener)) { ReentrantNodeIterator.apply(new FloatingReadClosure(modifiedInLoops, createFloatingReads, createMemoryMapNodes), graph.start(), new MemoryMapImpl(graph.start())); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java index 9290b15dd3..3f7376e7fe 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IncrementalCanonicalizerPhase.java @@ -28,7 +28,7 @@ import org.graalvm.compiler.graph.Graph.NodeEventScope; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.tiers.PhaseContext; /** @@ -51,7 +51,7 @@ public class IncrementalCanonicalizerPhase extends Phase @Override @SuppressWarnings("try") protected void run(StructuredGraph graph, C context) { - HashSetNodeEventListener listener = new HashSetNodeEventListener(); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); try (NodeEventScope nes = graph.trackNodeEvents(listener)) { super.run(graph, context); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/InsertGuardFencesPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/InsertGuardFencesPhase.java new file mode 100644 index 0000000000..774e49ca7f --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/InsertGuardFencesPhase.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.phases.common; + +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.NonDeoptGuardTargets; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.MitigateSpeculativeExecutionAttacks; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.UseIndexMasking; + +import java.util.ArrayList; +import java.util.List; + +import org.graalvm.compiler.core.common.type.IntegerStamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.Position; +import org.graalvm.compiler.nodeinfo.InputType; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.DeoptimizeNode; +import org.graalvm.compiler.nodes.IfNode; +import org.graalvm.compiler.nodes.LoopExitNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.MultiGuardNode; +import org.graalvm.compiler.nodes.memory.Access; +import org.graalvm.compiler.phases.Phase; + +import jdk.vm.ci.meta.DeoptimizationReason; + +/** + * This phase sets the {@linkplain AbstractBeginNode#setWithSpeculationFence() speculation fence} + * flag on {@linkplain AbstractBeginNode begin nodes} in order to mitigate speculative execution + * attacks. + */ +public class InsertGuardFencesPhase extends Phase { + @Override + protected void run(StructuredGraph graph) { + for (AbstractBeginNode beginNode : graph.getNodes(AbstractBeginNode.TYPE)) { + if (hasGuardUsages(beginNode)) { + if (MitigateSpeculativeExecutionAttacks.getValue(graph.getOptions()) == NonDeoptGuardTargets) { + if (isDeoptGuard(beginNode)) { + graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Skipping deoptimizing guard speculation fence at %s", beginNode); + continue; + } + } + if (UseIndexMasking.getValue(graph.getOptions())) { + if (isBoundsCheckGuard(beginNode)) { + graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Skipping bounds-check speculation fence at %s", beginNode); + continue; + } + } + if (graph.getDebug().isLogEnabled(DebugContext.DETAILED_LEVEL)) { + graph.getDebug().log(DebugContext.DETAILED_LEVEL, "Adding speculation fence for %s at %s", guardUsages(beginNode), beginNode); + } else { + graph.getDebug().log(DebugContext.VERBOSE_LEVEL, "Adding speculation fence at %s", beginNode); + } + beginNode.setWithSpeculationFence(); + } else { + graph.getDebug().log(DebugContext.DETAILED_LEVEL, "No guards on %s", beginNode); + } + } + } + + private static boolean isDeoptGuard(AbstractBeginNode beginNode) { + if (!(beginNode.predecessor() instanceof IfNode)) { + return false; + } + IfNode ifNode = (IfNode) beginNode.predecessor(); + AbstractBeginNode otherBegin; + if (ifNode.trueSuccessor() == beginNode) { + otherBegin = ifNode.falseSuccessor(); + } else { + assert ifNode.falseSuccessor() == beginNode; + otherBegin = ifNode.trueSuccessor(); + } + if (!(otherBegin.next() instanceof DeoptimizeNode)) { + return false; + } + DeoptimizeNode deopt = (DeoptimizeNode) otherBegin.next(); + return deopt.getAction().doesInvalidateCompilation(); + } + + public static final IntegerStamp POSITIVE_ARRAY_INDEX_STAMP = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1); + + private static boolean isBoundsCheckGuard(AbstractBeginNode beginNode) { + if (!(beginNode.predecessor() instanceof IfNode)) { + return false; + } + IfNode ifNode = (IfNode) beginNode.predecessor(); + AbstractBeginNode otherBegin; + if (ifNode.trueSuccessor() == beginNode) { + otherBegin = ifNode.falseSuccessor(); + } else { + assert ifNode.falseSuccessor() == beginNode; + otherBegin = ifNode.trueSuccessor(); + } + if (otherBegin.next() instanceof DeoptimizeNode) { + DeoptimizeNode deopt = (DeoptimizeNode) otherBegin.next(); + if (deopt.getReason() == DeoptimizationReason.BoundsCheckException && !hasMultipleGuardUsages(beginNode)) { + return true; + } + } else if (otherBegin instanceof LoopExitNode && beginNode.usages().filter(MultiGuardNode.class).isNotEmpty() && !hasMultipleGuardUsages(beginNode)) { + return true; + } + + for (Node usage : beginNode.usages()) { + for (Position pos : usage.inputPositions()) { + if (pos.getInputType() == InputType.Guard && pos.get(usage) == beginNode) { + if (usage instanceof PiNode) { + if (!((PiNode) usage).piStamp().equals(POSITIVE_ARRAY_INDEX_STAMP)) { + return false; + } + } else if (usage instanceof Access) { + if (!NamedLocationIdentity.isArrayLocation(((Access) usage).getLocationIdentity())) { + return false; + } + } else { + return false; + } + break; + } + } + } + + return true; + } + + private static boolean hasGuardUsages(Node n) { + for (Node usage : n.usages()) { + for (Position pos : usage.inputPositions()) { + if (pos.getInputType() == InputType.Guard && pos.get(usage) == n) { + return true; + } + } + } + return false; + } + + private static boolean hasMultipleGuardUsages(Node n) { + boolean foundOne = false; + for (Node usage : n.usages()) { + for (Position pos : usage.inputPositions()) { + if (pos.getInputType() == InputType.Guard && pos.get(usage) == n) { + if (foundOne) { + return true; + } + foundOne = true; + } + } + } + return false; + } + + private static List guardUsages(Node n) { + List ret = new ArrayList<>(); + for (Node usage : n.usages()) { + for (Position pos : usage.inputPositions()) { + if (pos.getInputType() == InputType.Guard && pos.get(usage) == n) { + ret.add(usage); + } + } + } + return ret; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java index 66a7e7060c..f824fc6142 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/IterativeConditionalEliminationPhase.java @@ -32,7 +32,7 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.spi.Simplifiable; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.phases.BasePhase; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.tiers.PhaseContext; public class IterativeConditionalEliminationPhase extends BasePhase { @@ -50,7 +50,7 @@ public class IterativeConditionalEliminationPhase extends BasePhase loop : cfg.getLoops()) { - double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).probability(); + double loopProbability = cfg.blockFor(loop.getHeader().getBeginNode()).getRelativeFrequency(); if (loopProbability > (1D / Integer.MAX_VALUE)) { addSectionCounters(loop.getHeader().getBeginNode(), loop.getBlocks(), loop.getChildren(), graph.getLastSchedule(), cfg); } @@ -126,10 +126,10 @@ public class ProfileCompiledMethodsPhase extends Phase { for (Loop loop : childLoops) { blocks.removeAll(loop.getBlocks()); } - double weight = getSectionWeight(schedule, blocks) / cfg.blockFor(start).probability(); - DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), (long) weight, true, start.next()); + long increment = DynamicCounterNode.clampIncrement((long) (getSectionWeight(schedule, blocks) / cfg.blockFor(start).getRelativeFrequency())); + DynamicCounterNode.addCounterBefore(GROUP_NAME, sectionHead(start), increment, true, start.next()); if (WITH_INVOKE_FREE_SECTIONS && !hasInvoke(blocks)) { - DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), (long) weight, true, start.next()); + DynamicCounterNode.addCounterBefore(GROUP_NAME_WITHOUT, sectionHead(start), increment, true, start.next()); } } @@ -144,7 +144,7 @@ public class ProfileCompiledMethodsPhase extends Phase { private static double getSectionWeight(ScheduleResult schedule, Collection blocks) { double count = 0; for (Block block : blocks) { - double blockProbability = block.probability(); + double blockProbability = block.getRelativeFrequency(); for (Node node : schedule.getBlockToNodesMap().get(block)) { count += blockProbability * getNodeWeight(node); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java index ed9be9f404..936e5d096f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java @@ -101,7 +101,7 @@ import org.graalvm.compiler.nodes.spi.Replacements; import org.graalvm.compiler.nodes.type.StampTool; import org.graalvm.compiler.nodes.util.GraphUtil; import org.graalvm.compiler.phases.common.inlining.info.InlineInfo; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.util.ValueMergeUtil; import jdk.vm.ci.code.BytecodeFrame; @@ -507,7 +507,7 @@ public class InliningUtil extends ValueMergeUtil { @SuppressWarnings("try") public static EconomicSet inlineForCanonicalization(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck, ResolvedJavaMethod inlineeMethod, Consumer> duplicatesConsumer, String reason, String phase) { - HashSetNodeEventListener listener = new HashSetNodeEventListener(); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); /* * This code relies on the fact that Graph.addDuplicates doesn't trigger the * NodeEventListener to track only nodes which were modified into the process of inlining diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java index 92ddf9b970..3655750ccd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/elem/InlineableGraph.java @@ -43,7 +43,7 @@ import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.inlining.InliningUtil; -import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache; +import org.graalvm.compiler.phases.graph.FixedNodeRelativeFrequencyCache; import org.graalvm.compiler.phases.tiers.HighTierContext; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -66,7 +66,7 @@ public class InlineableGraph implements Inlineable { private final StructuredGraph graph; - private FixedNodeProbabilityCache probabilites = new FixedNodeProbabilityCache(); + private FixedNodeRelativeFrequencyCache probabilites = new FixedNodeRelativeFrequencyCache(); public InlineableGraph(final ResolvedJavaMethod method, final Invoke invoke, final HighTierContext context, CanonicalizerPhase canonicalizer, boolean trackNodeSourcePosition) { StructuredGraph original = InliningUtil.getIntrinsicGraph(context.getReplacements(), method, invoke.bci(), trackNodeSourcePosition, null); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java index e2e88d7b0e..1c27504feb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java @@ -36,7 +36,7 @@ import org.graalvm.compiler.nodes.ParameterNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.phases.common.inlining.policy.AbstractInliningPolicy; -import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache; +import org.graalvm.compiler.phases.graph.FixedNodeRelativeFrequencyCache; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -87,7 +87,7 @@ public final class CallsiteHolderExplorable extends CallsiteHolder { probabilities = null; computeInliningRelevance = null; } else { - probabilities = new FixedNodeProbabilityCache(); + probabilities = new FixedNodeRelativeFrequencyCache(); computeInliningRelevance = new ComputeInliningRelevance(graph, probabilities); computeProbabilities(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java index a9eb6d8e31..f2f2d3fe14 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java @@ -232,12 +232,8 @@ public class InliningData { AssumptionResult leafConcreteSubtype = holder.findLeafConcreteSubtype(); if (leafConcreteSubtype != null) { ResolvedJavaMethod resolvedMethod = leafConcreteSubtype.getResult().resolveConcreteMethod(targetMethod, contextType); - if (resolvedMethod != null) { - if (leafConcreteSubtype.canRecordTo(callTarget.graph().getAssumptions())) { - return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype); - } else { - return getTypeCheckedAssumptionInfo(invoke, resolvedMethod, leafConcreteSubtype.getResult()); - } + if (resolvedMethod != null && leafConcreteSubtype.canRecordTo(callTarget.graph().getAssumptions())) { + return getAssumptionInlineInfo(invoke, resolvedMethod, leafConcreteSubtype); } } @@ -250,13 +246,6 @@ public class InliningData { return getTypeCheckedInlineInfo(invoke, targetMethod); } - private InlineInfo getTypeCheckedAssumptionInfo(Invoke invoke, ResolvedJavaMethod method, ResolvedJavaType type) { - if (!checkTargetConditions(invoke, method)) { - return null; - } - return new TypeGuardInlineInfo(invoke, method, type); - } - private InlineInfo getTypeCheckedInlineInfo(Invoke invoke, ResolvedJavaMethod targetMethod) { JavaTypeProfile typeProfile = ((MethodCallTargetNode) invoke.callTarget()).getProfile(); if (typeProfile == null) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java similarity index 91% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java index 50cbb926a1..0a7c59ea74 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.phases.common.util; import java.util.EnumSet; -import java.util.HashSet; import java.util.Set; import jdk.internal.vm.compiler.collections.EconomicSet; @@ -37,9 +36,9 @@ import org.graalvm.compiler.graph.Node.IndirectCanonicalization; /** * A simple {@link NodeEventListener} implementation that accumulates event nodes in a - * {@link HashSet}. + * {@link EconomicSet}. */ -public class HashSetNodeEventListener extends NodeEventListener { +public class EconomicSetNodeEventListener extends NodeEventListener { private final EconomicSet nodes; private final Set filter; @@ -47,7 +46,7 @@ public class HashSetNodeEventListener extends NodeEventListener { /** * Creates a {@link NodeEventListener} that collects nodes from all events. */ - public HashSetNodeEventListener() { + public EconomicSetNodeEventListener() { this.nodes = EconomicSet.create(Equivalence.IDENTITY); this.filter = EnumSet.allOf(NodeEvent.class); } @@ -56,7 +55,7 @@ public class HashSetNodeEventListener extends NodeEventListener { * Creates a {@link NodeEventListener} that collects nodes from all events that match a given * filter. */ - public HashSetNodeEventListener(Set filter) { + public EconomicSetNodeEventListener(Set filter) { this.nodes = EconomicSet.create(Equivalence.IDENTITY); this.filter = filter; } @@ -64,7 +63,7 @@ public class HashSetNodeEventListener extends NodeEventListener { /** * Excludes a given event from those for which nodes are collected. */ - public HashSetNodeEventListener exclude(NodeEvent e) { + public EconomicSetNodeEventListener exclude(NodeEvent e) { filter.remove(e); return this; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java index 4246d1b847..7f8957e4c4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/contract/NodeCostUtil.java @@ -83,12 +83,12 @@ public class NodeCostUtil { try (DebugContext.Scope s = debug.scope("NodeCostSummary")) { for (Block block : cfg.getBlocks()) { for (Node n : blockToNodes.apply(block)) { - double probWeighted = n.estimatedNodeCycles().value * block.probability(); + double probWeighted = n.estimatedNodeCycles().value * block.getRelativeFrequency(); assert Double.isFinite(probWeighted); weightedCycles += probWeighted; if (debug.isLogEnabled()) { - debug.log("Node %s contributes cycles:%f size:%d to graph %s [block prob:%f]", n, n.estimatedNodeCycles().value * block.probability(), - n.estimatedNodeSize().value, graph, block.probability()); + debug.log("Node %s contributes cycles:%f size:%d to graph %s [block freq:%f]", n, n.estimatedNodeCycles().value * block.getRelativeFrequency(), + n.estimatedNodeSize().value, graph, block.getRelativeFrequency()); } } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java similarity index 75% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java index 72dbdfb228..43c5bfc454 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java @@ -24,7 +24,7 @@ package org.graalvm.compiler.phases.graph; -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyRelativeFrequencies; import java.util.function.ToDoubleFunction; @@ -44,11 +44,12 @@ import org.graalvm.compiler.nodes.LoopBeginNode; import org.graalvm.compiler.nodes.StartNode; /** - * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s. + * Compute relative frequencies for fixed nodes on the fly and cache them at + * {@link AbstractBeginNode}s. */ -public class FixedNodeProbabilityCache implements ToDoubleFunction { +public class FixedNodeRelativeFrequencyCache implements ToDoubleFunction { - private static final CounterKey computeNodeProbabilityCounter = DebugContext.counter("ComputeNodeProbability"); + private static final CounterKey computeNodeRelativeFrequencyCounter = DebugContext.counter("ComputeNodeRelativeFrequency"); private final EconomicMap cache = EconomicMap.create(Equivalence.IDENTITY); @@ -66,19 +67,19 @@ public class FixedNodeProbabilityCache implements ToDoubleFunction { *

* The thus found {@link AbstractBeginNode} is equi-probable with the {@link FixedNode} it was * obtained from. When computed for the first time (afterwards a cache lookup returns it) that - * probability is computed as follows, again depending on the begin-node's predecessor: + * relative frequency is computed as follows, again depending on the begin-node's predecessor: *

    *
  • No predecessor. In this case the begin-node is either:
  • *
      - *
    • a merge-node, whose probability adds up those of its forward-ends
    • - *
    • a loop-begin, with probability as above multiplied by the loop-frequency
    • + *
    • a merge-node, whose relative frequency adds up those of its forward-ends
    • + *
    • a loop-begin, with frequency as above multiplied by the loop-frequency
    • *
    - *
  • Control-split predecessor: probability of the branch times that of the control-split
  • + *
  • Control-split predecessor: frequency of the branch times that of the control-split
  • *
*

* *

- * As an exception to all the above, a probability of 1 is assumed for a {@link FixedNode} that + * As an exception to all the above, a frequency of 1 is assumed for a {@link FixedNode} that * appears to be dead-code (ie, lacks a predecessor). *

* @@ -86,7 +87,7 @@ public class FixedNodeProbabilityCache implements ToDoubleFunction { @Override public double applyAsDouble(FixedNode node) { assert node != null; - computeNodeProbabilityCounter.increment(node.getDebug()); + computeNodeRelativeFrequencyCounter.increment(node.getDebug()); FixedNode current = findBegin(node); if (current == null) { @@ -100,25 +101,25 @@ public class FixedNodeProbabilityCache implements ToDoubleFunction { return cachedValue; } - double probability = 0.0; + double relativeFrequency = 0.0; if (current.predecessor() == null) { if (current instanceof AbstractMergeNode) { - probability = handleMerge(current, probability); + relativeFrequency = handleMerge(current, relativeFrequency); } else { assert current instanceof StartNode; - probability = 1D; + relativeFrequency = 1D; } } else { ControlSplitNode split = (ControlSplitNode) current.predecessor(); - probability = multiplyProbabilities(split.probability((AbstractBeginNode) current), applyAsDouble(split)); + relativeFrequency = multiplyRelativeFrequencies(split.probability((AbstractBeginNode) current), applyAsDouble(split)); } - assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability; - cache.put(current, probability); - return probability; + assert !Double.isNaN(relativeFrequency) && !Double.isInfinite(relativeFrequency) : current + " " + relativeFrequency; + cache.put(current, relativeFrequency); + return relativeFrequency; } - private double handleMerge(FixedNode current, double probability) { - double result = probability; + private double handleMerge(FixedNode current, double relativeFrequency) { + double result = relativeFrequency; AbstractMergeNode currentMerge = (AbstractMergeNode) current; NodeInputList currentForwardEnds = currentMerge.forwardEnds(); /* @@ -129,7 +130,7 @@ public class FixedNodeProbabilityCache implements ToDoubleFunction { result += applyAsDouble(endNode); } if (current instanceof LoopBeginNode) { - result = multiplyProbabilities(result, ((LoopBeginNode) current).loopFrequency()); + result = multiplyRelativeFrequencies(result, ((LoopBeginNode) current).loopFrequency()); } return result; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java index 707255d25d..b9caa30d29 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java @@ -550,7 +550,7 @@ public final class SchedulePhase extends Phase { Block previousCurrentBlock = currentBlock; currentBlock = currentBlock.getDominator(); if (previousCurrentBlock.isLoopHeader()) { - if (currentBlock.probability() < latestBlock.probability() || ((StructuredGraph) currentNode.graph()).hasValueProxies()) { + if (currentBlock.getRelativeFrequency() < latestBlock.getRelativeFrequency() || ((StructuredGraph) currentNode.graph()).hasValueProxies()) { // Only assign new latest block if frequency is actually lower or if // loop proxies would be required otherwise. latestBlock = currentBlock; @@ -567,7 +567,8 @@ public final class SchedulePhase extends Phase { if (latestBlock != earliestBlock && currentNode instanceof FloatingReadNode) { FloatingReadNode floatingReadNode = (FloatingReadNode) currentNode; - if (isImplicitNullOpportunity(floatingReadNode, earliestBlock) && earliestBlock.probability() < latestBlock.probability() * IMPLICIT_NULL_CHECK_OPPORTUNITY_PROBABILITY_FACTOR) { + if (isImplicitNullOpportunity(floatingReadNode, earliestBlock) && + earliestBlock.getRelativeFrequency() < latestBlock.getRelativeFrequency() * IMPLICIT_NULL_CHECK_OPPORTUNITY_PROBABILITY_FACTOR) { latestBlock = earliestBlock; } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java index c518d77e8c..040ee38b21 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java @@ -24,7 +24,6 @@ package org.graalvm.compiler.phases.util; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.CodeGenProviders; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; @@ -92,11 +91,6 @@ public class Providers implements CodeGenProviders { return lowerer; } - @Override - public ArrayOffsetProvider getArrayOffsetProvider() { - return lowerer; - } - @Override public ConstantReflectionProvider getConstantReflection() { return constantReflection; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java index df3da5863d..3cdb14f217 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyBailoutUsage.java @@ -48,7 +48,16 @@ public class VerifyBailoutUsage extends VerifyPhase { static { try { - AllowedPackagePrefixes = new String[]{getPackageName(PermanentBailoutException.class), "jdk.vm.ci"}; + AllowedPackagePrefixes = new String[]{ + getPackageName(PermanentBailoutException.class), + "jdk.vm.ci", + + // Allows GraalTruffleRuntime.handleAnnotationFailure to throw + // a BailoutException since the org.graalvm.compiler.truffle.runtime + // project can not see the PermanentBailoutException or + // RetryableBailoutException types. + "org.graalvm.compiler.truffle.runtime" + }; } catch (Throwable t) { throw new GraalError(t); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java index c86b777e7d..92d0369db5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/BinaryGraphPrinter.java @@ -229,29 +229,23 @@ public class BinaryGraphPrinter implements @SuppressWarnings({"unchecked", "rawtypes"}) public void nodeProperties(GraphInfo info, Node node, Map props) { node.getDebugProperties((Map) props); - Graph graph = info.graph; - ControlFlowGraph cfg = info.cfg; NodeMap nodeToBlocks = info.nodeToBlocks; - if (cfg != null && DebugOptions.PrintGraphProbabilities.getValue(graph.getOptions()) && node instanceof FixedNode) { - try { - props.put("probability", cfg.blockFor(node).probability()); - } catch (Throwable t) { - props.put("probability", 0.0); - props.put("probability-exception", t); + + if (nodeToBlocks != null) { + Block block = getBlockForNode(node, nodeToBlocks); + if (block != null) { + props.put("relativeFrequency", block.getRelativeFrequency()); + props.put("nodeToBlock", block); } } - try { - props.put("NodeCost-Size", node.estimatedNodeSize()); - props.put("NodeCost-Cycles", node.estimatedNodeCycles()); - } catch (Throwable t) { - props.put("node-cost-exception", t.getMessage()); - } + props.put("nodeCostSize", node.estimatedNodeSize()); + props.put("nodeCostCycles", node.estimatedNodeCycles()); if (nodeToBlocks != null) { Object block = getBlockForNode(node, nodeToBlocks); if (block != null) { - props.put("node-to-block", block); + props.put("nodeToBlock", block); } } @@ -289,13 +283,13 @@ public class BinaryGraphPrinter implements } } - private Object getBlockForNode(Node node, NodeMap nodeToBlocks) { + private Block getBlockForNode(Node node, NodeMap nodeToBlocks) { if (nodeToBlocks.isNew(node)) { - return "NEW (not in schedule)"; + return null; } else { Block block = nodeToBlocks.get(node); if (block != null) { - return block.getId(); + return block; } else if (node instanceof PhiNode) { return getBlockForNode(((PhiNode) node).merge(), nodeToBlocks); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java index 40deeb8207..be0b5d4533 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java @@ -295,7 +295,7 @@ class CFGPrinter extends CompilationPrinter { out.print("loop_depth ").println(block.getLoop().getDepth()); } - out.print("probability ").println(Double.doubleToRawLongBits(block.probability())); + out.print("probability ").println(Double.doubleToRawLongBits(block.getRelativeFrequency())); } private void printNodes(Block block) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/AbstractProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/AbstractProcessor.java index 01868b5a0f..8cdea40ba7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/AbstractProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/AbstractProcessor.java @@ -32,11 +32,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.annotation.processing.FilerException; import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; @@ -62,6 +64,20 @@ public abstract class AbstractProcessor extends javax.annotation.processing.Abst return processingEnv; } + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + // In JDK 8, each annotation processing round has its own Elements object + // so this cache must be cleared at the start of each round. As of JDK9, + // a single Elements is preserved across all annotation processing rounds. + // However, since both behaviors are compliant with the annotation processing + // specification, we unconditionally clear the cache to be safe. + types.clear(); + + return doProcess(annotations, roundEnv); + } + + protected abstract boolean doProcess(Set annotations, RoundEnvironment roundEnv); + private final Map types = new HashMap<>(); /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java index da20c0f198..6b1460dfa2 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java @@ -168,15 +168,13 @@ public class AArch64GraphBuilderPlugins { } private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { - Registration r; - JavaKind[] unsafeJavaKinds; - if (Java8OrEarlier) { - r = new Registration(plugins, Unsafe.class); - unsafeJavaKinds = new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}; - } else { - r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider); - unsafeJavaKinds = new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}; + registerUnsafePlugins(new Registration(plugins, Unsafe.class), new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}); + if (!Java8OrEarlier) { + registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider), new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}); } + } + + private static void registerUnsafePlugins(Registration r, JavaKind[] unsafeJavaKinds) { for (JavaKind kind : unsafeJavaKinds) { Class javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOf.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOf.java new file mode 100644 index 0000000000..331bac64ca --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOf.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.amd64; + +import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor; +import org.graalvm.compiler.graph.Node.ConstantNodeParameter; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import jdk.internal.vm.compiler.word.Pointer; + +import static org.graalvm.compiler.graph.Node.NodeIntrinsic; + +public class AMD64ArrayIndexOf { + + public static final ForeignCallDescriptor STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES = new ForeignCallDescriptor( + "indexOfTwoConsecutiveBytes", int.class, Pointer.class, int.class, int.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS = new ForeignCallDescriptor( + "indexOfTwoConsecutiveChars", int.class, Pointer.class, int.class, int.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_1_BYTE = new ForeignCallDescriptor( + "indexOf1Byte", int.class, Pointer.class, int.class, byte.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_2_BYTES = new ForeignCallDescriptor( + "indexOf2Bytes", int.class, Pointer.class, int.class, byte.class, byte.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_3_BYTES = new ForeignCallDescriptor( + "indexOf3Bytes", int.class, Pointer.class, int.class, byte.class, byte.class, byte.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_4_BYTES = new ForeignCallDescriptor( + "indexOf4Bytes", int.class, Pointer.class, int.class, byte.class, byte.class, byte.class, byte.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_1_CHAR = new ForeignCallDescriptor( + "indexOf1Char", int.class, Pointer.class, int.class, char.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_2_CHARS = new ForeignCallDescriptor( + "indexOf2Chars", int.class, Pointer.class, int.class, char.class, char.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_3_CHARS = new ForeignCallDescriptor( + "indexOf3Chars", int.class, Pointer.class, int.class, char.class, char.class, char.class); + public static final ForeignCallDescriptor STUB_INDEX_OF_4_CHARS = new ForeignCallDescriptor( + "indexOf4Chars", int.class, Pointer.class, int.class, char.class, char.class, char.class, char.class); + + public static int indexOfTwoConsecutiveBytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) { + int searchValue = (Byte.toUnsignedInt(b2) << Byte.SIZE) | Byte.toUnsignedInt(b1); + return callInt(STUB_INDEX_OF_TWO_CONSECUTIVE_BYTES, arrayPointer, arrayLength, searchValue); + } + + public static int indexOfTwoConsecutiveChars(Pointer arrayPointer, int arrayLength, char c1, char c2) { + int searchValue = (c2 << Character.SIZE) | c1; + return callInt(STUB_INDEX_OF_TWO_CONSECUTIVE_CHARS, arrayPointer, arrayLength, searchValue); + } + + public static int indexOf1Byte(Pointer arrayPointer, int arrayLength, byte b) { + return callByte1(STUB_INDEX_OF_1_BYTE, arrayPointer, arrayLength, b); + } + + public static int indexOf2Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2) { + return callByte2(STUB_INDEX_OF_2_BYTES, arrayPointer, arrayLength, b1, b2); + } + + public static int indexOf3Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3) { + return callByte3(STUB_INDEX_OF_3_BYTES, arrayPointer, arrayLength, b1, b2, b3); + } + + public static int indexOf4Bytes(Pointer arrayPointer, int arrayLength, byte b1, byte b2, byte b3, byte b4) { + return callByte4(STUB_INDEX_OF_4_BYTES, arrayPointer, arrayLength, b1, b2, b3, b4); + } + + public static int indexOf1Char(Pointer arrayPointer, int arrayLength, char c) { + return callChar1(STUB_INDEX_OF_1_CHAR, arrayPointer, arrayLength, c); + } + + public static int indexOf2Chars(Pointer arrayPointer, int arrayLength, char c1, char c2) { + return callChar2(STUB_INDEX_OF_2_CHARS, arrayPointer, arrayLength, c1, c2); + } + + public static int indexOf3Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3) { + return callChar3(STUB_INDEX_OF_3_CHARS, arrayPointer, arrayLength, c1, c2, c3); + } + + public static int indexOf4Chars(Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4) { + return callChar4(STUB_INDEX_OF_4_CHARS, arrayPointer, arrayLength, c1, c2, c3, c4); + } + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callInt(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, int v1); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callByte1(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callByte2(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callByte3(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2, byte v3); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callByte4(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, byte v1, byte v2, byte v3, byte v4); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callChar1(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callChar2(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callChar3(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2, char v3); + + @NodeIntrinsic(value = ForeignCallNode.class) + private static native int callChar4(@ConstantNodeParameter ForeignCallDescriptor descriptor, Pointer arrayPointer, int arrayLength, char v1, char v2, char v3, char v4); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java index e371100fc6..cbc935a395 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64ArrayIndexOfNode.java @@ -24,10 +24,11 @@ package org.graalvm.compiler.replacements.amd64; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512; - +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeInputList; import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeCycles; import org.graalvm.compiler.nodeinfo.NodeInfo; @@ -42,8 +43,7 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.internal.vm.compiler.word.Pointer; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Value; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512; @NodeInfo(size = SIZE_512, cycles = NodeCycles.CYCLES_UNKNOWN) public class AMD64ArrayIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess { @@ -51,19 +51,26 @@ public class AMD64ArrayIndexOfNode extends FixedWithNextNode implements LIRLower public static final NodeClass TYPE = NodeClass.create(AMD64ArrayIndexOfNode.class); private final JavaKind kind; + private final boolean findTwoConsecutive; @Input private ValueNode arrayPointer; @Input private ValueNode arrayLength; - @Input private ValueNode searchValue; + @Input private NodeInputList searchValues; @OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess; - public AMD64ArrayIndexOfNode(ValueNode arrayPointer, ValueNode arrayLength, ValueNode searchValue, @ConstantNodeParameter JavaKind kind) { + public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind kind, @ConstantNodeParameter boolean findTwoConsecutive, + ValueNode arrayPointer, ValueNode arrayLength, ValueNode... searchValues) { super(TYPE, StampFactory.forKind(JavaKind.Int)); this.kind = kind; + this.findTwoConsecutive = findTwoConsecutive; this.arrayPointer = arrayPointer; this.arrayLength = arrayLength; - this.searchValue = searchValue; + this.searchValues = new NodeInputList<>(this, searchValues); + } + + public AMD64ArrayIndexOfNode(@ConstantNodeParameter JavaKind kind, ValueNode arrayPointer, ValueNode arrayLength, ValueNode... searchValues) { + this(kind, false, arrayPointer, arrayLength, searchValues); } @Override @@ -73,7 +80,11 @@ public class AMD64ArrayIndexOfNode extends FixedWithNextNode implements LIRLower @Override public void generate(NodeLIRBuilderTool gen) { - Value result = gen.getLIRGeneratorTool().emitArrayIndexOf(kind, gen.operand(arrayPointer), gen.operand(arrayLength), gen.operand(searchValue)); + Value[] searchValueOperands = new Value[searchValues.size()]; + for (int i = 0; i < searchValues.size(); i++) { + searchValueOperands[i] = gen.operand(searchValues.get(i)); + } + Value result = gen.getLIRGeneratorTool().emitArrayIndexOf(kind, findTwoConsecutive, gen.operand(arrayPointer), gen.operand(arrayLength), searchValueOperands); gen.setResult(this, result); } @@ -89,5 +100,30 @@ public class AMD64ArrayIndexOfNode extends FixedWithNextNode implements LIRLower } @NodeIntrinsic - public static native int optimizedArrayIndexOf(Pointer arrayPointer, int arrayLength, char searchValue, @ConstantNodeParameter JavaKind kind); + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, @ConstantNodeParameter boolean findTwoConsecutive, + Pointer arrayPointer, int arrayLength, int searchValue); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2, char c3); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, char c1, char c2, char c3, char c4); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2, byte c3); + + @NodeIntrinsic + public static native int optimizedArrayIndexOf(@ConstantNodeParameter JavaKind kind, Pointer arrayPointer, int arrayLength, byte c1, byte c2, byte c3, byte c4); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java index d5303de3e9..89aac60478 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java @@ -212,6 +212,9 @@ public class AMD64GraphBuilderPlugins { r.setAllowOverwrite(true); r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); + r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, char[].class, int.class, int.class); + r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, byte[].class, int.class, int.class); + if (arch.getFeatures().contains(CPUFeature.SSSE3)) { r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, int.class); } @@ -224,6 +227,9 @@ public class AMD64GraphBuilderPlugins { r.setAllowOverwrite(true); r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); + r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", char[].class, int.class, byte[].class, int.class, int.class); + r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", byte[].class, int.class, byte[].class, int.class, int.class); + if (arch.getFeatures().contains(CPUFeature.SSSE3)) { r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfCharUnsafe", byte[].class, int.class, int.class, int.class); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java new file mode 100644 index 0000000000..aa4f05b4ce --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1InflateNode.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.amd64; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValueNodeUtil; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; + +import jdk.vm.ci.meta.JavaKind; + +@NodeInfo(allowedUsageTypes = Memory, size = SIZE_512, cycles = CYCLES_UNKNOWN) + +public final class AMD64StringLatin1InflateNode extends FixedWithNextNode + implements LIRLowerable, MemoryCheckpoint.Multi, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(AMD64StringLatin1InflateNode.class); + + @Input private ValueNode src; + @Input private ValueNode dst; + @Input private ValueNode len; + + private final JavaKind writeKind; + + @OptionalInput(Memory) private MemoryNode lla; // Last access location registered. + + // java.lang.StringLatin1.inflate([BI[CII)V + // + // void inflate(byte[] src, int src_indx, char[] dst, int dst_indx, int len) + // + // Represented as a graph node by: + + public AMD64StringLatin1InflateNode(ValueNode src, ValueNode dst, ValueNode len, JavaKind writeKind) { + super(TYPE, StampFactory.forVoid()); + this.src = src; + this.dst = dst; + this.len = len; + this.writeKind = writeKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + // Model read access via 'src' using: + return NamedLocationIdentity.getArrayLocation(JavaKind.Byte); + } + + @Override + public LocationIdentity[] getLocationIdentities() { + // Model write access via 'dst' using: + return new LocationIdentity[]{NamedLocationIdentity.getArrayLocation(writeKind)}; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool lgt = gen.getLIRGeneratorTool(); + lgt.emitStringLatin1Inflate(gen.operand(src), gen.operand(dst), gen.operand(len)); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lla; + } + + @Override + public void setLastLocationAccess(MemoryNode newlla) { + updateUsages(ValueNodeUtil.asNode(lla), ValueNodeUtil.asNode(newlla)); + lla = newlla; + } + + @NodeIntrinsic + public static native void inflate(Pointer src, Pointer dst, int len, @ConstantNodeParameter JavaKind writeKind); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java index 463e7fba77..811ee02afd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringLatin1Substitutions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,16 +24,20 @@ package org.graalvm.compiler.replacements.amd64; -import jdk.vm.ci.meta.JavaKind; import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; +import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; import org.graalvm.compiler.word.Word; import jdk.internal.vm.compiler.word.Pointer; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; + // JaCoCo Exclude /** @@ -45,12 +49,27 @@ import jdk.internal.vm.compiler.word.Pointer; public class AMD64StringLatin1Substitutions { @Fold - static int byteArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayBaseOffset(JavaKind.Byte); + static int byteArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Byte); + } + + @Fold + static int byteArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayIndexScale(JavaKind.Byte); + } + + @Fold + static int charArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Char); + } + + @Fold + static int charArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayIndexScale(JavaKind.Char); } /** Marker value for the {@link InjectedParameter} injected parameter. */ - static final ArrayOffsetProvider INJECTED = null; + static final MetaAccessProvider INJECTED = null; /** * @param value is byte[] @@ -85,10 +104,55 @@ public class AMD64StringLatin1Substitutions { return -1; } Pointer sourcePointer = Word.objectToTrackedPointer(value).add(byteArrayBaseOffset(INJECTED)).add(fromIndex); - int result = AMD64ArrayIndexOfNode.optimizedArrayIndexOf(sourcePointer, length - fromIndex, (char) ch, JavaKind.Byte); + int result = AMD64ArrayIndexOf.indexOf1Byte(sourcePointer, length - fromIndex, (byte) ch); if (result != -1) { return result + fromIndex; } return result; } + + /** + * Intrinsic for {@code java.lang.StringLatin1.inflate([BI[CII)V}. + * + *
+     * @HotSpotIntrinsicCandidate
+     * public static void inflate(byte[] src, int src_indx, char[] dst, int dst_indx, int len)
+     * 
+ */ + @MethodSubstitution + public static void inflate(byte[] src, int srcIndex, char[] dest, int destIndex, int len) { + if (len < 0 || srcIndex < 0 || (srcIndex + len > src.length) || destIndex < 0 || (destIndex + len > dest.length)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); + } + + // Offset calc. outside of the actual intrinsic. + Pointer srcPointer = Word.objectToTrackedPointer(src).add(byteArrayBaseOffset(INJECTED)).add(srcIndex * byteArrayIndexScale(INJECTED)); + Pointer destPointer = Word.objectToTrackedPointer(dest).add(charArrayBaseOffset(INJECTED)).add(destIndex * charArrayIndexScale(INJECTED)); + AMD64StringLatin1InflateNode.inflate(srcPointer, destPointer, len, JavaKind.Char); + } + + /** + * Intrinsic for {@code }java.lang.StringLatin1.inflate([BI[BII)V}. + * + *
+     * @HotSpotIntrinsicCandidate
+     * public static void inflate(byte[] src, int src_indx, byte[] dst, int dst_indx, int len)
+     * 
+ * + * In this variant {@code dest} refers to a byte array containing 2 byte per char so + * {@code destIndex} and {@code len} are in terms of char elements and have to be scaled by 2 + * when referring to {@code dest} + */ + @MethodSubstitution + public static void inflate(byte[] src, int srcIndex, byte[] dest, int destIndex, int len) { + if (len < 0 || srcIndex < 0 || (srcIndex + len > src.length) || destIndex < 0 || (destIndex * 2 + len * 2 > dest.length)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); + } + + // Offset calc. outside of the actual intrinsic. + Pointer srcPointer = Word.objectToTrackedPointer(src).add(byteArrayBaseOffset(INJECTED)).add(srcIndex * byteArrayIndexScale(INJECTED)); + Pointer destPointer = Word.objectToTrackedPointer(dest).add(byteArrayBaseOffset(INJECTED)).add(destIndex * 2 * byteArrayIndexScale(INJECTED)); + AMD64StringLatin1InflateNode.inflate(srcPointer, destPointer, len, JavaKind.Byte); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java index 706c96c3b3..e91f8b8c64 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java @@ -29,14 +29,15 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.MethodSubstitution; import org.graalvm.compiler.core.common.SuppressFBWarnings; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.graph.Node.ConstantNodeParameter; import org.graalvm.compiler.replacements.StringSubstitutions; import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; +import org.graalvm.compiler.replacements.nodes.ArrayRegionEqualsNode; import org.graalvm.compiler.word.Word; import jdk.internal.vm.compiler.word.Pointer; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; // JaCoCo Exclude @@ -47,17 +48,17 @@ import jdk.vm.ci.meta.JavaKind; public class AMD64StringSubstitutions { @Fold - static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char); + static int charArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Char); } @Fold - static int charArrayIndexScale(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayScalingFactor(JavaKind.Char); + static int charArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayIndexScale(JavaKind.Char); } /** Marker value for the {@link InjectedParameter} injected parameter. */ - static final ArrayOffsetProvider INJECTED = null; + static final MetaAccessProvider INJECTED = null; // Only exists in JDK <= 8 @MethodSubstitution(isStatic = true, optional = true) @@ -83,13 +84,39 @@ public class AMD64StringSubstitutions { } assert sourceCount - fromIndex > 0 && targetCount > 0; - Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); - Pointer targetPointer = Word.objectToTrackedPointer(target).add(charArrayBaseOffset(INJECTED)).add(targetOffset * charArrayIndexScale(INJECTED)); - int result = AMD64StringIndexOfNode.optimizedStringIndexPointer(sourcePointer, sourceCount - fromIndex, targetPointer, targetCount); - if (result >= 0) { - return result + totalOffset; + if (targetCount == 1) { + Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); + int indexOfResult = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, target[targetOffset]); + if (indexOfResult >= 0) { + return indexOfResult + totalOffset; + } + return indexOfResult; + } else if (targetCount == 2) { + Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); + int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, sourceCount - fromIndex, target[targetOffset], target[targetOffset + 1]); + if (indexOfResult >= 0) { + return indexOfResult + totalOffset; + } + return indexOfResult; + } else { + int haystackLength = sourceCount - (fromIndex + (targetCount - 2)); + while (haystackLength > 0) { + Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); + int indexOfResult = AMD64ArrayIndexOf.indexOfTwoConsecutiveChars(sourcePointer, haystackLength, target[targetOffset], target[targetOffset + 1]); + if (indexOfResult < 0) { + return -1; + } + totalOffset += indexOfResult; + haystackLength -= (indexOfResult + 1); + Pointer cmpSourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED)); + Pointer targetPointer = Word.objectToTrackedPointer(target).add(charArrayBaseOffset(INJECTED)).add(targetOffset * charArrayIndexScale(INJECTED)); + if (ArrayRegionEqualsNode.regionEquals(cmpSourcePointer, targetPointer, targetCount, JavaKind.Char)) { + return totalOffset; + } + totalOffset++; + } + return -1; } - return result; } // Only exists in JDK <= 8 @@ -109,7 +136,7 @@ public class AMD64StringSubstitutions { char[] sourceArray = StringSubstitutions.getValue(source); Pointer sourcePointer = Word.objectToTrackedPointer(sourceArray).add(charArrayBaseOffset(INJECTED)).add(fromIndex * charArrayIndexScale(INJECTED)); - int result = AMD64ArrayIndexOfNode.optimizedArrayIndexOf(sourcePointer, sourceCount - fromIndex, (char) ch, JavaKind.Char); + int result = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, sourceCount - fromIndex, (char) ch); if (result != -1) { return result + fromIndex; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java new file mode 100644 index 0000000000..a39f15c27a --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16CompressNode.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.amd64; + +import static org.graalvm.compiler.nodeinfo.InputType.Memory; +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_512; + +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.lir.gen.LIRGeneratorTool; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.NamedLocationIdentity; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.ValueNodeUtil; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.MemoryNode; +import org.graalvm.compiler.nodes.spi.LIRLowerable; +import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; +import jdk.internal.vm.compiler.word.LocationIdentity; +import jdk.internal.vm.compiler.word.Pointer; + +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; + +@NodeInfo(allowedUsageTypes = Memory, size = SIZE_512, cycles = CYCLES_UNKNOWN) + +public final class AMD64StringUTF16CompressNode extends FixedWithNextNode + implements LIRLowerable, MemoryCheckpoint.Multi, MemoryAccess { + + public static final NodeClass TYPE = NodeClass.create(AMD64StringUTF16CompressNode.class); + + @Input private ValueNode src; + @Input private ValueNode dst; + @Input private ValueNode len; + final JavaKind readKind; + + @OptionalInput(Memory) private MemoryNode lla; // Last access location registered. + + // java.lang.StringUTF16.compress([CI[BII)I + // + // int compress(char[] src, int src_indx, byte[] dst, int dst_indx, int len) + // + // Represented as a graph node by: + + public AMD64StringUTF16CompressNode(ValueNode src, ValueNode dst, ValueNode len, JavaKind readKind) { + super(TYPE, StampFactory.forInteger(32)); + this.src = src; + this.dst = dst; + this.len = len; + this.readKind = readKind; + } + + @Override + public LocationIdentity getLocationIdentity() { + // Model read access via 'src' using: + return NamedLocationIdentity.getArrayLocation(readKind); + } + + @Override + public LocationIdentity[] getLocationIdentities() { + // Model write access via 'dst' using: + return new LocationIdentity[]{NamedLocationIdentity.getArrayLocation(JavaKind.Byte)}; + } + + @Override + public void generate(NodeLIRBuilderTool gen) { + LIRGeneratorTool lgt = gen.getLIRGeneratorTool(); + Value res = lgt.emitStringUTF16Compress(gen.operand(src), gen.operand(dst), gen.operand(len)); + gen.setResult(this, res); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lla; + } + + @Override + public void setLastLocationAccess(MemoryNode newlla) { + updateUsages(ValueNodeUtil.asNode(lla), ValueNodeUtil.asNode(newlla)); + lla = newlla; + } + + @NodeIntrinsic + public static native int compress(Pointer src, Pointer dst, int len, @ConstantNodeParameter JavaKind readKind); +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java index e16dabac61..8789d742fd 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringUTF16Substitutions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,13 +28,16 @@ import org.graalvm.compiler.api.replacements.ClassSubstitution; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.MethodSubstitution; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; +import org.graalvm.compiler.nodes.DeoptimizeNode; import org.graalvm.compiler.replacements.nodes.ArrayCompareToNode; - -import jdk.vm.ci.meta.JavaKind; import org.graalvm.compiler.word.Word; import jdk.internal.vm.compiler.word.Pointer; +import jdk.vm.ci.meta.DeoptimizationAction; +import jdk.vm.ci.meta.DeoptimizationReason; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; + // JaCoCo Exclude /** @@ -46,17 +49,27 @@ import jdk.internal.vm.compiler.word.Pointer; public class AMD64StringUTF16Substitutions { @Fold - static int byteArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayBaseOffset(JavaKind.Byte); + static int byteArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Byte); } @Fold - static int charArrayIndexScale(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayScalingFactor(JavaKind.Char); + static int byteArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayIndexScale(JavaKind.Byte); + } + + @Fold + static int charArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Char); + } + + @Fold + static int charArrayIndexScale(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayIndexScale(JavaKind.Char); } /** Marker value for the {@link InjectedParameter} injected parameter. */ - static final ArrayOffsetProvider INJECTED = null; + static final MetaAccessProvider INJECTED = null; /** * @param value is char[] @@ -83,10 +96,53 @@ public class AMD64StringUTF16Substitutions { @MethodSubstitution(optional = true) public static int indexOfCharUnsafe(byte[] value, int ch, int fromIndex, int max) { Pointer sourcePointer = Word.objectToTrackedPointer(value).add(byteArrayBaseOffset(INJECTED)).add(fromIndex * charArrayIndexScale(INJECTED)); - int result = AMD64ArrayIndexOfNode.optimizedArrayIndexOf(sourcePointer, max - fromIndex, (char) ch, JavaKind.Char); + int result = AMD64ArrayIndexOf.indexOf1Char(sourcePointer, max - fromIndex, (char) ch); if (result != -1) { return result + fromIndex; } return result; } + + /** + * Intrinsic for {@code java.lang.StringUTF16.compress([CI[BII)I}. + * + *
+     * @HotSpotIntrinsicCandidate
+     * public static int compress(char[] src, int src_indx, byte[] dst, int dst_indx, int len)
+     * 
+ */ + @MethodSubstitution + public static int compress(char[] src, int srcIndex, byte[] dest, int destIndex, int len) { + if (len < 0 || srcIndex < 0 || (srcIndex + len > src.length) || destIndex < 0 || (destIndex + len > dest.length)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); + } + + Pointer srcPointer = Word.objectToTrackedPointer(src).add(charArrayBaseOffset(INJECTED)).add(srcIndex * charArrayIndexScale(INJECTED)); + Pointer destPointer = Word.objectToTrackedPointer(dest).add(byteArrayBaseOffset(INJECTED)).add(destIndex * byteArrayIndexScale(INJECTED)); + return AMD64StringUTF16CompressNode.compress(srcPointer, destPointer, len, JavaKind.Char); + } + + /** + * Intrinsic for {@code }java.lang.StringUTF16.compress([BI[BII)I}. + * + *
+     * @HotSpotIntrinsicCandidate
+     * public static int compress(byte[] src, int src_indx, byte[] dst, int dst_indx, int len)
+     * 
+ * + * In this variant {@code dest} refers to a byte array containing 2 byte per char so + * {@code srcIndex} and {@code len} are in terms of char elements and have to be scaled by 2 + * when referring to {@code src}. + */ + @MethodSubstitution + public static int compress(byte[] src, int srcIndex, byte[] dest, int destIndex, int len) { + if (len < 0 || srcIndex < 0 || (srcIndex * 2 + len * 2 > src.length) || destIndex < 0 || (destIndex + len > dest.length)) { + DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.BoundsCheckException); + } + + Pointer srcPointer = Word.objectToTrackedPointer(src).add(byteArrayBaseOffset(INJECTED)).add(srcIndex * 2 * byteArrayIndexScale(INJECTED)); + Pointer destPointer = Word.objectToTrackedPointer(dest).add(byteArrayBaseOffset(INJECTED)).add(destIndex * byteArrayIndexScale(INJECTED)); + return AMD64StringUTF16CompressNode.compress(srcPointer, destPointer, len, JavaKind.Byte); + } + } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk12.test/src/org/graalvm/compiler/replacements/jdk12/test/UnsafeObjectReplacementsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk12.test/src/org/graalvm/compiler/replacements/jdk12/test/UnsafeObjectReplacementsTest.java new file mode 100644 index 0000000000..7e1ed24ac0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk12.test/src/org/graalvm/compiler/replacements/jdk12/test/UnsafeObjectReplacementsTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.jdk12.test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.AddExports; +import org.junit.Test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.TargetDescription; + +/** + * As of JDK 12 {@code jdk.internal.misc.Unsafe::.*Object()} methods were renamed to + * {@code .*Reference()}. + * + * @see "https://bugs.openjdk.java.net/browse/JDK-8207146" + */ +@AddExports("java.base/jdk.internal.misc") +public class UnsafeObjectReplacementsTest extends MethodSubstitutionTest { + + static class Container { + public volatile Object objectField = dummyValue; + } + + static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); + static Container dummyValue = new Container(); + static Container newDummyValue = new Container(); + static long objectOffset; + + static { + try { + objectOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("objectField")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + public static Object unsafeCompareAndExchangeReference() { + Container container = new Container(); + return unsafe.compareAndExchangeReference(container, objectOffset, dummyValue, newDummyValue); + } + + @Test + public void testCompareAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64) { + testGraph("unsafeCompareAndExchangeReference"); + } + test("unsafeCompareAndExchangeReference"); + } + + public static Object unsafeGetAndSetReference() { + Container container = new Container(); + container.objectField = null; + Container other = new Container(); + return unsafe.getAndSetReference(container, objectOffset, other); + } + + @Test + public void testGetAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { + testGraph("unsafeGetAndSetReference"); + } + test("unsafeGetAndSetReference"); + } + + public static Object unsafeGetPutReference() { + Container container = new Container(); + unsafe.putReference(container, objectOffset, "Hello there"); + return unsafe.getReference(container, objectOffset); + } + + public static Object unsafeGetPutReferenceOpaque() { + Container container = new Container(); + unsafe.putReferenceOpaque(container, objectOffset, "Hello there"); + return unsafe.getReferenceOpaque(container, objectOffset); + } + + public static Object unsafeGetPutReferenceRA() { + Container container = new Container(); + unsafe.putReferenceRelease(container, objectOffset, "Hello there"); + return unsafe.getReferenceAcquire(container, objectOffset); + } + + public static Object unsafeGetPutReferenceVolatile() { + Container container = new Container(); + unsafe.putReferenceVolatile(container, objectOffset, "Hello there"); + return unsafe.getReferenceVolatile(container, objectOffset); + } + + @Test + public void testUnsafeGetPutPlain() { + testGraph("unsafeGetPutReference"); + test("unsafeGetPutReference"); + } + + @Test + public void testUnsafeGetPutOpaque() { + testGraph("unsafeGetPutReferenceOpaque"); + test("unsafeGetPutReferenceOpaque"); + } + + @Test + public void testUnsafeGetPutReleaseAcquire() { + testGraph("unsafeGetPutReferenceRA"); + test("unsafeGetPutReferenceRA"); + } + + @Test + public void testUnsafeGetPutVolatile() { + testGraph("unsafeGetPutReferenceVolatile"); + test("unsafeGetPutReferenceVolatile"); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/UnsafeReplacementsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/UnsafeReplacementsTest.java similarity index 92% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/UnsafeReplacementsTest.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/UnsafeReplacementsTest.java index 3ec708c330..18ef92a16b 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/UnsafeReplacementsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/UnsafeReplacementsTest.java @@ -22,7 +22,7 @@ */ -package org.graalvm.compiler.replacements.jdk9; +package org.graalvm.compiler.replacements.jdk9.test; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; @@ -49,7 +49,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { public volatile long longField = 0xdedababafafaL; public volatile float floatField = 0.125f; public volatile double doubleField = 0.125; - public volatile Object objectField = dummyValue; } static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); @@ -63,7 +62,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { static long longOffset; static long floatOffset; static long doubleOffset; - static long objectOffset; static { try { @@ -75,7 +73,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { longOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("longField")); floatOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("floatField")); doubleOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("doubleField")); - objectOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("objectField")); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } @@ -121,11 +118,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.compareAndSetDouble(container, doubleOffset, 0.125, 0.25); } - public static boolean unsafeCompareAndSetReference() { - Container container = new Container(); - return unsafe.compareAndSetReference(container, objectOffset, dummyValue, newDummyValue); - } - public static boolean unsafeCompareAndExchangeBoolean() { Container container = new Container(); return unsafe.compareAndExchangeBoolean(container, booleanOffset, false, true); @@ -166,11 +158,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.compareAndExchangeDouble(container, doubleOffset, 0.125, 0.25); } - public static Object unsafeCompareAndExchangeReference() { - Container container = new Container(); - return unsafe.compareAndExchangeReference(container, objectOffset, dummyValue, newDummyValue); - } - @Test public void testCompareAndSet() { TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); @@ -183,7 +170,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeCompareAndSetLong"); testGraph("unsafeCompareAndSetFloat"); testGraph("unsafeCompareAndSetDouble"); - testGraph("unsafeCompareAndSetReference"); testGraph("unsafeCompareAndExchangeBoolean"); testGraph("unsafeCompareAndExchangeByte"); testGraph("unsafeCompareAndExchangeChar"); @@ -192,7 +178,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeCompareAndExchangeLong"); testGraph("unsafeCompareAndExchangeFloat"); testGraph("unsafeCompareAndExchangeDouble"); - testGraph("unsafeCompareAndExchangeReference"); } test("unsafeCompareAndSetBoolean"); test("unsafeCompareAndSetByte"); @@ -202,7 +187,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeCompareAndSetLong"); test("unsafeCompareAndSetFloat"); test("unsafeCompareAndSetDouble"); - test("unsafeCompareAndSetReference"); test("unsafeCompareAndExchangeBoolean"); test("unsafeCompareAndExchangeByte"); test("unsafeCompareAndExchangeChar"); @@ -211,7 +195,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeCompareAndExchangeLong"); test("unsafeCompareAndExchangeFloat"); test("unsafeCompareAndExchangeDouble"); - test("unsafeCompareAndExchangeReference"); } public static int unsafeGetAndAddByte() { @@ -288,13 +271,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.getAndSetLong(container, longOffset, 0x12345678abL); } - public static Object unsafeGetAndSetReference() { - Container container = new Container(); - container.objectField = null; - Container other = new Container(); - return unsafe.getAndSetReference(container, objectOffset, other); - } - @Test public void testGetAndSet() { TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); @@ -307,7 +283,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { testGraph("unsafeGetAndSetInt"); testGraph("unsafeGetAndSetLong"); - testGraph("unsafeGetAndSetReference"); } test("unsafeGetAndSetBoolean"); test("unsafeGetAndSetByte"); @@ -315,7 +290,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeGetAndSetShort"); test("unsafeGetAndSetInt"); test("unsafeGetAndSetLong"); - test("unsafeGetAndSetReference"); } public static void fieldInstance() { @@ -562,12 +536,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.getDouble(container, doubleOffset); } - public static Object unsafeGetPutReference() { - Container container = new Container(); - unsafe.putReference(container, objectOffset, "Hello there"); - return unsafe.getReference(container, objectOffset); - } - public static boolean unsafeGetPutBooleanOpaque() { Container container = new Container(); unsafe.putBooleanOpaque(container, booleanOffset, true); @@ -616,12 +584,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.getDoubleOpaque(container, doubleOffset); } - public static Object unsafeGetPutReferenceOpaque() { - Container container = new Container(); - unsafe.putReferenceOpaque(container, objectOffset, "Hello there"); - return unsafe.getReferenceOpaque(container, objectOffset); - } - public static boolean unsafeGetPutBooleanRA() { Container container = new Container(); unsafe.putBooleanRelease(container, booleanOffset, true); @@ -670,12 +632,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.getDoubleAcquire(container, doubleOffset); } - public static Object unsafeGetPutReferenceRA() { - Container container = new Container(); - unsafe.putReferenceRelease(container, objectOffset, "Hello there"); - return unsafe.getReferenceAcquire(container, objectOffset); - } - public static boolean unsafeGetPutBooleanVolatile() { Container container = new Container(); unsafe.putBooleanVolatile(container, booleanOffset, true); @@ -724,12 +680,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { return unsafe.getDoubleVolatile(container, doubleOffset); } - public static Object unsafeGetPutReferenceVolatile() { - Container container = new Container(); - unsafe.putReferenceVolatile(container, objectOffset, "Hello there"); - return unsafe.getReferenceVolatile(container, objectOffset); - } - @Test public void testUnsafeGetPutPlain() { testGraph("unsafeGetPutBoolean"); @@ -740,7 +690,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeGetPutLong"); testGraph("unsafeGetPutFloat"); testGraph("unsafeGetPutDouble"); - testGraph("unsafeGetPutObject"); test("unsafeGetPutBoolean"); test("unsafeGetPutByte"); @@ -750,7 +699,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeGetPutLong"); test("unsafeGetPutFloat"); test("unsafeGetPutDouble"); - test("unsafeGetPutObject"); } @Test @@ -763,7 +711,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeGetPutLongOpaque"); testGraph("unsafeGetPutFloatOpaque"); testGraph("unsafeGetPutDoubleOpaque"); - testGraph("unsafeGetPutObjectOpaque"); test("unsafeGetPutBooleanOpaque"); test("unsafeGetPutByteOpaque"); @@ -773,7 +720,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeGetPutLongOpaque"); test("unsafeGetPutFloatOpaque"); test("unsafeGetPutDoubleOpaque"); - test("unsafeGetPutObjectOpaque"); } @Test @@ -786,7 +732,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeGetPutLongRA"); testGraph("unsafeGetPutFloatRA"); testGraph("unsafeGetPutDoubleRA"); - testGraph("unsafeGetPutReferenceRA"); test("unsafeGetPutBooleanRA"); test("unsafeGetPutByteRA"); @@ -796,7 +741,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeGetPutLongRA"); test("unsafeGetPutFloatRA"); test("unsafeGetPutDoubleRA"); - test("unsafeGetPutReferenceRA"); } @Test @@ -809,7 +753,6 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { testGraph("unsafeGetPutLongVolatile"); testGraph("unsafeGetPutFloatVolatile"); testGraph("unsafeGetPutDoubleVolatile"); - testGraph("unsafeGetPutReferenceVolatile"); test("unsafeGetPutBooleanVolatile"); test("unsafeGetPutByteVolatile"); @@ -819,6 +762,5 @@ public class UnsafeReplacementsTest extends MethodSubstitutionTest { test("unsafeGetPutLongVolatile"); test("unsafeGetPutFloatVolatile"); test("unsafeGetPutDoubleVolatile"); - test("unsafeGetPutReferenceVolatile"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/VarHandleTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java similarity index 99% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/VarHandleTest.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java index 3ed43cd939..85cd17c9d6 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/VarHandleTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java @@ -22,7 +22,7 @@ */ -package org.graalvm.compiler.replacements.jdk9; +package org.graalvm.compiler.replacements.jdk9.test; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9_11.test/src/org/graalvm/compiler/replacements/jdk9_11/test/UnsafeObjectReplacementsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9_11.test/src/org/graalvm/compiler/replacements/jdk9_11/test/UnsafeObjectReplacementsTest.java new file mode 100644 index 0000000000..a7d3e39a8d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9_11.test/src/org/graalvm/compiler/replacements/jdk9_11/test/UnsafeObjectReplacementsTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.jdk9_11.test; + +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.AddExports; +import org.junit.Test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.TargetDescription; + +@AddExports("java.base/jdk.internal.misc") +public class UnsafeObjectReplacementsTest extends MethodSubstitutionTest { + + static class Container { + public volatile Object objectField = dummyValue; + } + + static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); + static Container dummyValue = new Container(); + static Container newDummyValue = new Container(); + static long objectOffset; + + static { + try { + objectOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("objectField")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + public static Object unsafeCompareAndExchangeObject() { + Container container = new Container(); + return unsafe.compareAndExchangeObject(container, objectOffset, dummyValue, newDummyValue); + } + + @Test + public void testCompareAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64) { + testGraph("unsafeCompareAndExchangeObject"); + } + test("unsafeCompareAndExchangeObject"); + } + + public static Object unsafeGetAndSetObject() { + Container container = new Container(); + container.objectField = null; + Container other = new Container(); + return unsafe.getAndSetObject(container, objectOffset, other); + } + + @Test + public void testGetAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { + testGraph("unsafeGetAndSetObject"); + } + test("unsafeGetAndSetObject"); + } + + public static Object unsafeGetPutObject() { + Container container = new Container(); + unsafe.putObject(container, objectOffset, "Hello there"); + return unsafe.getObject(container, objectOffset); + } + + public static Object unsafeGetPutObjectOpaque() { + Container container = new Container(); + unsafe.putObjectOpaque(container, objectOffset, "Hello there"); + return unsafe.getObjectOpaque(container, objectOffset); + } + + public static Object unsafeGetPutObjectRA() { + Container container = new Container(); + unsafe.putObjectRelease(container, objectOffset, "Hello there"); + return unsafe.getObjectAcquire(container, objectOffset); + } + + public static Object unsafeGetPutObjectVolatile() { + Container container = new Container(); + unsafe.putObjectVolatile(container, objectOffset, "Hello there"); + return unsafe.getObjectVolatile(container, objectOffset); + } + + @Test + public void testUnsafeGetPutPlain() { + testGraph("unsafeGetPutObject"); + test("unsafeGetPutObject"); + } + + @Test + public void testUnsafeGetPutOpaque() { + testGraph("unsafeGetPutObjectOpaque"); + test("unsafeGetPutObjectOpaque"); + } + + @Test + public void testUnsafeGetPutReleaseAcquire() { + testGraph("unsafeGetPutObjectRA"); + test("unsafeGetPutObjectRA"); + } + + @Test + public void testUnsafeGetPutVolatile() { + testGraph("unsafeGetPutObjectVolatile"); + test("unsafeGetPutObjectVolatile"); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java index ff5e47115f..70035f4cb9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java @@ -84,8 +84,8 @@ public class GeneratedFoldPlugin extends GeneratedPlugin { if (processor.getAnnotation(param, processor.getType(INJECTED_PARAMETER_CLASS_NAME)) == null) { constantArgument(processor, out, deps, argCount, param.asType(), argCount); } else { - out.printf(" assert checkInjectedArgument(b, args[%d], targetMethod);\n", argCount); - out.printf(" %s arg%d = %s;\n", param.asType(), argCount, deps.use(processor, (DeclaredType) param.asType())); + out.printf(" assert checkInjectedArgument(b, args[%d], targetMethod);\n", argCount); + out.printf(" %s arg%d = %s;\n", param.asType(), argCount, deps.use(processor, (DeclaredType) param.asType())); } argCount++; } @@ -103,7 +103,7 @@ public class GeneratedFoldPlugin extends GeneratedPlugin { } } if (suppressWarnings.size() > 0) { - out.printf(" @SuppressWarnings({"); + out.printf(" @SuppressWarnings({"); String sep = ""; for (String suppressWarning : suppressWarnings) { out.printf("%s\"%s\"", sep, suppressWarning); @@ -112,7 +112,7 @@ public class GeneratedFoldPlugin extends GeneratedPlugin { out.printf("})\n"); } - out.printf(" %s result = %s.%s(", getErasedType(intrinsicMethod.getReturnType()), receiver, intrinsicMethod.getSimpleName()); + out.printf(" %s result = %s.%s(", getErasedType(intrinsicMethod.getReturnType()), receiver, intrinsicMethod.getSimpleName()); if (argCount > firstArg) { out.printf("arg%d", firstArg); for (int i = firstArg + 1; i < argCount; i++) { @@ -124,40 +124,40 @@ public class GeneratedFoldPlugin extends GeneratedPlugin { TypeMirror returnType = intrinsicMethod.getReturnType(); switch (returnType.getKind()) { case BOOLEAN: - out.printf(" JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n"); + out.printf(" JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n"); break; case BYTE: case SHORT: case CHAR: case INT: - out.printf(" JavaConstant constant = JavaConstant.forInt(result);\n"); + out.printf(" JavaConstant constant = JavaConstant.forInt(result);\n"); break; case LONG: - out.printf(" JavaConstant constant = JavaConstant.forLong(result);\n"); + out.printf(" JavaConstant constant = JavaConstant.forLong(result);\n"); break; case FLOAT: - out.printf(" JavaConstant constant = JavaConstant.forFloat(result);\n"); + out.printf(" JavaConstant constant = JavaConstant.forFloat(result);\n"); break; case DOUBLE: - out.printf(" JavaConstant constant = JavaConstant.forDouble(result);\n"); + out.printf(" JavaConstant constant = JavaConstant.forDouble(result);\n"); break; case ARRAY: case TYPEVAR: case DECLARED: if (returnType.equals(processor.getType("java.lang.String"))) { - out.printf(" JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION)); + out.printf(" JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION)); } else { - out.printf(" JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION)); + out.printf(" JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION)); } break; default: throw new IllegalArgumentException(returnType.toString()); } - out.printf(" ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH)); - out.printf(" b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod)); - out.printf(" b.notifyReplacedCall(targetMethod, node);\n"); - out.printf(" return true;\n"); + out.printf(" ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH)); + out.printf(" b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod)); + out.printf(" b.notifyReplacedCall(targetMethod, node);\n"); + out.printf(" return true;\n"); return deps; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java index 3329958500..22e1eecdad 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java @@ -75,7 +75,7 @@ public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin { break; } - out.printf(" %s arg%d = %s;\n", param.asType(), idx, deps.use(processor, (DeclaredType) param.asType())); + out.printf(" %s arg%d = %s;\n", param.asType(), idx, deps.use(processor, (DeclaredType) param.asType())); } for (int i = 0; i < signature.length; i++, idx++) { @@ -83,9 +83,9 @@ public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin { constantArgument(processor, out, deps, idx, signature[i], i); } else { if (signature[i].equals(processor.getType(VALUE_NODE_CLASS_NAME))) { - out.printf(" ValueNode arg%d = args[%d];\n", idx, i); + out.printf(" ValueNode arg%d = args[%d];\n", idx, i); } else { - out.printf(" %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i); + out.printf(" %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i); } } } @@ -118,7 +118,7 @@ public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin { @Override protected void factoryCall(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argCount) { - out.printf(" %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement()); + out.printf(" %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement()); if (argCount > 0) { out.printf("arg0"); for (int i = 1; i < argCount; i++) { @@ -128,11 +128,11 @@ public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin { out.printf(");\n"); if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) { - out.printf(" b.add(node);\n"); + out.printf(" b.add(node);\n"); } else { - out.printf(" b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod)); + out.printf(" b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod)); } - out.printf(" return true;\n"); + out.printf(" return true;\n"); } } @@ -158,7 +158,7 @@ public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin { @Override protected void factoryCall(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argCount) { - out.printf(" return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName()); + out.printf(" return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName()); for (int i = 0; i < argCount; i++) { out.printf(", arg%d", i); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java index 3f65702e33..d0924af6ee 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java @@ -52,7 +52,7 @@ public abstract class GeneratedPlugin { this.intrinsicMethod = intrinsicMethod; this.needInjectionProvider = false; // Lets keep generated class names short to mitigate hitting file name length limits. - this.pluginName = intrinsicMethod.getSimpleName().toString(); + this.pluginName = "Plugin_" + intrinsicMethod.getEnclosingElement().getSimpleName() + "_" + intrinsicMethod.getSimpleName().toString(); } protected abstract TypeElement getAnnotationClass(AbstractProcessor processor); @@ -66,23 +66,23 @@ public abstract class GeneratedPlugin { } public void generate(AbstractProcessor processor, PrintWriter out) { - out.printf(" // class: %s\n", intrinsicMethod.getEnclosingElement()); - out.printf(" // method: %s\n", intrinsicMethod); - out.printf(" // generated-by: %s\n", getClass().getName()); - out.printf(" private static final class %s extends GeneratedInvocationPlugin {\n", pluginName); + out.printf("// class: %s\n", intrinsicMethod.getEnclosingElement()); + out.printf("// method: %s\n", intrinsicMethod); + out.printf("// generated-by: %s\n", getClass().getName()); + out.printf("final class %s extends GeneratedInvocationPlugin {\n", pluginName); out.printf("\n"); - out.printf(" @Override\n"); - out.printf(" public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n"); + out.printf(" @Override\n"); + out.printf(" public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n"); InjectedDependencies deps = createExecute(processor, out); - out.printf(" }\n"); - out.printf(" @Override\n"); - out.printf(" public Class getSource() {\n"); - out.printf(" return %s.class;\n", getAnnotationClass(processor).getQualifiedName().toString().replace('$', '.')); - out.printf(" }\n"); + out.printf(" }\n"); + out.printf(" @Override\n"); + out.printf(" public Class getSource() {\n"); + out.printf(" return %s.class;\n", getAnnotationClass(processor).getQualifiedName().toString().replace('$', '.')); + out.printf(" }\n"); createPrivateMembers(processor, out, deps); - out.printf(" }\n"); + out.printf("}\n"); } public void register(PrintWriter out) { @@ -162,15 +162,15 @@ public abstract class GeneratedPlugin { if (!deps.isEmpty()) { out.printf("\n"); for (Dependency dep : deps) { - out.printf(" private final %s %s;\n", dep.type, dep.name); + out.printf(" private final %s %s;\n", dep.type, dep.name); } out.printf("\n"); - out.printf(" private %s(InjectionProvider injection) {\n", pluginName); + out.printf(" %s(NodeIntrinsicPluginFactory.InjectionProvider injection) {\n", pluginName); for (Dependency dep : deps) { - out.printf(" this.%s = %s;\n", dep.name, dep.inject(processor, intrinsicMethod)); + out.printf(" this.%s = %s;\n", dep.name, dep.inject(processor, intrinsicMethod)); } - out.printf(" }\n"); + out.printf(" }\n"); needInjectionProvider = true; } @@ -203,49 +203,49 @@ public abstract class GeneratedPlugin { protected static void constantArgument(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) { if (hasRawtypeWarning(type)) { - out.printf(" @SuppressWarnings({\"rawtypes\"})\n"); + out.printf(" @SuppressWarnings({\"rawtypes\"})\n"); } - out.printf(" %s arg%d;\n", getErasedType(type), argIdx); - out.printf(" if (args[%d].isConstant()) {\n", nodeIdx); + out.printf(" %s arg%d;\n", getErasedType(type), argIdx); + out.printf(" if (args[%d].isConstant()) {\n", nodeIdx); if (type.equals(processor.getType("jdk.vm.ci.meta.ResolvedJavaType"))) { - out.printf(" arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx); + out.printf(" arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx); } else { switch (type.getKind()) { case BOOLEAN: - out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx); + out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx); break; case BYTE: - out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); + out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); break; case CHAR: - out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); + out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); break; case SHORT: - out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); + out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); break; case INT: - out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); + out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx); break; case LONG: - out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx); + out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx); break; case FLOAT: - out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx); + out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx); break; case DOUBLE: - out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx); + out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx); break; case ARRAY: case DECLARED: - out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx); + out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx); break; default: throw new IllegalArgumentException(type.toString()); } } - out.printf(" } else {\n"); - out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString();\n"); - out.printf(" return false;\n"); - out.printf(" }\n"); + out.printf(" } else {\n"); + out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString();\n"); + out.printf(" return false;\n"); + out.printf(" }\n"); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java index 2ce9c0efdd..1b9ac95af3 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java @@ -124,12 +124,11 @@ public class PluginGenerator { out.printf("\n"); createImports(out, plugins); out.printf("\n"); - out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName); for (GeneratedPlugin plugin : plugins) { - out.printf("\n"); plugin.generate(processor, out); + out.printf("\n"); } - out.printf("\n"); + out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName); createPluginFactoryMethod(out, plugins); out.printf("}\n"); } @@ -164,7 +163,7 @@ public class PluginGenerator { private static void createPluginFactoryMethod(PrintWriter out, List plugins) { out.printf(" @Override\n"); - out.printf(" public void registerPlugins(InvocationPlugins plugins, InjectionProvider injection) {\n"); + out.printf(" public void registerPlugins(InvocationPlugins plugins, NodeIntrinsicPluginFactory.InjectionProvider injection) {\n"); for (GeneratedPlugin plugin : plugins) { plugin.register(out); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ReplacementsAnnotationProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ReplacementsAnnotationProcessor.java index b15946b3ff..0e065173ef 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ReplacementsAnnotationProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ReplacementsAnnotationProcessor.java @@ -51,7 +51,7 @@ public class ReplacementsAnnotationProcessor extends AbstractProcessor { } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (!roundEnv.processingOver()) { PluginGenerator generator = new PluginGenerator(); for (AnnotationHandler handler : getHandlers()) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayEqualsConstantLengthTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayEqualsConstantLengthTest.java new file mode 100644 index 0000000000..62818e579a --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayEqualsConstantLengthTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.test; + +import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; +import org.graalvm.compiler.replacements.ConstantBindingParameterPlugin; +import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode; +import org.junit.Test; + +import java.util.Arrays; + +public class ArrayEqualsConstantLengthTest extends ArraysSubstitutionsTestBase { + + private static final int[] LENGTHS = {0, 1, 2, 3, 4, 5, 7, 8, 9, 15, 16, 17, 24, 31, 32, 33, 48, 63, 64, 65, 127, 128, 129, 255, 256, 257}; + + private void testEquals(String methodName, Class[] parameterTypes, ArrayBuilder builder) { + for (int length : LENGTHS) { + testSubstitution(methodName, ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, + true, new Object[]{ + builder.newArray(length, 0, 1), + builder.newArray(length, 0, 1), + builder.newArray(length, 0, 1)}, + new Object[]{ + builder.newArray(length, 0, 1), + builder.newArray(length, 1, 1), + builder.newArray(length, 0, 2)}); + } + } + + @Test + public void testEqualsBoolean() { + testEquals("arraysEqualsBoolean", new Class[]{boolean[].class, boolean[].class}, ArraysSubstitutionsTestBase::booleanArray); + } + + @Test + public void testEqualsByte() { + testEquals("arraysEqualsByte", new Class[]{byte[].class, byte[].class}, ArraysSubstitutionsTestBase::byteArray); + } + + @Test + public void testEqualsChar() { + testEquals("arraysEqualsChar", new Class[]{char[].class, char[].class}, ArraysSubstitutionsTestBase::charArray); + } + + @Test + public void testEqualsShort() { + testEquals("arraysEqualsShort", new Class[]{short[].class, short[].class}, ArraysSubstitutionsTestBase::shortArray); + } + + @Test + public void testEqualsInt() { + testEquals("arraysEqualsInt", new Class[]{int[].class, int[].class}, ArraysSubstitutionsTestBase::intArray); + } + + @Test + public void testEqualsLong() { + testEquals("arraysEqualsLong", new Class[]{long[].class, long[].class}, ArraysSubstitutionsTestBase::longArray); + } + + private Object[] constantArgs; + + @Override + protected GraphBuilderConfiguration editGraphBuilderConfiguration(GraphBuilderConfiguration conf) { + if (constantArgs != null) { + ConstantBindingParameterPlugin constantBinding = new ConstantBindingParameterPlugin(constantArgs, this.getMetaAccess(), this.getSnippetReflection()); + conf.getPlugins().appendParameterPlugin(constantBinding); + } + return super.editGraphBuilderConfiguration(conf); + } + + @Override + protected void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, Class[] parameterTypes, boolean optional, boolean forceCompilation, + Object[] args1, Object[] args2) { + constantArgs = new Object[]{args1[0], null}; + super.testSubstitution(testMethodName, intrinsicClass, holder, methodName, parameterTypes, optional, forceCompilation, args1, args2); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java index 72d42ecd1f..8df34969d7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTest.java @@ -24,213 +24,71 @@ package org.graalvm.compiler.replacements.test; -import java.util.Arrays; - -import org.junit.Assert; -import org.junit.Test; - import org.graalvm.compiler.nodes.ReturnNode; import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.inlining.InliningPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; import org.graalvm.compiler.phases.tiers.PhaseContext; -import org.graalvm.compiler.replacements.ArraysSubstitutions; import org.graalvm.compiler.replacements.nodes.ArrayEqualsNode; import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; +import org.junit.Assert; +import org.junit.Test; -/** - * Tests {@link ArraysSubstitutions}. - */ -public class ArraysSubstitutionsTest extends MethodSubstitutionTest { +import java.util.Arrays; + +import static org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; + +public class ArraysSubstitutionsTest extends ArraysSubstitutionsTestBase { private static final int N = 10; - @Test - public void testEqualsBoolean() { + private void testEquals(String methodName, Class[] parameterTypes, ArrayBuilder builder) { Object[] args1 = new Object[N]; Object[] args2 = new Object[N]; int n = 0; - // equal arrays for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new boolean[i]; - args2[n] = new boolean[i]; + args1[n] = builder.newArray(i, 0, 1); + args2[n] = builder.newArray(i, 0, 1); } - // non-equal arrays for (int i = 0; i < N / 2; i++, n++) { - boolean[] a2 = new boolean[i]; - if (i > 0) { - a2[i - 1] = true; - } - args1[n] = new boolean[i]; - args2[n] = a2; + args1[n] = builder.newArray(i, 0, 1); + args2[n] = builder.newArray(i, 1, 1); } - Class[] parameterTypes = new Class[]{boolean[].class, boolean[].class}; - testSubstitution("arraysEqualsBoolean", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); + testSubstitution(methodName, ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, false, args1, args2); } - @SuppressWarnings("all") - public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) { - return Arrays.equals(a, b); + @Test + public void testEqualsBoolean() { + testEquals("arraysEqualsBoolean", new Class[]{boolean[].class, boolean[].class}, ArraysSubstitutionsTestBase::booleanArray); } @Test public void testEqualsByte() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new byte[i]; - args2[n] = new byte[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - byte[] a2 = new byte[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new byte[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{byte[].class, byte[].class}; - testSubstitution("arraysEqualsByte", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsByte(byte[] a, byte[] b) { - return Arrays.equals(a, b); + testEquals("arraysEqualsByte", new Class[]{byte[].class, byte[].class}, ArraysSubstitutionsTestBase::byteArray); } @Test public void testEqualsChar() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new char[i]; - args2[n] = new char[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - char[] a2 = new char[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new char[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{char[].class, char[].class}; - testSubstitution("arraysEqualsChar", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsChar(char[] a, char[] b) { - return Arrays.equals(a, b); + testEquals("arraysEqualsChar", new Class[]{char[].class, char[].class}, ArraysSubstitutionsTestBase::charArray); } @Test public void testEqualsShort() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new short[i]; - args2[n] = new short[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - short[] a2 = new short[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new short[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{short[].class, short[].class}; - testSubstitution("arraysEqualsShort", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsShort(short[] a, short[] b) { - return Arrays.equals(a, b); + testEquals("arraysEqualsShort", new Class[]{short[].class, short[].class}, ArraysSubstitutionsTestBase::shortArray); } @Test public void testEqualsInt() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new int[i]; - args2[n] = new int[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - int[] a2 = new int[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new int[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{int[].class, int[].class}; - testSubstitution("arraysEqualsInt", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsInt(int[] a, int[] b) { - return Arrays.equals(a, b); + testEquals("arraysEqualsInt", new Class[]{int[].class, int[].class}, ArraysSubstitutionsTestBase::intArray); } @Test public void testEqualsLong() { - Object[] args1 = new Object[N]; - Object[] args2 = new Object[N]; - int n = 0; - - // equal arrays - for (int i = 0; i < N / 2; i++, n++) { - args1[n] = new long[i]; - args2[n] = new long[i]; - } - - // non-equal arrays - for (int i = 0; i < N / 2; i++, n++) { - long[] a2 = new long[i]; - if (i > 0) { - a2[i - 1] = 1; - } - args1[n] = new long[i]; - args2[n] = a2; - } - - Class[] parameterTypes = new Class[]{long[].class, long[].class}; - testSubstitution("arraysEqualsLong", ArrayEqualsNode.class, Arrays.class, "equals", parameterTypes, false, args1, args2); - } - - @SuppressWarnings("all") - public static boolean arraysEqualsLong(long[] a, long[] b) { - return Arrays.equals(a, b); + testEquals("arraysEqualsLong", new Class[]{long[].class, long[].class}, ArraysSubstitutionsTestBase::longArray); } @Test diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTestBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTestBase.java new file mode 100644 index 0000000000..32dd9924cd --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArraysSubstitutionsTestBase.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.test; + +import org.graalvm.compiler.replacements.ArraysSubstitutions; + +import java.util.Arrays; + +/** + * Tests {@link ArraysSubstitutions}. + */ +public class ArraysSubstitutionsTestBase extends MethodSubstitutionTest { + + @SuppressWarnings("all") + public static boolean arraysEqualsBoolean(boolean[] a, boolean[] b) { + return Arrays.equals(a, b); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsByte(byte[] a, byte[] b) { + return Arrays.equals(a, b); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsChar(char[] a, char[] b) { + return Arrays.equals(a, b); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsShort(short[] a, short[] b) { + return Arrays.equals(a, b); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsInt(int[] a, int[] b) { + return Arrays.equals(a, b); + } + + @SuppressWarnings("all") + public static boolean arraysEqualsLong(long[] a, long[] b) { + return Arrays.equals(a, b); + } + + interface ArrayBuilder { + Object newArray(int length, int firstValue, int lastValue); + } + + static boolean[] booleanArray(int length, int firstValue, int lastValue) { + boolean[] arr = new boolean[length]; + for (int i = 0; i < length; i++) { + arr[i] = (i & 1) == 0; + } + if (length > 0) { + arr[0] = (firstValue & 1) == 0; + } + if (length > 1) { + arr[length - 1] = (lastValue & 1) == 0; + } + return arr; + } + + static byte[] byteArray(int length, int firstValue, int lastValue) { + byte[] arr = new byte[length]; + for (int i = 0; i < length; i++) { + arr[i] = (byte) i; + } + if (length > 0) { + arr[0] = (byte) firstValue; + } + if (length > 1) { + arr[length - 1] = (byte) lastValue; + } + return arr; + } + + static char[] charArray(int length, int firstValue, int lastValue) { + char[] arr = new char[length]; + for (int i = 0; i < length; i++) { + arr[i] = (char) i; + } + if (length > 0) { + arr[0] = (char) firstValue; + } + if (length > 1) { + arr[length - 1] = (char) lastValue; + } + return arr; + } + + static short[] shortArray(int length, int firstValue, int lastValue) { + short[] arr = new short[length]; + for (int i = 0; i < length; i++) { + arr[i] = (short) i; + } + if (length > 0) { + arr[0] = (short) firstValue; + } + if (length > 1) { + arr[length - 1] = (short) lastValue; + } + return arr; + } + + static int[] intArray(int length, int firstValue, int lastValue) { + int[] arr = new int[length]; + for (int i = 0; i < length; i++) { + arr[i] = i; + } + if (length > 0) { + arr[0] = firstValue; + } + if (length > 1) { + arr[length - 1] = lastValue; + } + return arr; + } + + static long[] longArray(int length, int firstValue, int lastValue) { + long[] arr = new long[length]; + for (int i = 0; i < length; i++) { + arr[i] = i; + } + if (length > 0) { + arr[0] = firstValue; + } + if (length > 1) { + arr[length - 1] = lastValue; + } + return arr; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java index 1923d6cc8f..578e33f570 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java @@ -81,7 +81,7 @@ public class FoldTest extends ReplacementsTest { @Override protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { - InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), getProviders().getLowerer(), null); + InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null); new PluginFactory_FoldTest().registerPlugins(invocationPlugins, injection); BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider(); Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java index 16c4038586..2bcd7a4a46 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/MethodSubstitutionTest.java @@ -65,9 +65,14 @@ public abstract class MethodSubstitutionTest extends GraalCompilerTest { @SuppressWarnings("try") protected StructuredGraph testGraph(final String snippet, String name) { + return testGraph(getResolvedJavaMethod(snippet), name); + } + + @SuppressWarnings("try") + protected StructuredGraph testGraph(final ResolvedJavaMethod method, String name) { DebugContext debug = getDebugContext(); - try (DebugContext.Scope s = debug.scope("MethodSubstitutionTest", getResolvedJavaMethod(snippet))) { - StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES, debug); + try (DebugContext.Scope s = debug.scope("MethodSubstitutionTest", method)) { + StructuredGraph graph = parseEager(method, AllowAssumptions.YES, debug); HighTierContext context = getDefaultHighTierContext(); debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph"); createInliningPhase(graph).apply(graph, context); @@ -111,7 +116,8 @@ public abstract class MethodSubstitutionTest extends GraalCompilerTest { return graph; } - protected void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, Class[] parameterTypes, boolean optional, Object[] args1, Object[] args2) { + protected void testSubstitution(String testMethodName, Class intrinsicClass, Class holder, String methodName, Class[] parameterTypes, boolean optional, boolean forceCompilation, + Object[] args1, Object[] args2) { ResolvedJavaMethod realMethod = getResolvedJavaMethod(holder, methodName, parameterTypes); ResolvedJavaMethod testMethod = getResolvedJavaMethod(testMethodName); StructuredGraph graph = testGraph(testMethodName); @@ -123,7 +129,7 @@ public abstract class MethodSubstitutionTest extends GraalCompilerTest { } // Force compilation - InstalledCode code = getCode(testMethod); + InstalledCode code = getCode(testMethod, null, forceCompilation); assert optional || code != null; for (int i = 0; i < args1.length; i++) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java index 7461bad3c5..45087c43da 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ReplacementsParseTest.java @@ -47,7 +47,7 @@ import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.PiNode; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; @@ -595,7 +595,7 @@ public class ReplacementsParseTest extends ReplacementsTest { StructuredGraph graph = parseEager(name, StructuredGraph.AllowAssumptions.YES); try (DebugContext.Scope s0 = graph.getDebug().scope(name, graph)) { for (OpaqueNode node : graph.getNodes().filter(OpaqueNode.class)) { - node.replaceAndDelete(node.getValue()); + node.remove(); } HighTierContext context = getDefaultHighTierContext(); CanonicalizerPhase canonicalizer = new CanonicalizerPhase(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java new file mode 100644 index 0000000000..163e3ef26d --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringCompressInflateTest.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.test; + +import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; + +import java.io.UnsupportedEncodingException; + +import org.graalvm.compiler.core.common.CompilationIdentifier; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.replacements.amd64.AMD64StringLatin1InflateNode; +import org.graalvm.compiler.replacements.amd64.AMD64StringLatin1Substitutions; +import org.graalvm.compiler.replacements.amd64.AMD64StringUTF16CompressNode; +import org.graalvm.compiler.replacements.amd64.AMD64StringUTF16Substitutions; +import org.graalvm.compiler.test.AddExports; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.InstalledCode; +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * Test intrinsic/node substitutions for (innate) methods StringLatin1.inflate and + * StringUTF16.compress provided by {@link AMD64StringLatin1Substitutions} and + * {@link AMD64StringUTF16Substitutions}. + */ +@AddExports({"java.base/java.lang"}) +public final class StringCompressInflateTest extends MethodSubstitutionTest { + + static final int N = 1000; + + @Before + public void checkAMD64() { + assumeFalse(Java8OrEarlier); + // Test case is (currently) AMD64 only. + assumeTrue(getTarget().arch instanceof AMD64); + } + + @Test + public void testStringLatin1Inflate() throws ClassNotFoundException, UnsupportedEncodingException { + Class javaclass = Class.forName("java.lang.StringLatin1"); + Class testclass = AMD64StringLatin1InflateNode.class; + + TestMethods tms = new TestMethods("testInflate", javaclass, AMD64StringLatin1InflateNode.class, "inflate", + byte[].class, int.class, char[].class, int.class, int.class); + + tms.testSubstitution(testclass); + + for (int i = 0; i < N; i++) { + byte[] src = fillLatinBytes(new byte[i2sz(i)]); + char[] dst = new char[i2sz(i)]; + + // Invoke void StringLatin1.inflate(byte[], 0, char[], 0, length) + Object nil = tms.invokeJava(src, 0, dst, 0, i2sz(i)); + + assert nil == null; + + // Perform a sanity check: + for (int j = 0; j < i2sz(i); j++) { + assert (dst[j] & 0xff00) == 0; + assert (32 <= dst[j] && dst[j] <= 126) || (160 <= dst[j] && dst[j] <= 255); + assert ((byte) dst[j] == src[j]); + } + + String str = new String(src, 0, src.length, "ISO8859_1"); + + for (int j = 0; j < src.length; j++) { + assert ((char) src[j] & 0xff) == str.charAt(j); + } + + // Invoke char[] testInflate(String) + char[] inflate1 = (char[]) tms.invokeTest(str); + + // Another sanity check: + for (int j = 0; j < i2sz(i); j++) { + assert (inflate1[j] & 0xff00) == 0; + assert (32 <= inflate1[j] && inflate1[j] <= 126) || (160 <= inflate1[j] && inflate1[j] <= 255); + } + + assertDeepEquals(dst, inflate1); + + // Invoke char[] testInflate(String) through code handle. + char[] inflate2 = (char[]) tms.invokeCode(str); + assertDeepEquals(dst, inflate2); + } + } + + @Test + public void testStringLatin1InflateByteByte() throws ClassNotFoundException { + Class javaclass = Class.forName("java.lang.StringLatin1"); + + ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "inflate", byte[].class, int.class, byte[].class, int.class, int.class); + StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext()); + assertInGraph(graph, AMD64StringLatin1InflateNode.class); + + InstalledCode code = getCode(caller, graph); + + for (int dstOffset = 0; dstOffset < 2; dstOffset++) { + for (int srcOffset = 0; srcOffset < 2; srcOffset++) { + for (int i = 0; i < N; i++) { + int length = i2sz(i); + byte[] src = fillLatinBytes(new byte[length]); + int resultLength = length * 2; + byte[] dst = new byte[resultLength]; + int copiedLength = Math.max(0, length - Math.max(dstOffset, srcOffset)); + int dstDelta = Math.min(dstOffset, copiedLength); + int srcDelta = Math.min(srcOffset, copiedLength); + invokeSafe(caller, null, src, srcDelta, dst, dstDelta, copiedLength); + + // Perform a sanity check: + for (int j = 0; j < copiedLength; j++) { + assert (dst[j * 2 + 1 + dstDelta * 2]) == 0; + int c = dst[j * 2 + dstDelta * 2] & 0xFF; + assert (32 <= c && c <= 126) || (160 <= c && c <= 255); + assert (c == (src[j + srcDelta] & 0xFF)); + } + + byte[] dst2 = new byte[resultLength]; + executeVarargsSafe(code, src, srcDelta, dst2, dstDelta, copiedLength); + assertDeepEquals(dst, dst2); + } + } + } + } + + @Test + public void testStringLatin1InflateByteChar() throws ClassNotFoundException { + Class javaclass = Class.forName("java.lang.StringLatin1"); + + ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "inflate", byte[].class, int.class, char[].class, int.class, int.class); + StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext()); + assertInGraph(graph, AMD64StringLatin1InflateNode.class); + + InstalledCode code = getCode(caller, graph); + + for (int dstOffset = 0; dstOffset < 2; dstOffset++) { + for (int srcOffset = 0; srcOffset < 2; srcOffset++) { + for (int i = 0; i < N; i++) { + int length = i2sz(i); + byte[] src = fillLatinBytes(new byte[length]); + char[] dst = new char[length]; + int copiedLength = Math.max(0, length - Math.max(dstOffset, srcOffset)); + int dstDelta = Math.min(dstOffset, copiedLength); + int srcDelta = Math.min(srcOffset, copiedLength); + invokeSafe(caller, null, src, srcDelta, dst, dstDelta, copiedLength); + + // Perform a sanity check: + for (int j = 0; j < copiedLength; j++) { + int c = dst[j + dstDelta] & 0xFF; + assert (32 <= c && c <= 126) || (160 <= c && c <= 255); + assert (c == (src[j + srcDelta] & 0xFF)); + } + + char[] dst2 = new char[length]; + executeVarargsSafe(code, src, srcDelta, dst2, dstDelta, copiedLength); + assertDeepEquals(dst, dst2); + } + } + } + } + + @Test + public void testStringUTF16Compress() throws ClassNotFoundException, UnsupportedEncodingException { + Class javaclass = Class.forName("java.lang.StringUTF16"); + Class testclass = AMD64StringUTF16CompressNode.class; + TestMethods tms = new TestMethods("testCompress", javaclass, AMD64StringUTF16CompressNode.class, "compress", + char[].class, int.class, byte[].class, int.class, int.class); + tms.testSubstitution(testclass); + + for (int i = 0; i < N; i++) { + char[] src = fillLatinChars(new char[i2sz(i)]); + byte[] dst = new byte[i2sz(i)]; + + // Invoke int StringUTF16.compress(char[], 0, byte[], 0, length) + Object len = tms.invokeJava(src, 0, dst, 0, i2sz(i)); + + assert (int) len == i2sz(i); + + // Invoke String testCompress(char[]) + String str1 = (String) tms.invokeTest(src); + + assertDeepEquals(dst, str1.getBytes("ISO8859_1")); + + // Invoke String testCompress(char[]) through code handle. + String str2 = (String) tms.invokeCode(src); + + assertDeepEquals(dst, str2.getBytes("ISO8859_1")); + } + } + + @Test + public void testStringUTF16CompressByteByte() throws ClassNotFoundException { + Class javaclass = Class.forName("java.lang.StringUTF16"); + + ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "compress", byte[].class, int.class, byte[].class, int.class, int.class); + StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext()); + assertInGraph(graph, AMD64StringUTF16CompressNode.class); + + InstalledCode code = getCode(caller, graph); + + for (int dstOffset = 0; dstOffset < 2; dstOffset++) { + for (int srcOffset = 0; srcOffset < 2; srcOffset++) { + for (int i = 0; i < N; i++) { + int length = i2sz(i); + byte[] src = fillLatinChars(new byte[length * 2]); + byte[] dst = new byte[length]; + int copiedLength = Math.max(0, length - Math.max(dstOffset, srcOffset)); + int dstDelta = Math.min(dstOffset, copiedLength); + int srcDelta = Math.min(srcOffset, copiedLength); + invokeSafe(caller, null, src, srcDelta, dst, dstDelta, copiedLength); + + // Perform a sanity check: + for (int j = 0; j < copiedLength; j++) { + int c = dst[j + dstDelta] & 0xFF; + assert (32 <= c && c <= 126) || (160 <= c && c <= 255); + assert (c == (src[(j + srcDelta) * 2] & 0xFF)); + } + + byte[] dst2 = new byte[length]; + executeVarargsSafe(code, src, srcDelta, dst2, dstDelta, copiedLength); + assertDeepEquals(dst, dst2); + } + } + } + } + + @Test + public void testStringUTF16CompressCharByte() throws ClassNotFoundException { + Class javaclass = Class.forName("java.lang.StringUTF16"); + + ResolvedJavaMethod caller = getResolvedJavaMethod(javaclass, "compress", char[].class, int.class, byte[].class, int.class, int.class); + StructuredGraph graph = getReplacements().getIntrinsicGraph(caller, CompilationIdentifier.INVALID_COMPILATION_ID, getDebugContext()); + assertInGraph(graph, AMD64StringUTF16CompressNode.class); + + InstalledCode code = getCode(caller, graph); + + for (int dstOffset = 0; dstOffset < 2; dstOffset++) { + for (int srcOffset = 0; srcOffset < 2; srcOffset++) { + for (int i = 0; i < N; i++) { + int length = i2sz(i); + char[] src = fillLatinChars(new char[length]); + byte[] dst = new byte[length]; + int copiedLength = Math.max(0, length - Math.max(dstOffset, srcOffset)); + int dstDelta = Math.min(dstOffset, copiedLength); + int srcDelta = Math.min(srcOffset, copiedLength); + invokeSafe(caller, null, src, srcDelta, dst, dstDelta, copiedLength); + + // Perform a sanity check: + for (int j = 0; j < copiedLength; j++) { + int c = dst[j + dstDelta] & 0xFF; + assert (32 <= c && c <= 126) || (160 <= c && c <= 255); + assert (c == (src[j + srcDelta] & 0xFF)); + } + + byte[] dst2 = new byte[length]; + executeVarargsSafe(code, src, srcDelta, dst2, dstDelta, copiedLength); + assertDeepEquals(dst, dst2); + } + } + } + } + + @SuppressWarnings("all") + public static String testCompress(char[] a) { + return new String(a); + } + + @SuppressWarnings("all") + public static char[] testInflate(String a) { + return a.toCharArray(); + } + + private class TestMethods { + + TestMethods(String testmname, Class javaclass, Class intrinsicClass, String javamname, Class... params) { + javamethod = getResolvedJavaMethod(javaclass, javamname, params); + testmethod = getResolvedJavaMethod(testmname); + testgraph = testGraph(testmname, javamname); + assertInGraph(testgraph, intrinsicClass); + + assert javamethod != null; + assert testmethod != null; + + // Force the test method to be compiled. + testcode = getCode(testmethod); + + assert testcode != null; + } + + StructuredGraph replacementGraph() { + return getReplacements().getSubstitution(javamethod, -1, false, null); + } + + StructuredGraph testMethodGraph() { + return testgraph; + } + + void testSubstitution(Class intrinsicclass) { + // Check if the resulting graph contains the expected node. + if (replacementGraph() == null) { + assertInGraph(testMethodGraph(), intrinsicclass); + } + } + + Object invokeJava(Object... args) { + return invokeSafe(javamethod, null, args); + } + + Object invokeTest(Object... args) { + return invokeSafe(testmethod, null, args); + } + + Object invokeCode(Object... args) { + return executeVarargsSafe(testcode, args); + } + + // Private data section: + private ResolvedJavaMethod javamethod; + private ResolvedJavaMethod testmethod; + private StructuredGraph testgraph; + private InstalledCode testcode; + } + + private static byte[] fillLatinBytes(byte[] v) { + for (int ch = 32, i = 0; i < v.length; i++) { + v[i] = (byte) (ch & 0xff); + ch = ch == 126 ? 160 : (ch == 255 ? 32 : ch + 1); + } + return v; + } + + private static char[] fillLatinChars(char[] v) { + for (int ch = 32, i = 0; i < v.length; i++) { + v[i] = (char) (ch & 0xff); + ch = ch == 126 ? 160 : (ch == 255 ? 32 : ch + 1); + } + return v; + } + + private static byte[] fillLatinChars(byte[] v) { + for (int ch = 32, i = 0; i < v.length; i += 2) { + v[i] = (byte) (ch & 0xff); + ch = ch == 126 ? 160 : (ch == 255 ? 32 : ch + 1); + } + return v; + } + + private static int i2sz(int i) { + return i * 3; + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfDeoptimizeTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfDeoptimizeTest.java new file mode 100644 index 0000000000..5c7a5733db --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfDeoptimizeTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.test; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.junit.Test; + +public class StringIndexOfDeoptimizeTest extends GraalCompilerTest { + public int testStringIndexOfDeoptimize(String a) { + int result = a.indexOf("ba"); + if (result == -1) { + GraalDirectives.deoptimizeAndInvalidate(); + } + return result; + } + + @Test + public void testStringIndexOfConstantDeoptimize() { + test("testStringIndexOfDeoptimize", "a"); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfTestBase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfTestBase.java index beea1f36d9..a7ada18be4 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfTestBase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/StringIndexOfTestBase.java @@ -24,14 +24,14 @@ package org.graalvm.compiler.replacements.test; -import java.util.ArrayList; -import java.util.Collection; - import org.graalvm.compiler.core.test.GraalCompilerTest; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import java.util.ArrayList; +import java.util.Collection; + @RunWith(value = Parameterized.class) public abstract class StringIndexOfTestBase extends GraalCompilerTest { @Parameterized.Parameter(value = 0) public String sourceString; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java new file mode 100644 index 0000000000..dff3612ba5 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/SubstitutionNodeSourcePositionTest.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.replacements.test; + +import static org.graalvm.compiler.core.GraalCompiler.compileGraph; +import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; + +import java.util.List; + +import org.graalvm.compiler.api.directives.GraalDirectives; +import org.graalvm.compiler.api.replacements.ClassSubstitution; +import org.graalvm.compiler.api.replacements.MethodSubstitution; +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.code.SourceMapping; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.debug.BlackholeNode; +import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.phases.OptimisticOptimizations; +import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +/** + * Test that various substitution implementations produce the expected + * {@link org.graalvm.compiler.graph.NodeSourcePosition} structure. Method substitutions and method + * plugins should leave behind a frame for the substitution. Method substitutions should have + * bytecodes below the substitution. Snippet lowerings should just have the bytecodes without a + * marker frame. + */ +public class SubstitutionNodeSourcePositionTest extends ReplacementsTest { + + private static class TestMethod { + + public static int test(int i) { + return i; + } + } + + @ClassSubstitution(TestMethod.class) + public static class TestMethodSubstitution { + + @MethodSubstitution + public static int test(int i) { + blackhole(i); + return i; + } + + @Node.NodeIntrinsic(BlackholeNode.class) + private static native void blackhole(int i); + } + + @Override + protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { + new PluginFactory_SubstitutionNodeSourcePositionTest().registerPlugins(invocationPlugins, null); + ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider(); + InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestMethod.class, bytecodeProvider); + r.registerMethodSubstitution(TestMethodSubstitution.class, "test", int.class); + super.registerInvocationPlugins(invocationPlugins); + } + + public int methodSubstitution() { + return TestMethod.test(42); + } + + @Test + public void testMethodSubstitution() { + // @formatter:off + // Expect mappings of the form: + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethodSubstitution.blackhole(int) [bci: -1] + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethodSubstitution.test(SubstitutionNodeSourcePositionTest.java:71) [bci: 1] Substitution + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethod.test(int) [bci: -1] + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.methodSubstitution(SubstitutionNodeSourcePositionTest.java:89) [bci: 2] + // @formatter:on + checkMappings("methodSubstitution", true, TestMethod.class, "test"); + } + + public void snippetLowering(String[] array, String value) { + array[0] = value; + } + + @Test + public void testSnippetLowering() { + // @formatter:off + // Expect mappings of the form: + // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialWriteBarrier(WriteBarrierSnippets.java:140) [bci: 18] + // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialPreciseWriteBarrier(WriteBarrierSnippets.java:158) [bci: 5] Substitution + // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialPreciseWriteBarrier(AddressNode$Address, WriteBarrierSnippets$Counters) [bci: -1] Substitution + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.snippetLowering(SubstitutionNodeSourcePositionTest.java:99) [bci: 3] + // @formatter:on + // + // The precise snippet bytecodes don't matter, just ensure that some actually appear after + // lowering. + checkMappings("snippetLowering", true, SubstitutionNodeSourcePositionTest.class, "snippetLowering"); + } + + public int methodPlugin(int i) { + GraalDirectives.blackhole(i); + return i; + } + + @Test + public void testMethodPlugin() { + // @formatter:off + // Expect mappings of the form: + // at org.graalvm.compiler.api.directives.GraalDirectives.blackhole(int) [bci: -1] + // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.methodPlugin(SubstitutionNodeSourcePositionTest.java:109) [bci: 1] + // @formatter:on + checkMappings("methodPlugin", false, GraalDirectives.class, "blackhole"); + } + + private void checkMappings(String snippetMethod, boolean hasBytecodes, Class boundaryClass, String boundaryMethod) { + List mappings = getSourceMappings(snippetMethod); + ResolvedJavaType resolvedJavaType = getMetaAccess().lookupJavaType(boundaryClass); + boolean found = false; + Assert.assertTrue("must have mappings", !mappings.isEmpty()); + for (SourceMapping mapping : mappings) { + NodeSourcePosition callee = null; + for (NodeSourcePosition pos = mapping.getSourcePosition(); pos != null; pos = pos.getCaller()) { + ResolvedJavaMethod method = pos.getMethod(); + if (method.getName().equals(boundaryMethod) && method.getDeclaringClass().equals(resolvedJavaType)) { + if ((callee != null) == hasBytecodes) { + if (hasBytecodes) { + assertTrue(callee.isSubstitution()); + } + assertTrue(pos.trim() == pos); + assertTrue(mapping.getSourcePosition().trim() == pos); + found = true; + } + } + callee = pos; + } + } + Assert.assertTrue("must have substitution for " + resolvedJavaType + "." + boundaryMethod, found); + } + + private List getSourceMappings(String name) { + final ResolvedJavaMethod method = getResolvedJavaMethod(name); + final OptionValues options = new OptionValues(getInitialOptions(), TrackNodeSourcePosition, true); + final StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES, options); + final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(), + createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true); + return cr.getSourceMappings(); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java index 5aeab1350d..810a127898 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/ClassfileBytecodeProviderTest.java @@ -87,8 +87,10 @@ import java.util.Formatter; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import org.graalvm.compiler.test.SubprocessUtil; import org.junit.Assert; import org.junit.Assume; +import org.junit.Before; import org.junit.Test; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; @@ -124,6 +126,12 @@ import jdk.vm.ci.meta.ResolvedJavaType; */ public class ClassfileBytecodeProviderTest extends GraalCompilerTest { + @Before + public void checkJavaAgent() { + assumeManagementLibraryIsLoadable(); + Assume.assumeFalse("Java Agent found -> skipping", SubprocessUtil.isJavaAgentAttached()); + } + private static boolean shouldProcess(String classpathEntry) { if (classpathEntry.endsWith(".jar")) { String name = new File(classpathEntry).getName(); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java index f3ee724b30..cf602ef88f 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/classfile/RedefineIntrinsicTest.java @@ -102,6 +102,7 @@ public class RedefineIntrinsicTest extends ReplacementsTest { @Test public void test() throws Throwable { + assumeManagementLibraryIsLoadable(); try { Class.forName("java.lang.instrument.Instrumentation"); } catch (ClassNotFoundException ex) { @@ -198,7 +199,7 @@ public class RedefineIntrinsicTest extends ReplacementsTest { } } - @SuppressWarnings("deprecation") + @SuppressWarnings({"deprecation", "unused"}) public static boolean loadAgent(Path agent) throws Exception { String vmName = ManagementFactory.getRuntimeMXBean().getName(); int p = vmName.indexOf('@'); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java index 7831bc9600..1c679deadc 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java @@ -90,6 +90,7 @@ public class CachingPEGraphDecoder extends PEGraphDecoder { trackNodeSourcePosition(graphBuilderConfig.trackNodeSourcePosition()). method(method). setIsSubstitution(isSubstitution). + cancellable(graph.getCancellable()). build(); // @formatter:on try (DebugContext.Scope scope = debug.scope("createGraph", graphToEncode)) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java index f0b545f60e..2cf155cf83 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java @@ -31,7 +31,6 @@ import org.graalvm.compiler.api.replacements.Fold.InjectedParameter; import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.spi.LoweringTool; @@ -44,6 +43,7 @@ import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.MetaAccessProvider; public class ConstantStringIndexOfSnippets implements Snippets { public static class Templates extends AbstractTemplates { @@ -95,8 +95,8 @@ public class ConstantStringIndexOfSnippets implements Snippets { args.add("targetCount", utf16IndexOf.getArgument(3)); args.add("origFromIndex", utf16IndexOf.getArgument(4)); byte[] targetByteArray = snippetReflection.asObject(byte[].class, utf16IndexOf.getArgument(2).asJavaConstant()); - args.addConst("md2", md2Utf16(targetByteArray)); - args.addConst("cache", computeCacheUtf16(targetByteArray)); + args.addConst("md2", md2Utf16(tool.getMetaAccess(), targetByteArray)); + args.addConst("cache", computeCacheUtf16(tool.getMetaAccess(), targetByteArray)); template(utf16IndexOf, args).instantiate(providers.getMetaAccess(), utf16IndexOf, DEFAULT_REPLACER, args); } } @@ -151,12 +151,12 @@ public class ConstantStringIndexOfSnippets implements Snippets { return cache; } - static int md2Utf16(byte[] target) { + static int md2Utf16(MetaAccessProvider metaAccess, byte[] target) { int c = target.length / 2; if (c == 0) { return 0; } - long base = UnsafeAccess.UNSAFE.arrayBaseOffset(byte[].class); + long base = metaAccess.getArrayBaseOffset(JavaKind.Byte); char lastChar = UnsafeAccess.UNSAFE.getChar(target, base + (c - 1) * 2); int md2 = c; for (int i = 0; i < c - 1; i++) { @@ -168,11 +168,11 @@ public class ConstantStringIndexOfSnippets implements Snippets { return md2; } - static long computeCacheUtf16(byte[] s) { + static long computeCacheUtf16(MetaAccessProvider metaAccess, byte[] s) { int c = s.length / 2; int cache = 0; int i; - long base = UnsafeAccess.UNSAFE.arrayBaseOffset(byte[].class); + long base = metaAccess.getArrayBaseOffset(JavaKind.Byte); for (i = 0; i < c - 1; i++) { char currChar = UnsafeAccess.UNSAFE.getChar(s, base + i * 2); cache |= (1 << (currChar & 63)); @@ -181,17 +181,17 @@ public class ConstantStringIndexOfSnippets implements Snippets { } @Fold - static int byteArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayBaseOffset(JavaKind.Byte); + static int byteArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Byte); } @Fold - static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) { - return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char); + static int charArrayBaseOffset(@InjectedParameter MetaAccessProvider metaAccess) { + return metaAccess.getArrayBaseOffset(JavaKind.Char); } /** Marker value for the {@link InjectedParameter} injected parameter. */ - static final ArrayOffsetProvider INJECTED = null; + static final MetaAccessProvider INJECTED = null; @Snippet public static int indexOfConstant(char[] source, int sourceOffset, int sourceCount, diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java index 68c2e5c5df..be2097c403 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java @@ -31,7 +31,10 @@ import static jdk.vm.ci.code.MemoryBarriers.JMM_PRE_VOLATILE_WRITE; import static jdk.vm.ci.meta.DeoptimizationAction.InvalidateReprofile; import static jdk.vm.ci.meta.DeoptimizationReason.BoundsCheckException; import static jdk.vm.ci.meta.DeoptimizationReason.NullCheckException; +import static org.graalvm.compiler.core.common.SpeculativeExecutionAttacksMitigations.Options.UseIndexMasking; import static org.graalvm.compiler.nodes.NamedLocationIdentity.ARRAY_LENGTH_LOCATION; +import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.branchlessMax; +import static org.graalvm.compiler.nodes.calc.BinaryArithmeticNode.branchlessMin; import static org.graalvm.compiler.nodes.java.ArrayLengthNode.readArrayLength; import static org.graalvm.compiler.nodes.util.GraphUtil.skipPiWhileNonNull; @@ -185,6 +188,10 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { return target; } + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + @Override @SuppressWarnings("try") public void lower(Node n, LoweringTool tool) { @@ -440,13 +447,14 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { } } + public static final IntegerStamp POSITIVE_ARRAY_INDEX_STAMP = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1); + /** * Create a PiNode on the index proving that the index is positive. On some platforms this is * important to allow the index to be used as an int in the address mode. */ public AddressNode createArrayIndexAddress(StructuredGraph graph, ValueNode array, JavaKind elementKind, ValueNode index, GuardingNode boundsCheck) { - IntegerStamp indexStamp = StampFactory.forInteger(32, 0, Integer.MAX_VALUE - 1); - ValueNode positiveIndex = graph.maybeAddOrUnique(PiNode.create(index, indexStamp, boundsCheck != null ? boundsCheck.asNode() : null)); + ValueNode positiveIndex = graph.maybeAddOrUnique(PiNode.create(index, POSITIVE_ARRAY_INDEX_STAMP, boundsCheck != null ? boundsCheck.asNode() : null)); return createArrayAddress(graph, array, elementKind, positiveIndex); } @@ -459,10 +467,10 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { wordIndex = index; } - int shift = CodeUtil.log2(arrayScalingFactor(elementKind)); + int shift = CodeUtil.log2(metaAccess.getArrayIndexScale(elementKind)); ValueNode scaledIndex = graph.unique(new LeftShiftNode(wordIndex, ConstantNode.forInt(shift, graph))); - int base = arrayBaseOffset(elementKind); + int base = metaAccess.getArrayBaseOffset(elementKind); ValueNode offset = graph.unique(new AddNode(scaledIndex, ConstantNode.forIntegerKind(target.wordJavaKind, base, graph))); return graph.unique(new OffsetAddressNode(array, offset)); @@ -476,7 +484,12 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { Stamp loadStamp = loadStamp(loadIndexed.stamp(NodeView.DEFAULT), elementKind); GuardingNode boundsCheck = getBoundsCheck(loadIndexed, array, tool); - AddressNode address = createArrayIndexAddress(graph, array, elementKind, loadIndexed.index(), boundsCheck); + ValueNode index = loadIndexed.index(); + if (UseIndexMasking.getValue(graph.getOptions())) { + index = proxyIndex(loadIndexed, index, array, tool); + } + AddressNode address = createArrayIndexAddress(graph, array, elementKind, index, boundsCheck); + ReadNode memoryRead = graph.add(new ReadNode(address, NamedLocationIdentity.getArrayLocation(elementKind), loadStamp, BarrierType.NONE)); memoryRead.setGuard(boundsCheck); ValueNode readValue = implicitLoadConvert(graph, elementKind, memoryRead); @@ -800,7 +813,7 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { barrierType = fieldInitializationBarrier(entryKind); } } else { - address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind)); + address = createOffsetAddress(graph, newObject, metaAccess.getArrayBaseOffset(entryKind) + i * metaAccess.getArrayIndexScale(entryKind)); barrierType = arrayInitializationBarrier(entryKind); } if (address != null) { @@ -1000,11 +1013,6 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { public abstract int arrayLengthOffset(); - @Override - public int arrayScalingFactor(JavaKind elementKind) { - return target.arch.getPlatformKind(elementKind).getSizeInBytes(); - } - public Stamp loadStamp(Stamp stamp, JavaKind kind) { return loadStamp(stamp, kind, true); } @@ -1110,18 +1118,20 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor); + protected ValueNode proxyIndex(AccessIndexedNode n, ValueNode index, ValueNode array, LoweringTool tool) { + StructuredGraph graph = index.graph(); + ValueNode arrayLength = readOrCreateArrayLength(n, array, tool, graph); + ValueNode lengthMinusOne = SubNode.create(arrayLength, ConstantNode.forInt(1), NodeView.DEFAULT); + return branchlessMax(branchlessMin(index, lengthMinusOne, NodeView.DEFAULT), ConstantNode.forInt(0), NodeView.DEFAULT); + } + protected GuardingNode getBoundsCheck(AccessIndexedNode n, ValueNode array, LoweringTool tool) { if (n.getBoundsCheck() != null) { return n.getBoundsCheck(); } StructuredGraph graph = n.graph(); - ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection()); - if (arrayLength == null) { - arrayLength = createReadArrayLength(array, n, tool); - } else { - arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength); - } + ValueNode arrayLength = readOrCreateArrayLength(n, array, tool, graph); LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength, NodeView.DEFAULT); if (boundsCheck.isTautology()) { @@ -1130,6 +1140,16 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile); } + private ValueNode readOrCreateArrayLength(AccessIndexedNode n, ValueNode array, LoweringTool tool, StructuredGraph graph) { + ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection()); + if (arrayLength == null) { + arrayLength = createReadArrayLength(array, n, tool); + } else { + arrayLength = arrayLength.isAlive() ? arrayLength : graph.addOrUniqueWithInputs(arrayLength); + } + return arrayLength; + } + protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) { if (StampTool.isPointerNonNull(object)) { return null; @@ -1150,10 +1170,10 @@ public abstract class DefaultJavaLoweringProvider implements LoweringProvider { StructuredGraph graph = address.graph(); ValueNode offset = ((OffsetAddressNode) address).getOffset(); - int base = arrayBaseOffset(elementKind); + int base = metaAccess.getArrayBaseOffset(elementKind); ValueNode scaledIndex = graph.unique(new SubNode(offset, ConstantNode.forIntegerStamp(offset.stamp(NodeView.DEFAULT), base, graph))); - int shift = CodeUtil.log2(arrayScalingFactor(elementKind)); + int shift = CodeUtil.log2(metaAccess.getArrayIndexScale(elementKind)); ValueNode ret = graph.unique(new RightShiftNode(scaledIndex, ConstantNode.forInt(shift, graph))); return IntegerConvertNode.convert(ret, StampFactory.forKind(JavaKind.Int), graph, NodeView.DEFAULT); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JDK9StringSubstitutions.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JDK9StringSubstitutions.java index 746269f05f..88ae834865 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JDK9StringSubstitutions.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/JDK9StringSubstitutions.java @@ -75,4 +75,8 @@ public class JDK9StringSubstitutions { public static native byte[] getValue(String s); public static native int getCoder(String s); + + public static boolean isCompactString(String s) { + return getCoder(s) == 0; + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java index 8326c084b0..8733a48ce7 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java @@ -25,7 +25,6 @@ package org.graalvm.compiler.replacements; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.ForeignCallsProvider; import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; @@ -43,15 +42,12 @@ public class NodeIntrinsificationProvider implements InjectionProvider { private final MetaAccessProvider metaAccess; private final SnippetReflectionProvider snippetReflection; private final ForeignCallsProvider foreignCalls; - private final ArrayOffsetProvider arrayOffsetProvider; private final WordTypes wordTypes; - public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ArrayOffsetProvider arrayOffsetProvider, - WordTypes wordTypes) { + public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) { this.metaAccess = metaAccess; this.snippetReflection = snippetReflection; this.foreignCalls = foreignCalls; - this.arrayOffsetProvider = arrayOffsetProvider; this.wordTypes = wordTypes; } @@ -79,8 +75,6 @@ public class NodeIntrinsificationProvider implements InjectionProvider { return type.cast(foreignCalls); } else if (type.equals(SnippetReflectionProvider.class)) { return type.cast(snippetReflection); - } else if (type.equals(ArrayOffsetProvider.class)) { - return type.cast(arrayOffsetProvider); } else { throw new GraalError("Cannot handle injected argument of type %s.", type.getName()); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java index 9e978c24d6..fbbd38e7b5 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java @@ -24,13 +24,14 @@ package org.graalvm.compiler.replacements; -import java.net.URI; import static org.graalvm.compiler.debug.GraalError.unimplemented; import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; +import java.util.Formatter; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ import jdk.internal.vm.compiler.collections.Equivalence; import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; import org.graalvm.compiler.core.common.PermanentBailoutException; import org.graalvm.compiler.core.common.cfg.CFGVerifier; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; @@ -399,6 +401,18 @@ public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { public JavaType getInvokeReturnType() { throw unimplemented(); } + + @Override + public String toString() { + Formatter fmt = new Formatter(); + PEMethodScope scope = this.methodScope; + fmt.format("%s", new ResolvedJavaMethodBytecode(scope.method).asStackTraceElement(invoke.bci())); + NodeSourcePosition callers = scope.getCallerBytecodePosition(); + if (callers != null) { + fmt.format("%n%s", callers); + } + return fmt.toString(); + } } protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java index bace141123..8106b3a155 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java @@ -30,6 +30,7 @@ import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsin import static org.graalvm.compiler.java.BytecodeParserOptions.InlineIntrinsicsDuringParsing; import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createIntrinsicInlineInfo; import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING; +import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION; import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required; import java.util.Collections; @@ -48,6 +49,7 @@ import org.graalvm.compiler.api.replacements.SnippetTemplateCache; import org.graalvm.compiler.bytecode.Bytecode; import org.graalvm.compiler.bytecode.BytecodeProvider; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.debug.DebugCloseable; @@ -57,8 +59,8 @@ import org.graalvm.compiler.debug.DebugHandlersFactory; import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.graph.Node.NodeIntrinsic; +import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.java.GraphBuilderPhase.Instance; import org.graalvm.compiler.nodes.CallTargetNode; @@ -311,6 +313,37 @@ public class ReplacementsImpl implements Replacements, InlineInvokePlugin { return result; } + @SuppressWarnings("try") + @Override + public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) { + Bytecode subst = getSubstitutionBytecode(method); + if (subst != null) { + ResolvedJavaMethod substMethod = subst.getMethod(); + assert !substMethod.equals(method); + BytecodeProvider bytecodeProvider = subst.getOrigin(); + // @formatter:off + StructuredGraph graph = new StructuredGraph.Builder(options, debug, StructuredGraph.AllowAssumptions.YES). + method(substMethod). + compilationId(compilationId). + recordInlinedMethods(bytecodeProvider.shouldRecordMethodDependencies()). + setIsSubstitution(true). + build(); + // @formatter:on + try (DebugContext.Scope scope = debug.scope("GetIntrinsicGraph", graph)) { + Plugins plugins = new Plugins(getGraphBuilderPlugins()); + GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins); + IntrinsicContext initialReplacementContext = new IntrinsicContext(method, substMethod, bytecodeProvider, ROOT_COMPILATION); + new GraphBuilderPhase.Instance(providers.getMetaAccess(), providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config, + OptimisticOptimizations.NONE, initialReplacementContext).apply(graph); + assert !graph.isFrozen(); + return graph; + } catch (Throwable e) { + debug.handle(e); + } + } + return null; + } + /** * Creates a preprocessed graph for a snippet or method substitution. * diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java index 018a4c56a5..19602ec1cb 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java @@ -88,7 +88,7 @@ import org.graalvm.compiler.nodes.calc.ZeroExtendNode; import org.graalvm.compiler.nodes.debug.BindToRegisterNode; import org.graalvm.compiler.nodes.debug.BlackholeNode; import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode; -import org.graalvm.compiler.nodes.debug.OpaqueNode; +import org.graalvm.compiler.nodes.extended.OpaqueNode; import org.graalvm.compiler.nodes.debug.SpillRegistersNode; import org.graalvm.compiler.nodes.extended.BoxNode; import org.graalvm.compiler.nodes.extended.BranchProbabilityNode; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/UnsafeAccess.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/UnsafeAccess.java index 04a03f552d..124521425d 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/UnsafeAccess.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/UnsafeAccess.java @@ -33,7 +33,9 @@ import sun.misc.Unsafe; */ class UnsafeAccess { - static final Unsafe UNSAFE = initUnsafe(); + private static final Unsafe THE_UNSAFE = initUnsafe(); + + static final UnsafeAccess UNSAFE = new UnsafeAccess(); private static Unsafe initUnsafe() { try { @@ -50,4 +52,12 @@ class UnsafeAccess { } } } + + public char getChar(Object target, long l) { + return THE_UNSAFE.getChar(target, l); + } + + public byte getByte(Object target, long l) { + return THE_UNSAFE.getByte(target, l); + } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java index 6e33e1c2b4..6cf3f2c560 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayEqualsNode.java @@ -86,18 +86,6 @@ public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLower this.length = length; } - public ValueNode getArray1() { - return array1; - } - - public ValueNode getArray2() { - return array2; - } - - public ValueNode getLength() { - return length; - } - private static boolean isNaNFloat(JavaConstant constant) { JavaKind kind = constant.getJavaKind(); return (kind == JavaKind.Float && Float.isNaN(constant.asFloat())) || (kind == JavaKind.Double && Double.isNaN(constant.asDouble())); @@ -157,14 +145,14 @@ public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLower // Float NaN constants are different constant nodes but treated as // equal in Arrays.equals([F[F) or Arrays.equals([D[D). if (entry1.getStackKind() == JavaKind.Float && entry2.getStackKind() == JavaKind.Float) { - float value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asFloat(); - float value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asFloat(); + float value1 = ((JavaConstant) entry1.asConstant()).asFloat(); + float value2 = ((JavaConstant) entry2.asConstant()).asFloat(); if (Float.floatToIntBits(value1) != Float.floatToIntBits(value2)) { allEqual = false; } } else if (entry1.getStackKind() == JavaKind.Double && entry2.getStackKind() == JavaKind.Double) { - double value1 = ((JavaConstant) ((ConstantNode) entry1).asConstant()).asDouble(); - double value2 = ((JavaConstant) ((ConstantNode) entry2).asConstant()).asDouble(); + double value1 = ((JavaConstant) entry1.asConstant()).asDouble(); + double value2 = ((JavaConstant) entry2.asConstant()).asDouble(); if (Double.doubleToLongBits(value1) != Double.doubleToLongBits(value2)) { allEqual = false; } @@ -226,7 +214,11 @@ public final class ArrayEqualsNode extends FixedWithNextNode implements LIRLower @Override public void generate(NodeLIRBuilderTool gen) { - Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length)); + int constantLength = -1; + if (length.isConstant()) { + constantLength = length.asJavaConstant().asInt(); + } + Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length), constantLength, false); gen.setResult(this, result); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java similarity index 55% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java rename to src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java index ca6d9ede4a..5610e07d7a 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,16 +22,15 @@ */ -package org.graalvm.compiler.replacements.amd64; - -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; +package org.graalvm.compiler.replacements.nodes; +import jdk.vm.ci.meta.JavaKind; +import jdk.vm.ci.meta.Value; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodeinfo.InputType; import org.graalvm.compiler.nodeinfo.NodeCycles; import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodeinfo.NodeSize; import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.NamedLocationIdentity; import org.graalvm.compiler.nodes.ValueNode; @@ -43,52 +42,56 @@ import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool; import jdk.internal.vm.compiler.word.LocationIdentity; import jdk.internal.vm.compiler.word.Pointer; -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.Value; +import static org.graalvm.compiler.nodeinfo.InputType.Memory; -@NodeInfo(size = SIZE_64, cycles = NodeCycles.CYCLES_UNKNOWN) -public class AMD64StringIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess { - public static final NodeClass TYPE = NodeClass.create(AMD64StringIndexOfNode.class); +// JaCoCo Exclude - @OptionalInput(InputType.Memory) protected MemoryNode lastLocationAccess; +/** + * Compares two array regions with a given length. + */ +@NodeInfo(cycles = NodeCycles.CYCLES_UNKNOWN, size = NodeSize.SIZE_128) +public final class ArrayRegionEqualsNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess { - @Input protected NodeInputList arguments; + public static final NodeClass TYPE = NodeClass.create(ArrayRegionEqualsNode.class); - public AMD64StringIndexOfNode(ValueNode sourcePointer, ValueNode sourceCount, ValueNode targetPointer, ValueNode targetCount) { - super(TYPE, StampFactory.forInteger(32)); - this.arguments = new NodeInputList<>(this, new ValueNode[]{sourcePointer, sourceCount, targetPointer, targetCount}); + /** {@link JavaKind} of the arrays to compare. */ + private final JavaKind kind; + + /** Pointer to first array region to be tested for equality. */ + @Input private ValueNode array1; + + /** Pointer to second array region to be tested for equality. */ + @Input private ValueNode array2; + + /** Length of the array region. */ + @Input private ValueNode length; + + @OptionalInput(Memory) private MemoryNode lastLocationAccess; + + public ArrayRegionEqualsNode(ValueNode array1, ValueNode array2, ValueNode length, @ConstantNodeParameter JavaKind kind) { + super(TYPE, StampFactory.forKind(JavaKind.Boolean)); + this.kind = kind; + this.array1 = array1; + this.array2 = array2; + this.length = length; + } + + @NodeIntrinsic + public static native boolean regionEquals(Pointer array1, Pointer array2, int length, @ConstantNodeParameter JavaKind kind); + + @Override + public void generate(NodeLIRBuilderTool gen) { + int constantLength = -1; + if (length.isConstant()) { + constantLength = length.asJavaConstant().asInt(); + } + Value result = gen.getLIRGeneratorTool().emitArrayEquals(kind, gen.operand(array1), gen.operand(array2), gen.operand(length), constantLength, true); + gen.setResult(this, result); } @Override public LocationIdentity getLocationIdentity() { - return NamedLocationIdentity.getArrayLocation(JavaKind.Char); - } - - ValueNode sourcePointer() { - return arguments.get(0); - } - - ValueNode sourceCount() { - return arguments.get(1); - } - - ValueNode targetPointer() { - return arguments.get(2); - } - - ValueNode targetCount() { - return arguments.get(3); - } - - @Override - public void generate(NodeLIRBuilderTool gen) { - int constantTargetCount = -1; - if (targetCount().isConstant()) { - constantTargetCount = targetCount().asJavaConstant().asInt(); - } - Value result = gen.getLIRGeneratorTool().emitStringIndexOf(gen.operand(sourcePointer()), gen.operand(sourceCount()), gen.operand(targetPointer()), gen.operand(targetCount()), - constantTargetCount); - gen.setResult(this, result); + return NamedLocationIdentity.getArrayLocation(kind); } @Override @@ -101,7 +104,4 @@ public class AMD64StringIndexOfNode extends FixedWithNextNode implements LIRLowe updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla)); lastLocationAccess = lla; } - - @NodeIntrinsic - public static native int optimizedStringIndexPointer(Pointer sourcePointer, int sourceCount, Pointer targetPointer, int targetCount); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java index 331eb23e6f..23ac8ee055 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java @@ -145,7 +145,7 @@ public abstract class BasicObjectCloneNode extends MacroStateSplitNode implement tool.createVirtualObject(newVirtual, state, Collections. emptyList(), false); tool.replaceWithVirtual(newVirtual); } else { - ValueNode length = findLength(FindLengthMode.SEARCH_ONLY, tool.getConstantReflectionProvider()); + ValueNode length = findLength(FindLengthMode.SEARCH_ONLY, tool.getConstantReflection()); if (length == null) { return; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java index fd0ffa3a63..7b721938d9 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java @@ -119,7 +119,7 @@ public class ServiceProviderProcessor extends AbstractProcessor { } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { for (Entry e : serviceProviders.entrySet()) { createProviderFile(e.getKey().getQualifiedName().toString(), e.getValue(), e.getKey()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java index 076ae021f3..51d66e2150 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java @@ -34,6 +34,7 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicLong; +import jdk.vm.ci.runtime.JVMCI; import jdk.vm.ci.services.JVMCIPermission; import jdk.vm.ci.services.Services; @@ -76,7 +77,6 @@ public final class GraalServices { * {@link JVMCIPermission} */ public static Iterable load(Class service) { - assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName(); Iterable iterable = ServiceLoader.load(service); return new Iterable<>() { @Override @@ -117,6 +117,11 @@ public final class GraalServices { if (jvmciModule != otherModule) { for (String pkg : jvmciModule.getPackages()) { if (!jvmciModule.isOpen(pkg, otherModule)) { + // JVMCI initialization opens all JVMCI packages + // to Graal which is a prerequisite for Graal to + // open JVMCI packages to other modules. + JVMCI.initialize(); + jvmciModule.addOpens(pkg, otherModule); } } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java index 445aec10d5..70c2f29449 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java @@ -35,8 +35,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.concurrent.TimeUnit; import java.util.List; +import java.util.concurrent.TimeUnit; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugDumpHandler; @@ -46,6 +46,7 @@ import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.serviceprovider.GraalServices; import org.junit.After; import org.junit.Assert; +import org.junit.AssumptionViolatedException; import org.junit.internal.ComparisonCriteria; import org.junit.internal.ExactComparisonCriteria; import org.junit.rules.DisableOnDebug; @@ -239,6 +240,16 @@ public class GraalTest { assertDeepEquals(message, expected, actual, equalFloatsOrDoublesDelta()); } + /** @see JDK-8076557 */ + protected static void assumeManagementLibraryIsLoadable() { + try { + /* Trigger loading of the management library using the bootstrap class loader. */ + GraalServices.getCurrentThreadAllocatedBytes(); + } catch (UnsatisfiedLinkError | NoClassDefFoundError | UnsupportedOperationException e) { + throw new AssumptionViolatedException("Management interface is unavailable: " + e); + } + } + /** * Gets the value used by {@link #assertDeepEquals(Object, Object)} and * {@link #assertDeepEquals(String, Object, Object)} for the maximum delta between two doubles diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java index b837a2dd05..50578c963e 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java @@ -113,6 +113,13 @@ public final class SubprocessUtil { } } + /** + * Detects whether a java agent is attached. + */ + public static boolean isJavaAgentAttached() { + return SubprocessUtil.getVMCommandLine().stream().anyMatch(args -> args.startsWith("-javaagent")); + } + /** * The details of a subprocess execution. */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java index 96d7d6d140..13e11a6200 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java @@ -38,7 +38,7 @@ import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.common.CanonicalizerPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; -import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener; +import org.graalvm.compiler.phases.common.util.EconomicSetNodeEventListener; import org.graalvm.compiler.phases.graph.ReentrantBlockIterator; import org.graalvm.compiler.phases.schedule.SchedulePhase; import org.graalvm.compiler.phases.tiers.PhaseContext; @@ -96,7 +96,7 @@ public abstract class EffectsPhase extends B if (closure.needsApplyEffects()) { // apply the effects collected during this iteration - HashSetNodeEventListener listener = new HashSetNodeEventListener(); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener(); try (NodeEventScope nes = graph.trackNodeEvents(listener)) { closure.applyEffects(); } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java index d52bb5e05f..cb8bcc2f95 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java @@ -188,17 +188,19 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure= 0) { + ValueNode object = GraphUtil.unproxify(load.object()); + LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind); + ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this); + assert cachedValue == null || load.stamp(NodeView.DEFAULT).isCompatible(cachedValue.stamp(NodeView.DEFAULT)) : "The RawLoadNode's stamp is not compatible with the cached value."; + if (cachedValue != null) { + effects.replaceAtUsages(load, cachedValue, load); + addScalarAlias(load, cachedValue); + return true; + } else { + state.addReadCache(object, location, index, accessKind, isOverflowAccess(accessKind, componentKind), load, this); + } } } } @@ -214,7 +216,7 @@ public final class PEReadEliminationClosure extends PartialEscapeClosure newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) { deleted = false; state = newState; @@ -168,7 +152,7 @@ class VirtualizerToolImpl implements VirtualizerTool, CanonicalizerTool { * Special case: Allow storing a single long or double value into two consecutive * int slots. */ - int nextIndex = virtual.entryIndexForOffset(getArrayOffsetProvider(), offset + 4, JavaKind.Int); + int nextIndex = virtual.entryIndexForOffset(getMetaAccess(), offset + 4, JavaKind.Int); if (nextIndex != -1) { canVirtualize = true; assert nextIndex == index + 1 : "expected to be sequential"; @@ -210,7 +194,7 @@ class VirtualizerToolImpl implements VirtualizerTool, CanonicalizerTool { private ValueNode getIllegalConstant() { if (illegalConstant == null) { - illegalConstant = ConstantNode.forConstant(JavaConstant.forIllegal(), getMetaAccessProvider()); + illegalConstant = ConstantNode.forConstant(JavaConstant.forIllegal(), getMetaAccess()); addNode(illegalConstant); } return illegalConstant; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java index 472c6899db..6b33aab07c 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordCastNode.java @@ -28,7 +28,6 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1; import org.graalvm.compiler.core.common.LIRKind; -import org.graalvm.compiler.core.common.type.AbstractObjectStamp; import org.graalvm.compiler.core.common.type.AbstractPointerStamp; import org.graalvm.compiler.core.common.type.IntegerStamp; import org.graalvm.compiler.core.common.type.ObjectStamp; @@ -140,8 +139,25 @@ public final class WordCastNode extends FixedWithNextNode implements LIRLowerabl @Override public boolean inferStamp() { - if (stamp.equals(StampFactory.object())) { - return updateStamp(objectStampFor(input)); + if (stamp instanceof AbstractPointerStamp) { + AbstractPointerStamp objectStamp = (AbstractPointerStamp) stamp; + if (!objectStamp.alwaysNull() && !objectStamp.nonNull()) { + Stamp newStamp = stamp; + Stamp inputStamp = input.stamp(NodeView.DEFAULT); + if (inputStamp instanceof AbstractPointerStamp) { + AbstractPointerStamp pointerStamp = (AbstractPointerStamp) inputStamp; + if (pointerStamp.alwaysNull()) { + newStamp = objectStamp.asAlwaysNull(); + } else if (pointerStamp.nonNull()) { + newStamp = objectStamp.asNonNull(); + } + } else if (inputStamp instanceof IntegerStamp && !((IntegerStamp) inputStamp).contains(0)) { + newStamp = objectStamp.asNonNull(); + } else if (input.isConstant() && isZeroConstant(input)) { + newStamp = objectStamp.asAlwaysNull(); + } + return updateStamp(newStamp); + } } return false; } @@ -153,13 +169,13 @@ public final class WordCastNode extends FixedWithNextNode implements LIRLowerabl return input; } - assert !stamp(NodeView.DEFAULT).isCompatible(input.stamp(NodeView.DEFAULT)); + assert !stamp.isCompatible(input.stamp(NodeView.DEFAULT)); if (input.isConstant()) { /* Null pointers are uncritical for GC, so they can be constant folded. */ if (input.asJavaConstant().isNull()) { - return ConstantNode.forIntegerStamp(stamp(NodeView.DEFAULT), 0); + return ConstantNode.forIntegerStamp(stamp, 0); } else if (isZeroConstant(input)) { - return ConstantNode.forConstant(stamp(NodeView.DEFAULT), JavaConstant.NULL_POINTER, tool.getMetaAccess()); + return ConstantNode.forConstant(stamp, ((AbstractPointerStamp) stamp).nullConstant(), tool.getMetaAccess()); } } @@ -183,7 +199,7 @@ public final class WordCastNode extends FixedWithNextNode implements LIRLowerabl AllocatableValue result = generator.getLIRGeneratorTool().newVariable(kind); if (stamp.equals(StampFactory.object())) { generator.getLIRGeneratorTool().emitConvertZeroToNull(result, value); - } else if (!trackedPointer && !((AbstractObjectStamp) input.stamp(NodeView.DEFAULT)).nonNull()) { + } else if (!trackedPointer && !((AbstractPointerStamp) input.stamp(NodeView.DEFAULT)).nonNull()) { generator.getLIRGeneratorTool().emitConvertNullToZero(result, value); } else { generator.getLIRGeneratorTool().emitMove(result, value); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java index e39182aa32..ce9a69b574 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java @@ -317,8 +317,9 @@ public class WordOperationPlugin implements NodePlugin, TypePlugin, InlineInvoke if (args.length == 2) { location = any(); } else { - assert args[2].isConstant(); + assert args[2].isConstant() : args[2]; location = snippetReflection.asObject(LocationIdentity.class, args[2].asJavaConstant()); + assert location != null : snippetReflection.asObject(Object.class, args[2].asJavaConstant()); } b.push(returnKind, readOp(b, readKind, address, location, operation.opcode())); break; diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java index ab3be6f575..d8e6ff93a0 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordTypes.java @@ -24,6 +24,8 @@ package org.graalvm.compiler.word; +import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; + import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.nodes.ValueNode; @@ -78,7 +80,9 @@ public class WordTypes { this.objectAccessType = metaAccess.lookupJavaType(ObjectAccess.class); this.barrieredAccessType = metaAccess.lookupJavaType(BarrieredAccess.class); - Word.ensureInitialized(); + if (!IS_BUILDING_NATIVE_IMAGE) { + Word.ensureInitialized(); + } this.wordImplType.initialize(); } @@ -88,7 +92,7 @@ public class WordTypes { public boolean isWordOperation(ResolvedJavaMethod targetMethod) { final boolean isWordFactory = wordFactoryType.equals(targetMethod.getDeclaringClass()); if (isWordFactory) { - return true; + return !targetMethod.isConstructor(); } final boolean isObjectAccess = objectAccessType.equals(targetMethod.getDeclaringClass()); final boolean isBarrieredAccess = barrieredAccessType.equals(targetMethod.getDeclaringClass()); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/BigIntegerBenchmark.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/BigIntegerBenchmark.java new file mode 100644 index 0000000000..b6bf4e38c0 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/BigIntegerBenchmark.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2018, 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 micro.benchmarks; + +import java.math.BigInteger; +import java.util.Random; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +/* + * Benchmarks cost of BigInteger intrinsics: + * + * montgomeryMultiply, montgomerySquare, mulAdd, multiplyToLen, squareToLen + */ +public class BigIntegerBenchmark extends BenchmarkBase { + + @State(Scope.Benchmark) + public static class ThreadState { + BigInteger[] data = randomBigInteger(100); + BigInteger[] result = new BigInteger[100]; + + static BigInteger[] randomBigInteger(int len) { + BigInteger[] data = new BigInteger[len]; + Random r = new Random(17); + for (int i = 0; i < data.length; i++) { + data[i] = new BigInteger(r.nextInt(16384) + 512, r); + } + return data; + } + } + + @Benchmark + @Warmup(iterations = 5) + public void bigIntMul(ThreadState state) { + BigInteger[] data = state.data; + for (int i = 1; i < data.length; i++) { + BigInteger[] result = state.result; + result[i] = data[i - 1].multiply(data[i]); + } + } + + @Benchmark + @Warmup(iterations = 5) + public void bigIntMulAdd(ThreadState state) { + BigInteger[] data = state.data; + for (int i = 0; i < data.length; i++) { + BigInteger[] result = state.result; + // Using BigInteger.square() when length is suitable. + // Using BigInteger.mulAdd() when length is suitable. + result[i] = data[i].multiply(data[i]); + } + } + + @Benchmark + @Warmup(iterations = 5) + public void bigIntMontgomeryMul(ThreadState state) { + BigInteger[] data = state.data; + BigInteger exp = BigInteger.valueOf(2); + + for (int i = 0; i < data.length; i++) { + BigInteger[] result = state.result; + int rsh = data[i].bitLength() / 2 + 3; + // The "odd" path. + // Using BigInteger.montgomeryMultiply(). + // Using BigInteger.montgomerySquare(). + // Using BigInteger.mulAdd() when length is suitable. + result[i] = data[i].modPow(exp, data[i].shiftRight(rsh).setBit(0)); + } + } + + @Benchmark + @Warmup(iterations = 5) + public void bigIntMontgomerySqr(ThreadState state) { + BigInteger[] data = state.data; + BigInteger exp = BigInteger.valueOf(2); + + for (int i = 0; i < data.length; i++) { + BigInteger[] result = state.result; + int rsh = data[i].bitLength() / 2 + 3; + // The "even" path. + // Using BigInteger.montgomeryMultiply(). + // Using BigInteger.montgomerySquare(). + // Using BigInteger.mulAdd() when length is suitable. + result[i] = data[i].modPow(exp, data[i].shiftRight(rsh).clearBit(0)); + } + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java index 49014eda94..1d3256a419 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.micro.benchmarks/src/micro/benchmarks/StringBenchmark.java @@ -60,6 +60,12 @@ public class StringBenchmark extends BenchmarkBase { String lorem = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; String loremLastChar = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum?"; // Checkstyle: resume + + String smallLorem = lorem.substring(0, 13); + String largeLorem = lorem.concat(lorem); + + char[] smallCharArray = lorem.substring(0, 13).toCharArray(); + char[] largeCharArray = lorem.concat(lorem).toCharArray(); } @Benchmark @@ -103,4 +109,28 @@ public class StringBenchmark extends BenchmarkBase { public int compareTo(BenchState state) { return state.lorem.compareTo(state.loremLastChar); } + + @Benchmark + @Warmup(iterations = 5) + public String compressSmallString(BenchState state) { + return new String(state.smallCharArray); + } + + @Benchmark + @Warmup(iterations = 5) + public String compressLargeString(BenchState state) { + return new String(state.largeCharArray); + } + + @Benchmark + @Warmup(iterations = 5) + public char[] inflateSmallString(BenchState state) { + return state.smallLorem.toCharArray(); + } + + @Benchmark + @Warmup(iterations = 5) + public char[] inflateLargeString(BenchState state) { + return state.largeLorem.toCharArray(); + } } diff --git a/test/hotspot/jtreg/ProblemList-graal.txt b/test/hotspot/jtreg/ProblemList-graal.txt index 5d4afd2eeb..d747a26a2a 100644 --- a/test/hotspot/jtreg/ProblemList-graal.txt +++ b/test/hotspot/jtreg/ProblemList-graal.txt @@ -165,4 +165,7 @@ org.graalvm.compiler.debug.test.DebugContextTest 8203504 org.graalvm.compiler.hotspot.test.GraalOSRTest 8206947 org.graalvm.compiler.hotspot.test.ReservedStackAccessTest 8213567 windows-all +org.graalvm.compiler.hotspot.test.BigIntegerIntrinsicsTest 8213556 +org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest 8213556 + org.graalvm.compiler.debug.test.TimerKeyTest 8213598 diff --git a/test/hotspot/jtreg/compiler/graalunit/EATest.java b/test/hotspot/jtreg/compiler/graalunit/EATest.java new file mode 100644 index 0000000000..b7f7ded9ef --- /dev/null +++ b/test/hotspot/jtreg/compiler/graalunit/EATest.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, 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. + */ + +/* + * @test + * @summary + * @requires vm.opt.final.EnableJVMCI == true + * + * @modules jdk.internal.vm.compiler + * + * @library /test/lib /compiler/graalunit / + * + * @build compiler.graalunit.common.GraalUnitTestLauncher + * + * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt + * + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.core.test.ea -exclude ExcludeList.txt + */ diff --git a/test/hotspot/jtreg/compiler/graalunit/CoreSparcTest.java b/test/hotspot/jtreg/compiler/graalunit/HotspotSparcTest.java similarity index 94% rename from test/hotspot/jtreg/compiler/graalunit/CoreSparcTest.java rename to test/hotspot/jtreg/compiler/graalunit/HotspotSparcTest.java index 59e88a6cc5..d101c6e10e 100644 --- a/test/hotspot/jtreg/compiler/graalunit/CoreSparcTest.java +++ b/test/hotspot/jtreg/compiler/graalunit/HotspotSparcTest.java @@ -34,5 +34,5 @@ * * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt * - * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.core.sparc.test -exclude ExcludeList.txt + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.hotspot.sparc.test -exclude ExcludeList.txt */ diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java b/test/hotspot/jtreg/compiler/graalunit/LirTest.java similarity index 65% rename from src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java rename to test/hotspot/jtreg/compiler/graalunit/LirTest.java index ec48e98d1b..b4e16ed832 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java +++ b/test/hotspot/jtreg/compiler/graalunit/LirTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -21,14 +21,18 @@ * questions. */ - -package org.graalvm.compiler.core.common.spi; - -import jdk.vm.ci.meta.JavaKind; - -public interface ArrayOffsetProvider { - - int arrayBaseOffset(JavaKind elementKind); - - int arrayScalingFactor(JavaKind elementKind); -} +/* + * @test + * @summary + * @requires vm.opt.final.EnableJVMCI == true + * + * @modules jdk.internal.vm.compiler + * + * @library /test/lib /compiler/graalunit / + * + * @build compiler.graalunit.common.GraalUnitTestLauncher + * + * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt + * + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.lir.test -exclude ExcludeList.txt + */ diff --git a/test/hotspot/jtreg/compiler/graalunit/Replacements12Test.java b/test/hotspot/jtreg/compiler/graalunit/Replacements12Test.java new file mode 100644 index 0000000000..0a54d1f02e --- /dev/null +++ b/test/hotspot/jtreg/compiler/graalunit/Replacements12Test.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, 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. + */ + +/* + * @test + * @summary + * @requires vm.opt.final.EnableJVMCI == true + * + * @modules jdk.internal.vm.compiler + * + * @library /test/lib /compiler/graalunit / + * + * @build compiler.graalunit.common.GraalUnitTestLauncher + * + * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt + * + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.replacements.jdk12.test -exclude ExcludeList.txt + */ diff --git a/test/hotspot/jtreg/compiler/graalunit/Replacements9Test.java b/test/hotspot/jtreg/compiler/graalunit/Replacements9Test.java new file mode 100644 index 0000000000..7d1298ea12 --- /dev/null +++ b/test/hotspot/jtreg/compiler/graalunit/Replacements9Test.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, 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. + */ + +/* + * @test + * @summary + * @requires vm.opt.final.EnableJVMCI == true + * + * @modules jdk.internal.vm.compiler + * + * @library /test/lib /compiler/graalunit / + * + * @build compiler.graalunit.common.GraalUnitTestLauncher + * + * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt + * + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.replacements.jdk9.test -exclude ExcludeList.txt + */ diff --git a/test/hotspot/jtreg/compiler/graalunit/Replacements9_11Test.java b/test/hotspot/jtreg/compiler/graalunit/Replacements9_11Test.java new file mode 100644 index 0000000000..9dc845016c --- /dev/null +++ b/test/hotspot/jtreg/compiler/graalunit/Replacements9_11Test.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018, 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. + */ + +/* + * @test + * @summary + * @requires vm.opt.final.EnableJVMCI == true + * + * @modules jdk.internal.vm.compiler + * + * @library /test/lib /compiler/graalunit / + * + * @build compiler.graalunit.common.GraalUnitTestLauncher + * + * @run driver jdk.test.lib.FileInstaller ../../ProblemList-graal.txt ExcludeList.txt + * + * @run main/othervm compiler.graalunit.common.GraalUnitTestLauncher -prefix org.graalvm.compiler.replacements.jdk9_11.test -exclude ExcludeList.txt + */ diff --git a/test/hotspot/jtreg/compiler/graalunit/TestPackages.txt b/test/hotspot/jtreg/compiler/graalunit/TestPackages.txt index 5af0d070e0..a0894f18c3 100644 --- a/test/hotspot/jtreg/compiler/graalunit/TestPackages.txt +++ b/test/hotspot/jtreg/compiler/graalunit/TestPackages.txt @@ -5,11 +5,13 @@ AsmAarch64 org.graalvm.compiler.asm.aarch64.test AsmAmd64 org.graalvm.compiler.asm.amd64.test AsmSparc org.graalvm.compiler.asm.sparc.test CoreAmd64 org.graalvm.compiler.core.amd64.test -CoreSparc org.graalvm.compiler.core.sparc.test @requires vm.simpleArch == "sparcv9" Core org.graalvm.compiler.core.test @requires !vm.graal.enabled +EA org.graalvm.compiler.core.test.ea +EA9 org.graalvm.compiler.core.jdk9.test.ea Debug org.graalvm.compiler.debug.test Graph org.graalvm.compiler.graph.test @requires vm.graal.enabled HotspotAmd64 org.graalvm.compiler.hotspot.amd64.test +HotspotSparc org.graalvm.compiler.hotspot.sparc.test @requires vm.simpleArch == "sparcv9" HotspotLir org.graalvm.compiler.hotspot.lir.test Hotspot org.graalvm.compiler.hotspot.test Loop org.graalvm.compiler.loop.test @@ -17,6 +19,9 @@ Nodes org.graalvm.compiler.nodes.test @requires vm.graal.enabled Options org.graalvm.compiler.options.test PhasesCommon org.graalvm.compiler.phases.common.test Replacements org.graalvm.compiler.replacements.test +Replacements9 org.graalvm.compiler.replacements.jdk9.test +Replacements9_11 org.graalvm.compiler.replacements.jdk9_11.test +Replacements12 org.graalvm.compiler.replacements.jdk12.test Util org.graalvm.util.test JttBackend org.graalvm.compiler.jtt.backend JttBytecode org.graalvm.compiler.jtt.bytecode @@ -37,4 +42,4 @@ JttReflectFieldSet org.graalvm.compiler.jtt.reflect.Field_set JttReflectGZ org.graalvm.compiler.jtt.reflect.[g-zG-Z] JttThreads org.graalvm.compiler.jtt.threads LirJtt org.graalvm.compiler.lir.jtt -Lir org.graalvm.compiler.lir.test \ No newline at end of file +Lir org.graalvm.compiler.lir.test