# HG changeset patch # User dlong # Date 1542222310 28800 # Wed Nov 14 11:05:10 2018 -0800 # Node ID 2cc888cdafffbcb78598b2a2e68efa0ac9879cb0 # Parent bbbcd90f0adbf7f41a287a25eb668e60fe1f28a0 [mq]: graal2 diff --git a/make/CompileJavaModules.gmk b/make/CompileJavaModules.gmk --- a/make/CompileJavaModules.gmk +++ b/make/CompileJavaModules.gmk @@ -450,21 +450,17 @@ 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 @@ 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/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 --- 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.debug.DebugContext; import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder; +import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; import org.graalvm.compiler.hotspot.meta.HotSpotProviders; -import org.graalvm.compiler.hotspot.meta.HotSpotInvokeDynamicPlugin; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.phases.LIRSuites; @@ -167,7 +167,7 @@ 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 --- 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.code.CompilationResult; import org.graalvm.compiler.core.GraalCompilerOptions; import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.debug.DebugContext.Activation; import org.graalvm.compiler.debug.TTY; -import org.graalvm.compiler.debug.DebugContext.Activation; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.printer.GraalDebugHandlersFactory; import org.graalvm.compiler.serviceprovider.GraalServices; @@ -143,7 +143,7 @@ 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 --- 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 @@ 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 @@ 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 @@ @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 --- 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.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 @@ 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 @@ @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 --- 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.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 @@ 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 --- 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 @@ */ 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 --- 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 @@ 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 --- 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 --- 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 --- 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 @@ 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 @@ 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 @@ 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 --- 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 @@ -1476,6 +1476,14 @@ } /** + * 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()}. */ @Override 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 --- 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.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 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 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 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 @@ @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 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 @@ @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 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 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 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 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 @@ 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 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 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 @@ @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 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 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 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 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 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 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 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 @@ * {@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 @@ 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 @@ 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 @@ 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 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 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 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 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 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 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 @@ 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 @@ 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 kortestd(Register src1, Register src2) { + assert supports(CPUFeature.AVX512BW); + 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); + } + + // Insn: KORTESTQ k1, k2 + // This instruction produces ZF or CF flags public final void kortestq(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.0F.W1 98 /r + vexPrefix(src1, Register.None, src2, AVXSize.XMM, P_, M_0F, W1, true); emitByte(0x98); emitModRM(src1, src2); } - public final void kmovq(Register dst, Register src) { + public final void kmovd(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)); - - 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); + 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 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 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 --- 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.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 @@ 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 @@ 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 @@ @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 @@ 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 @@ * 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 @@ byte2 |= l << 2; byte2 |= pp; - emitByte(0xC5); + emitByte(Prefix.VEX2); emitByte(byte2); } else { // 3 byte encoding @@ -881,7 +935,7 @@ byte3 |= l << 2; byte3 |= pp; - emitByte(0xC4); + emitByte(Prefix.VEX3); emitByte(byte2); emitByte(byte3); } @@ -900,12 +954,12 @@ } } - 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 @@ } } + // @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 @@ 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 @@ int p2 = 0; p2 |= w << 7; p2 |= ((vvvvv ^ 0x0F) & 0x0F) << 3; - p2 |= 0x4; + p2 |= 0x04; p2 |= pp; emitByte(p2); @@ -1050,6 +1149,11 @@ 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 @@ * 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 @@ * {@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 --- 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 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 --- 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 @@ 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 @@ 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 @@ 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 --- /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 --- /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 --- 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 @@ 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 --- 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.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 @@ } @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 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 --- 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.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 @@ } @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 --- 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 @@ 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 --- 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.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.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; @@ -932,6 +937,57 @@ } @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)); switch ((AMD64Kind) input.getPlatformKind()) { 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 --- 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.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 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 @@ } @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 @@ 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 @@ 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 --- 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.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 @@ 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 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 --- 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.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 @@ 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 --- 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 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 --- /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 --- 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 @@ } 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 @@ } 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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 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 @@ } // 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 --- 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 @@ 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 --- 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 @@ } 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 @@ 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 @@ 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 --- 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 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/ArrayOffsetProvider.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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.spi; - -import jdk.vm.ci.meta.JavaKind; - -public interface ArrayOffsetProvider { - - int arrayBaseOffset(JavaKind elementKind); - - int arrayScalingFactor(JavaKind elementKind); -} 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 --- 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 @@ 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 --- 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 @@ @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 --- /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 --- 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 @@ 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 --- 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 @@ } @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 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 --- 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 @@ @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 --- 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 --- 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 @@ 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 @@ 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 --- 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.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 @@ 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 --- 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 @@ @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 --- 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 @@ @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 --- 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.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 --- 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.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 @@ 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 --- 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.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 @@ * 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 @@ 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 --- 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 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 --- 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 @@ 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 --- /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 --- 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.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 @@ 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 --- 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 @@ 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 @@ 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 --- 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.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 @@ * 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 @@ 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 @@ 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 @@ 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 --- 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 @@ 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 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 @@ 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 --- 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.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 @@ @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 @@ @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 --- 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.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 @@ * 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 @@ } 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 --- 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.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 @@ 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 --- 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.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 @@ * Turns a Graal {@link CompilationResult} into a {@link CompiledCode} object that can be passed * to the VM for code installation. */ - protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult); + protected abstract CompiledCode createCompiledCode(ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, boolean isDefault, OptionValues options); /** * @see #createInstalledCode(DebugContext, ResolvedJavaMethod, CompilationRequest, @@ -192,6 +193,9 @@ * @param context a custom debug context to use for the code installation * @return a reference to the compiled and ready-to-run installed code * @throws BailoutException if the code installation failed + * @throws IllegalArgumentException if {@code installedCode != null} and this platform does not + * {@linkplain CodeCacheProvider#installCode support} a predefined + * {@link InstalledCode} object */ @SuppressWarnings("try") public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult, @@ -209,8 +213,8 @@ InstalledCode installedCode; try { - preCodeInstallationTasks(tasks, compilationResult, predefinedInstalledCode); - CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); + preCodeInstallationTasks(tasks, compilationResult); + CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult, isDefault, debug.getOptions()); installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); assert predefinedInstalledCode == null || installedCode == predefinedInstalledCode; } catch (Throwable t) { @@ -218,7 +222,7 @@ throw t; } - postCodeInstallationTasks(tasks, installedCode); + postCodeInstallationTasks(tasks, compilationResult, installedCode); return installedCode; } catch (Throwable e) { @@ -232,16 +236,16 @@ } } - private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult, InstalledCode predefinedInstalledCode) { + private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult) { for (CodeInstallationTask task : tasks) { - task.preProcess(compilationResult, predefinedInstalledCode); + task.preProcess(compilationResult); } } - private static void postCodeInstallationTasks(CodeInstallationTask[] tasks, InstalledCode installedCode) { + private static void postCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult, InstalledCode installedCode) { try { for (CodeInstallationTask task : tasks) { - task.postProcess(installedCode); + task.postProcess(compilationResult, installedCode); } } catch (Throwable t) { installedCode.invalidate(); @@ -310,19 +314,18 @@ * Task to run before code installation. * * @param compilationResult the code about to be installed - * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object that will be - * used as a reference to the installed code. May be {@code null}. * */ - public void preProcess(CompilationResult compilationResult, InstalledCode predefinedInstalledCode) { + public void preProcess(CompilationResult compilationResult) { } /** * Task to run after the code is installed. * + * @param compilationResult the code about to be installed * @param installedCode a reference to the installed code */ - public void postProcess(InstalledCode installedCode) { + public void postProcess(CompilationResult compilationResult, InstalledCode installedCode) { } /** diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java @@ -197,6 +197,7 @@ @Test public void testEnabledSandbox() { + TimerKeyTest.assumeManagementLibraryIsLoadable(); EconomicMap, Object> map = EconomicMap.create(); // Configure with an option that enables scopes map.put(DebugOptions.DumpOnError, true); @@ -226,6 +227,7 @@ @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 @@ @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 --- 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.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 @@ @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 --- 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 @@ */ 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 @@ 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 --- 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 @@ @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 --- 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 @@ } if (CLOSED.equals(path)) { TTY.println("Warning: Graal diagnostic directory already closed"); + return null; } return path; } @@ -129,6 +130,7 @@ 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 @@ @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 --- 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.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 --- 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.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.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 @@ * 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 @@ 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 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 @@ 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 @@ 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 --- 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.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 @@ 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 @@ } 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 --- 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.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 @@ } @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 --- /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 --- /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 --- /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 --- /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 --- /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 --- /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 --- 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.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 @@ 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 @@ } 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 --- 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.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.HotSpotCounterOp; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +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 @@ // 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 @@ 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 @@ } 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 --- 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.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 @@ 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 --- 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 @@ 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 --- /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/core/sparc/test/SPARCAllocatorTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.graalvm.compiler.core.sparc.test; - -import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; -import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; -import static org.junit.Assume.assumeTrue; - -import org.graalvm.compiler.core.test.backend.AllocatorTest; -import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; -import org.graalvm.compiler.hotspot.HotSpotBackend; -import org.junit.Before; -import org.junit.Test; - -import jdk.vm.ci.sparc.SPARC; - -public class SPARCAllocatorTest extends AllocatorTest { - - private final GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig(); - - @Before - public void checkSPARC() { - assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); - assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null); - assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions())); - } - - @Test - public void test1() { - testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); - } - - public static long test1snippet(long x) { - return x + 41; - } - - @Test - public void test2() { - testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); - } - - public static long test2snippet(long x) { - return x * 41; - } - - @Test - public void test3() { - testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0); - } - - public static long test3snippet(long x) { - return x / 41 + x % 41; - } - -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/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 new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/hotspot/sparc/test/SPARCAllocatorTest.java @@ -0,0 +1,77 @@ +/* + * 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 + * 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.sparc.test; + +import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure; +import static org.graalvm.compiler.core.common.GraalOptions.TraceRA; +import static org.junit.Assume.assumeTrue; + +import org.graalvm.compiler.core.test.backend.AllocatorTest; +import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; +import org.graalvm.compiler.hotspot.HotSpotBackend; +import org.junit.Before; +import org.junit.Test; + +import jdk.vm.ci.sparc.SPARC; + +public class SPARCAllocatorTest extends AllocatorTest { + + private final GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig(); + + @Before + public void checkSPARC() { + assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC); + assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null); + assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions())); + } + + @Test + public void test1() { + testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); + } + + public static long test1snippet(long x) { + return x + 41; + } + + @Test + public void test2() { + testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0); + } + + public static long test2snippet(long x) { + return x * 41; + } + + @Test + public void test3() { + testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0); + } + + public static long test3snippet(long x) { + return x / 41 + x % 41; + } + +} 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 --- 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 @@ @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 --- 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 @@ 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 @@ } 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 --- /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 --- 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 @@ // 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 @@ * 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 @@ "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 @@ "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 @@ "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 @@ // 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 @@ "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 @@ "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 @@ 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 --- 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 @@ */ @Test public void testVMCompilation1() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", "-XX:+UseJVMCICompiler", "-Dgraal.CompilationFailureAction=ExitVM", @@ -69,6 +70,7 @@ */ @Test public void testVMCompilation2() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList("-XX:-TieredCompilation", "-XX:+UseJVMCICompiler", "-Dgraal.ExitVMOnException=true", @@ -109,6 +111,7 @@ */ @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 @@ */ @Test public void testTruffleCompilation1() throws IOException, InterruptedException { + assumeManagementLibraryIsLoadable(); testHelper(Collections.emptyList(), Arrays.asList( "-Dgraal.CompilationFailureAction=ExitVM", @@ -175,6 +179,7 @@ */ @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 --- 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 @@ 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 @@ 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 --- 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 @@ 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 --- 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 @@ @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 --- 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.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 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 @@ 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 --- 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 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 --- 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 @@ 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 @@ @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 --- 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 @@ 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 --- 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 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 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 @@ @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 @@ 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 --- 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.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 --- 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.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 @@ } @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 --- 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 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 @@ 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 --- 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 @@ * * 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 @@ 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 --- 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 @@ } @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 --- 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.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.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.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 @@ * {@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 @@ 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; + + 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); } - 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)); - + 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 @@ } 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 --- 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 @@ 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 @@ 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 --- 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.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.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 @@ } 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 @@ 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 @@ 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 --- 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.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 @@ } @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 @@ } } 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 --- 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 @@ * @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 --- 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.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.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 --- 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 @@ */ 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 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 --- /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 --- 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 @@ 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 --- 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 @@ -774,20 +774,6 @@ } @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 --- 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 @@ * 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 @@ * 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 @@ * 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 @@ * 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 --- 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.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 @@ * @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 --- 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.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 @@ 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 @@ 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 --- 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 @@ } @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 --- 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 @@ } @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 --- 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 @@ 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 @@ DeoptimizeNode.deopt(None, RuntimeConstraint); } } - DeoptimizeNode.deopt(None, RuntimeConstraint); - return null; + return dynamicNewInstanceStub(type); } /** @@ -387,6 +386,24 @@ 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}. */ private static Object nonNullOrDeopt(Object 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 --- 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 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.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 @@ 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 --- 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.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; @@ -1037,6 +1038,15 @@ } /** + * @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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } - private void genCheckCast() { - int cpi = getStream().readCPI(); + private void genCheckCast(int cpi) { JavaType type = lookupType(cpi, CHECKCAST); ValueNode object = frameState.pop(JavaKind.Object); - - if (!(type instanceof ResolvedJavaType)) { + genCheckCast(type, object); + } + + 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 @@ 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); - - if (!(type instanceof ResolvedJavaType)) { + genInstanceOf(type, object); + } + + 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 @@ 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 @@ 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 @@ private void genNewObjectArray(int cpi) { JavaType type = lookupType(cpi, ANEWARRAY); - - if (!(type instanceof ResolvedJavaType)) { + genNewObjectArray(type); + } + + 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 @@ JavaType type = lookupType(cpi, MULTIANEWARRAY); int rank = getStream().readUByte(bci() + 3); ValueNode[] dims = new ValueNode[rank]; - - if (!(type instanceof ResolvedJavaType)) { + genNewMultiArray(type, rank, dims); + } + + 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 @@ } 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 @@ } 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 @@ } genStoreField(receiver, resolvedField, value); } else { - handleUnresolvedStoreField(field, value, receiver); + handleUnresolvedStoreField(field, value, receiverInput); } } @@ -4484,6 +4561,7 @@ } 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 @@ 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ */ 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 --- 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 @@ 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 --- /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 --- 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 @@ 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 --- 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 @@ 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 --- 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 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 --- 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 @@ } } - @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 --- 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 @@ } } - @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 --- 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 org.graalvm.compiler.asm.Label; import org.graalvm.compiler.asm.aarch64.AArch64Address; +import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler; -import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag; import org.graalvm.compiler.core.common.LIRKind; import org.graalvm.compiler.lir.LIRInstructionClass; import org.graalvm.compiler.lir.Opcode; @@ -78,8 +78,8 @@ 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 --- 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 @@ @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 --- /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 --- 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 @@ 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 --- 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 @@ 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 --- 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,17 +24,22 @@ 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.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; @@ -42,13 +47,9 @@ 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.code.TargetDescription; -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; /** * Emits code which compares two arrays of the same length. If the CPU supports any vector @@ -61,28 +62,39 @@ 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 @@ // 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 @@ 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 @@ 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 @@ /** * 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 @@ 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 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ /** * 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 @@ 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 @@ 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 @@ /** * 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 @@ 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 @@ /** * 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 @@ /** * 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 @@ 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 @@ /** * 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 @@ // 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 --- 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.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 @@ 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; + 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 arrayLengthValue is + // annotated with @Use + asm.movl(slotsRemaining, arrayLength); + // load array pointer + asm.movq(result, 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 + 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; - assert bulkSizeBytes >= 64; + 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 array length - // important: this must be the first register manipulation, since charArrayLengthValue 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); - // fill comparison vector with copies of the search value - emitBroadcast(asm, vecCmp, vecArray1, vectorSize); + 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 @@ // 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); + 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(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(vectorFound1); - // find index of first set bit in bit mask - asm.bsfq(cmpResult1, cmpResult1); - // add offset to array pointer - asm.addq(result, cmpResult1); - - 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 @@ } /** - * 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 @@ } } - 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 --- 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 @@ 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 --- 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 --- /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 --- /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 --- 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 @@ @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 --- 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 @@ 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 --- 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 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 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 @@ 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ /** * 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 @@ 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 --- 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 @@ NodeCost getOrInitCost(AbstractBlockBase 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 --- 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 @@ // 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 --- 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 @@ /** * 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 @@ 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 @@ 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 --- 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 @@ @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 @@ 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 @@ 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 --- 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.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.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 @@ // 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 @@ 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 @@ 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 @@ 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; + private static void updatePreLoopLimit(CountedLoopInfo preCounted) { + // Update the pre loops limit test + // Make new limit one iteration + 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 = preCounted.getLimit(); + LogicNode entryCheck; + if (preCounted.getDirection() == Direction.Up) { + entryCheck = IntegerLessThanNode.create(newLimit, ub, NodeView.DEFAULT); } else { - mainStride = mainLoop.getDuplicatedNode(preStride); + entryCheck = IntegerLessThanNode.create(ub, newLimit, NodeView.DEFAULT); } - // 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); - + newLimit = ConditionalNode.create(entryCheck, newLimit, ub, NodeView.DEFAULT); // Re-wire the condition with the new limit - compareNode.replaceFirstInput(ub, newLimit); - } - - private static void updatePreLoopLimit(IfNode preLimit, InductionVariable preIv, 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()); - - // 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(); - } else { - throw GraalError.shouldNotReachHere(); - } - // 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 @@ 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 @@ 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 --- 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 @@ @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 @@ @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 @@ 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 @@ 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 @@ 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 @@ @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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ @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 --- 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 @@ @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 --- 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 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.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 @@ /** * 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 @@ 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 --- 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 @@ } @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 --- 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 static final NodeClass TYPE = NodeClass.create(AbstractBeginNode.class); + private boolean withSpeculationFence; + protected AbstractBeginNode(NodeClass c) { this(c, StampFactory.forVoid()); } @@ -91,7 +93,9 @@ @Override public void generate(NodeLIRBuilderTool gen) { - // nop + if (withSpeculationFence) { + gen.getLIRGeneratorTool().emitSpeculationFence(); + } } public NodeIterable guards() { @@ -112,6 +116,14 @@ }; } + /** + * 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 --- 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 @@ * {@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 --- 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 @@ 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 --- 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.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 @@ @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 @@ @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 --- 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 @@ 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 @@ @Override public NodeCycles estimatedNodeCycles() { + if (loopBegin() == null) { + return CYCLES_UNKNOWN; + } if (canSafepoint()) { // jmp+read return CYCLES_2; @@ -152,8 +158,11 @@ @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 --- 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 @@ } 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 --- 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.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 @@ 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 @@ if (ret != this) { return ret; } + NodeView view = NodeView.from(tool); if (forX == forY) { // @formatter:off @@ -203,7 +215,7 @@ 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 @@ } } + 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 --- 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 @@ 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 --- 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 @@ 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.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 @@ 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 --- 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 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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ * 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 --- 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 @@ -85,6 +85,24 @@ } @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 --- 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 @@ // 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 --- 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 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 @@ 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); + // 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; } - 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 @@ 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 --- 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.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 @@ 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 @@ 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 @@ } 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 @@ } 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 @@ 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 @@ } 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 @@ 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 @@ * 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 @@ } 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 --- 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 @@ 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 --- 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.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 @@ } } - 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 @@ * 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 --- 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 @@ 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 --- 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 @@ @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 --- 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 @@ protected FixedNode endNode; - protected double probability; + protected double relativeFrequency; private Loop loop; protected Block postdominator; @@ -236,14 +236,18 @@ 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 --- 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 @@ 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 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 @@ 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 @@ 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 @@ } /** - * 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 --- 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 @@ 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 @@ @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 @@ } 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/debug/OpaqueNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/debug/OpaqueNode.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.graalvm.compiler.nodes.debug; - -import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; - -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.NodeView; -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; - -@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; - - public OpaqueNode(ValueNode value) { - super(TYPE, value.stamp(NodeView.DEFAULT).unrestricted()); - this.value = value; - } - - public ValueNode getValue() { - return value; - } - - @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/GetClassNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/GetClassNode.java --- 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 @@ 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 --- 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 @@ 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 --- /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/extended/OpaqueNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OpaqueNode.java new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/OpaqueNode.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.nodes.extended; + +import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; +import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; + +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.nodeinfo.NodeInfo; +import org.graalvm.compiler.nodes.NodeView; +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; + +@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()); + this.value = value; + } + + public ValueNode getValue() { + 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 --- 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 --- 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.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 @@ } 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 --- /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 --- 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 @@ 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 --- 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 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 --- 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 @@ * 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 --- 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 @@ 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 --- 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 @@ * 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 --- /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 --- 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 @@ /** * 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 --- 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.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; @@ -94,6 +96,17 @@ 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) * substitution graph} for a given method. 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 --- 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 @@ 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 @@ /** * @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 --- 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.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; @@ -108,8 +107,5 @@ } @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 --- 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 @@ 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 @@ 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 --- 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 @@ 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.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 @@ } @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 --- 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.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 @@ } @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 --- 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 @@ 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.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 @@ * * @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 --- 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.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.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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ } } - 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 @@ } } - 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 @@ } } - 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 @@ } @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { + public boolean doProcess(Set annotations, RoundEnvironment roundEnv) { if (roundEnv.processingOver()) { return true; } @@ -404,7 +399,9 @@ 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 @@ 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 @@ 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 --- 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.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 @@ } 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 --- 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.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 @@ } } - 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 --- 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.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 @@ @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 --- /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 --- 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.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 @@ @Override @SuppressWarnings("try") protected void run(StructuredGraph graph, PhaseContext context) { - HashSetNodeEventListener listener = new HashSetNodeEventListener().exclude(NODE_ADDED); + EconomicSetNodeEventListener listener = new EconomicSetNodeEventListener().exclude(NODE_ADDED); int count = 0; while (true) { try (NodeEventScope nes = graph.trackNodeEvents(listener)) { diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ProfileCompiledMethodsPhase.java @@ -98,7 +98,7 @@ ControlFlowGraph cfg = ControlFlowGraph.compute(graph, true, true, true, true); for (Loop 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 @@ 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 @@ 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 --- 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.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 @@ @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 --- 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.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 @@ 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 --- 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.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 @@ 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 --- 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 @@ 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 @@ 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/EconomicSetNodeEventListener.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/EconomicSetNodeEventListener.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.phases.common.util; + +import java.util.EnumSet; +import java.util.Set; + +import jdk.internal.vm.compiler.collections.EconomicSet; +import jdk.internal.vm.compiler.collections.Equivalence; +import org.graalvm.compiler.graph.Graph.NodeEvent; +import org.graalvm.compiler.graph.Graph.NodeEventListener; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.Node.IndirectCanonicalization; + +/** + * A simple {@link NodeEventListener} implementation that accumulates event nodes in a + * {@link EconomicSet}. + */ +public class EconomicSetNodeEventListener extends NodeEventListener { + + private final EconomicSet nodes; + private final Set filter; + + /** + * Creates a {@link NodeEventListener} that collects nodes from all events. + */ + public EconomicSetNodeEventListener() { + this.nodes = EconomicSet.create(Equivalence.IDENTITY); + this.filter = EnumSet.allOf(NodeEvent.class); + } + + /** + * Creates a {@link NodeEventListener} that collects nodes from all events that match a given + * filter. + */ + public EconomicSetNodeEventListener(Set filter) { + this.nodes = EconomicSet.create(Equivalence.IDENTITY); + this.filter = filter; + } + + /** + * Excludes a given event from those for which nodes are collected. + */ + public EconomicSetNodeEventListener exclude(NodeEvent e) { + filter.remove(e); + return this; + } + + @Override + public void changed(NodeEvent e, Node node) { + if (filter.contains(e)) { + nodes.add(node); + if (node instanceof IndirectCanonicalization) { + for (Node usage : node.usages()) { + nodes.add(usage); + } + } + } + } + + /** + * Gets the set being used to accumulate the nodes communicated to this listener. + */ + public EconomicSet getNodes() { + return nodes; + } +} 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/HashSetNodeEventListener.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package 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; -import jdk.internal.vm.compiler.collections.Equivalence; -import org.graalvm.compiler.graph.Graph.NodeEvent; -import org.graalvm.compiler.graph.Graph.NodeEventListener; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.Node.IndirectCanonicalization; - -/** - * A simple {@link NodeEventListener} implementation that accumulates event nodes in a - * {@link HashSet}. - */ -public class HashSetNodeEventListener extends NodeEventListener { - - private final EconomicSet nodes; - private final Set filter; - - /** - * Creates a {@link NodeEventListener} that collects nodes from all events. - */ - public HashSetNodeEventListener() { - this.nodes = EconomicSet.create(Equivalence.IDENTITY); - this.filter = EnumSet.allOf(NodeEvent.class); - } - - /** - * Creates a {@link NodeEventListener} that collects nodes from all events that match a given - * filter. - */ - public HashSetNodeEventListener(Set filter) { - this.nodes = EconomicSet.create(Equivalence.IDENTITY); - this.filter = filter; - } - - /** - * Excludes a given event from those for which nodes are collected. - */ - public HashSetNodeEventListener exclude(NodeEvent e) { - filter.remove(e); - return this; - } - - @Override - public void changed(NodeEvent e, Node node) { - if (filter.contains(e)) { - nodes.add(node); - if (node instanceof IndirectCanonicalization) { - for (Node usage : node.usages()) { - nodes.add(usage); - } - } - } - } - - /** - * Gets the set being used to accumulate the nodes communicated to this listener. - */ - public EconomicSet getNodes() { - return nodes; - } -} 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 --- 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 @@ 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/FixedNodeProbabilityCache.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - - -package org.graalvm.compiler.phases.graph; - -import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities; - -import java.util.function.ToDoubleFunction; - -import jdk.internal.vm.compiler.collections.EconomicMap; -import jdk.internal.vm.compiler.collections.Equivalence; -import org.graalvm.compiler.debug.CounterKey; -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodes.AbstractBeginNode; -import org.graalvm.compiler.nodes.AbstractEndNode; -import org.graalvm.compiler.nodes.AbstractMergeNode; -import org.graalvm.compiler.nodes.ControlSplitNode; -import org.graalvm.compiler.nodes.EndNode; -import org.graalvm.compiler.nodes.FixedNode; -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. - */ -public class FixedNodeProbabilityCache implements ToDoubleFunction { - - private static final CounterKey computeNodeProbabilityCounter = DebugContext.counter("ComputeNodeProbability"); - - private final EconomicMap cache = EconomicMap.create(Equivalence.IDENTITY); - - /** - *

- * Given a {@link FixedNode} this method finds the most immediate {@link AbstractBeginNode} - * preceding it that either: - *

    - *
  • has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the - * start-node)
  • - *
  • has a control-split predecessor
  • - *
- *

- * - *

- * 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: - *

    - *
  • 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
    • - *
    - *
  • Control-split predecessor: probability 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 - * appears to be dead-code (ie, lacks a predecessor). - *

- * - */ - @Override - public double applyAsDouble(FixedNode node) { - assert node != null; - computeNodeProbabilityCounter.increment(node.getDebug()); - - FixedNode current = findBegin(node); - if (current == null) { - // this should only appear for dead code - return 1D; - } - - assert current instanceof AbstractBeginNode; - Double cachedValue = cache.get(current); - if (cachedValue != null) { - return cachedValue; - } - - double probability = 0.0; - if (current.predecessor() == null) { - if (current instanceof AbstractMergeNode) { - probability = handleMerge(current, probability); - } else { - assert current instanceof StartNode; - probability = 1D; - } - } else { - ControlSplitNode split = (ControlSplitNode) current.predecessor(); - probability = multiplyProbabilities(split.probability((AbstractBeginNode) current), applyAsDouble(split)); - } - assert !Double.isNaN(probability) && !Double.isInfinite(probability) : current + " " + probability; - cache.put(current, probability); - return probability; - } - - private double handleMerge(FixedNode current, double probability) { - double result = probability; - AbstractMergeNode currentMerge = (AbstractMergeNode) current; - NodeInputList currentForwardEnds = currentMerge.forwardEnds(); - /* - * Use simple iteration instead of streams, since the stream infrastructure adds many frames - * which causes the recursion to overflow the stack earlier than it would otherwise. - */ - for (AbstractEndNode endNode : currentForwardEnds) { - result += applyAsDouble(endNode); - } - if (current instanceof LoopBeginNode) { - result = multiplyProbabilities(result, ((LoopBeginNode) current).loopFrequency()); - } - return result; - } - - private static FixedNode findBegin(FixedNode node) { - FixedNode current = node; - while (true) { - assert current != null; - Node predecessor = current.predecessor(); - if (current instanceof AbstractBeginNode) { - if (predecessor == null) { - break; - } else if (predecessor.successors().count() != 1) { - assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor; - break; - } - } else if (predecessor == null) { - current = null; - break; - } - current = (FixedNode) predecessor; - } - return current; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeRelativeFrequencyCache.java @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.phases.graph; + +import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyRelativeFrequencies; + +import java.util.function.ToDoubleFunction; + +import jdk.internal.vm.compiler.collections.EconomicMap; +import jdk.internal.vm.compiler.collections.Equivalence; +import org.graalvm.compiler.debug.CounterKey; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeInputList; +import org.graalvm.compiler.nodes.AbstractBeginNode; +import org.graalvm.compiler.nodes.AbstractEndNode; +import org.graalvm.compiler.nodes.AbstractMergeNode; +import org.graalvm.compiler.nodes.ControlSplitNode; +import org.graalvm.compiler.nodes.EndNode; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.LoopBeginNode; +import org.graalvm.compiler.nodes.StartNode; + +/** + * Compute relative frequencies for fixed nodes on the fly and cache them at + * {@link AbstractBeginNode}s. + */ +public class FixedNodeRelativeFrequencyCache implements ToDoubleFunction { + + private static final CounterKey computeNodeRelativeFrequencyCounter = DebugContext.counter("ComputeNodeRelativeFrequency"); + + private final EconomicMap cache = EconomicMap.create(Equivalence.IDENTITY); + + /** + *

+ * Given a {@link FixedNode} this method finds the most immediate {@link AbstractBeginNode} + * preceding it that either: + *

    + *
  • has no predecessor (ie, the begin-node is a merge, in particular a loop-begin, or the + * start-node)
  • + *
  • has a control-split predecessor
  • + *
+ *

+ * + *

+ * 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 + * 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 relative frequency adds up those of its forward-ends
    • + *
    • a loop-begin, with frequency as above multiplied by the loop-frequency
    • + *
    + *
  • Control-split predecessor: frequency of the branch times that of the control-split
  • + *
+ *

+ * + *

+ * 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). + *

+ * + */ + @Override + public double applyAsDouble(FixedNode node) { + assert node != null; + computeNodeRelativeFrequencyCounter.increment(node.getDebug()); + + FixedNode current = findBegin(node); + if (current == null) { + // this should only appear for dead code + return 1D; + } + + assert current instanceof AbstractBeginNode; + Double cachedValue = cache.get(current); + if (cachedValue != null) { + return cachedValue; + } + + double relativeFrequency = 0.0; + if (current.predecessor() == null) { + if (current instanceof AbstractMergeNode) { + relativeFrequency = handleMerge(current, relativeFrequency); + } else { + assert current instanceof StartNode; + relativeFrequency = 1D; + } + } else { + ControlSplitNode split = (ControlSplitNode) current.predecessor(); + relativeFrequency = multiplyRelativeFrequencies(split.probability((AbstractBeginNode) current), applyAsDouble(split)); + } + assert !Double.isNaN(relativeFrequency) && !Double.isInfinite(relativeFrequency) : current + " " + relativeFrequency; + cache.put(current, relativeFrequency); + return relativeFrequency; + } + + private double handleMerge(FixedNode current, double relativeFrequency) { + double result = relativeFrequency; + AbstractMergeNode currentMerge = (AbstractMergeNode) current; + NodeInputList currentForwardEnds = currentMerge.forwardEnds(); + /* + * Use simple iteration instead of streams, since the stream infrastructure adds many frames + * which causes the recursion to overflow the stack earlier than it would otherwise. + */ + for (AbstractEndNode endNode : currentForwardEnds) { + result += applyAsDouble(endNode); + } + if (current instanceof LoopBeginNode) { + result = multiplyRelativeFrequencies(result, ((LoopBeginNode) current).loopFrequency()); + } + return result; + } + + private static FixedNode findBegin(FixedNode node) { + FixedNode current = node; + while (true) { + assert current != null; + Node predecessor = current.predecessor(); + if (current instanceof AbstractBeginNode) { + if (predecessor == null) { + break; + } else if (predecessor.successors().count() != 1) { + assert predecessor instanceof ControlSplitNode : "a FixedNode with multiple successors needs to be a ControlSplitNode: " + current + " / " + predecessor; + break; + } + } else if (predecessor == null) { + current = null; + break; + } + current = (FixedNode) predecessor; + } + return current; + } +} 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 --- 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 @@ 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 @@ 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 --- 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; @@ -93,11 +92,6 @@ } @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 --- 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 @@ 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 --- 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 @@ @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 @@ } } - 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 --- 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 @@ 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 --- 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.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 @@ 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 --- 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 @@ } 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 --- /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 --- 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 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 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 @@ @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 @@ } @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 --- 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 @@ 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 @@ 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/AMD64StringIndexOfNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringIndexOfNode.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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.amd64; - -import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64; - -import org.graalvm.compiler.core.common.type.StampFactory; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeInputList; -import org.graalvm.compiler.nodeinfo.InputType; -import org.graalvm.compiler.nodeinfo.NodeCycles; -import org.graalvm.compiler.nodeinfo.NodeInfo; -import org.graalvm.compiler.nodes.FixedWithNextNode; -import org.graalvm.compiler.nodes.NamedLocationIdentity; -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.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(size = SIZE_64, cycles = NodeCycles.CYCLES_UNKNOWN) -public class AMD64StringIndexOfNode extends FixedWithNextNode implements LIRLowerable, MemoryAccess { - public static final NodeClass TYPE = NodeClass.create(AMD64StringIndexOfNode.class); - - @OptionalInput(InputType.Memory) protected MemoryNode lastLocationAccess; - - @Input protected NodeInputList arguments; - - 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}); - } - - @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); - } - - @Override - public MemoryNode getLastLocationAccess() { - return lastLocationAccess; - } - - @Override - public void setLastLocationAccess(MemoryNode lla) { - 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.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 --- /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 --- 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 @@ 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 @@ 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 --- 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.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 @@ 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 @@ } 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 @@ 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 --- /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 --- 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.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 @@ 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 @@ @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 --- /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/UnsafeReplacementsTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/UnsafeReplacementsTest.java +++ /dev/null @@ -1,824 +0,0 @@ -/* - * 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; - -import jdk.vm.ci.aarch64.AArch64; -import jdk.vm.ci.amd64.AMD64; -import jdk.vm.ci.code.TargetDescription; -import org.graalvm.compiler.api.test.Graal; -import org.graalvm.compiler.core.phases.HighTier; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; -import org.graalvm.compiler.runtime.RuntimeProvider; -import org.graalvm.compiler.test.AddExports; -import org.junit.Test; - -import java.lang.reflect.Field; - -@AddExports("java.base/jdk.internal.misc") -public class UnsafeReplacementsTest extends MethodSubstitutionTest { - - static class Container { - public volatile boolean booleanField; - public volatile byte byteField = 17; - public volatile char charField = 1025; - public volatile short shortField = 2232; - public volatile int intField = 0xcafebabe; - 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(); - static Container dummyValue = new Container(); - static Container newDummyValue = new Container(); - static long booleanOffset; - static long byteOffset; - static long charOffset; - static long shortOffset; - static long intOffset; - static long longOffset; - static long floatOffset; - static long doubleOffset; - static long objectOffset; - - static { - try { - booleanOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("booleanField")); - byteOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("byteField")); - charOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("charField")); - shortOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("shortField")); - intOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("intField")); - 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); - } - } - - public static boolean unsafeCompareAndSetBoolean() { - Container container = new Container(); - return unsafe.compareAndSetBoolean(container, booleanOffset, false, true); - } - - public static boolean unsafeCompareAndSetByte() { - Container container = new Container(); - return unsafe.compareAndSetByte(container, byteOffset, (byte) 17, (byte) 121); - } - - public static boolean unsafeCompareAndSetChar() { - Container container = new Container(); - return unsafe.compareAndSetChar(container, charOffset, (char) 1025, (char) 1777); - } - - public static boolean unsafeCompareAndSetShort() { - Container container = new Container(); - return unsafe.compareAndSetShort(container, shortOffset, (short) 2232, (short) 12111); - } - - public static boolean unsafeCompareAndSetInt() { - Container container = new Container(); - return unsafe.compareAndSetInt(container, intOffset, 0xcafebabe, 0xbabefafa); - } - - public static boolean unsafeCompareAndSetLong() { - Container container = new Container(); - return unsafe.compareAndSetLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL); - } - - public static boolean unsafeCompareAndSetFloat() { - Container container = new Container(); - return unsafe.compareAndSetFloat(container, floatOffset, 0.125f, 0.25f); - } - - public static boolean unsafeCompareAndSetDouble() { - Container container = new Container(); - 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); - } - - public static byte unsafeCompareAndExchangeByte() { - Container container = new Container(); - return unsafe.compareAndExchangeByte(container, byteOffset, (byte) 17, (byte) 31); - } - - public static char unsafeCompareAndExchangeChar() { - Container container = new Container(); - return unsafe.compareAndExchangeChar(container, charOffset, (char) 1025, (char) 4502); - } - - public static short unsafeCompareAndExchangeShort() { - Container container = new Container(); - return unsafe.compareAndExchangeShort(container, shortOffset, (short) 2232, (short) 8121); - } - - public static int unsafeCompareAndExchangeInt() { - Container container = new Container(); - return unsafe.compareAndExchangeInt(container, intOffset, 0xcafebabe, 0xbabefafa); - } - - public static long unsafeCompareAndExchangeLong() { - Container container = new Container(); - return unsafe.compareAndExchangeLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL); - } - - public static float unsafeCompareAndExchangeFloat() { - Container container = new Container(); - return unsafe.compareAndExchangeFloat(container, floatOffset, 0.125f, 0.25f); - } - - public static double unsafeCompareAndExchangeDouble() { - Container container = new Container(); - 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(); - if (target.arch instanceof AMD64) { - testGraph("unsafeCompareAndSetBoolean"); - testGraph("unsafeCompareAndSetByte"); - testGraph("unsafeCompareAndSetChar"); - testGraph("unsafeCompareAndSetShort"); - testGraph("unsafeCompareAndSetInt"); - testGraph("unsafeCompareAndSetLong"); - testGraph("unsafeCompareAndSetFloat"); - testGraph("unsafeCompareAndSetDouble"); - testGraph("unsafeCompareAndSetReference"); - testGraph("unsafeCompareAndExchangeBoolean"); - testGraph("unsafeCompareAndExchangeByte"); - testGraph("unsafeCompareAndExchangeChar"); - testGraph("unsafeCompareAndExchangeShort"); - testGraph("unsafeCompareAndExchangeInt"); - testGraph("unsafeCompareAndExchangeLong"); - testGraph("unsafeCompareAndExchangeFloat"); - testGraph("unsafeCompareAndExchangeDouble"); - testGraph("unsafeCompareAndExchangeReference"); - } - test("unsafeCompareAndSetBoolean"); - test("unsafeCompareAndSetByte"); - test("unsafeCompareAndSetChar"); - test("unsafeCompareAndSetShort"); - test("unsafeCompareAndSetInt"); - test("unsafeCompareAndSetLong"); - test("unsafeCompareAndSetFloat"); - test("unsafeCompareAndSetDouble"); - test("unsafeCompareAndSetReference"); - test("unsafeCompareAndExchangeBoolean"); - test("unsafeCompareAndExchangeByte"); - test("unsafeCompareAndExchangeChar"); - test("unsafeCompareAndExchangeShort"); - test("unsafeCompareAndExchangeInt"); - test("unsafeCompareAndExchangeLong"); - test("unsafeCompareAndExchangeFloat"); - test("unsafeCompareAndExchangeDouble"); - test("unsafeCompareAndExchangeReference"); - } - - public static int unsafeGetAndAddByte() { - Container container = new Container(); - return unsafe.getAndAddByte(container, byteOffset, (byte) 2); - } - - public static int unsafeGetAndAddChar() { - Container container = new Container(); - return unsafe.getAndAddChar(container, charOffset, (char) 250); - } - - public static int unsafeGetAndAddShort() { - Container container = new Container(); - return unsafe.getAndAddShort(container, shortOffset, (short) 1250); - } - - public static int unsafeGetAndAddInt() { - Container container = new Container(); - return unsafe.getAndAddInt(container, intOffset, 104501); - } - - public static long unsafeGetAndAddLong() { - Container container = new Container(); - return unsafe.getAndAddLong(container, longOffset, 0x123456abcdL); - } - - @Test - public void testGetAndAdd() { - TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); - if (target.arch instanceof AMD64) { - testGraph("unsafeGetAndAddByte"); - testGraph("unsafeGetAndAddChar"); - testGraph("unsafeGetAndAddShort"); - } - if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { - testGraph("unsafeGetAndAddInt"); - testGraph("unsafeGetAndAddLong"); - } - test("unsafeGetAndAddByte"); - test("unsafeGetAndAddChar"); - test("unsafeGetAndAddShort"); - test("unsafeGetAndAddInt"); - test("unsafeGetAndAddLong"); - } - - public static boolean unsafeGetAndSetBoolean() { - Container container = new Container(); - return unsafe.getAndSetBoolean(container, booleanOffset, true); - } - - public static byte unsafeGetAndSetByte() { - Container container = new Container(); - return unsafe.getAndSetByte(container, byteOffset, (byte) 129); - } - - public static char unsafeGetAndSetChar() { - Container container = new Container(); - return unsafe.getAndSetChar(container, charOffset, (char) 21111); - } - - public static short unsafeGetAndSetShort() { - Container container = new Container(); - return unsafe.getAndSetShort(container, shortOffset, (short) 21111); - } - - public static int unsafeGetAndSetInt() { - Container container = new Container(); - return unsafe.getAndSetInt(container, intOffset, 0x1234af); - } - - public static long unsafeGetAndSetLong() { - Container container = new Container(); - 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(); - if (target.arch instanceof AMD64) { - testGraph("unsafeGetAndSetBoolean"); - testGraph("unsafeGetAndSetByte"); - testGraph("unsafeGetAndSetChar"); - testGraph("unsafeGetAndSetShort"); - } - if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { - testGraph("unsafeGetAndSetInt"); - testGraph("unsafeGetAndSetLong"); - testGraph("unsafeGetAndSetReference"); - } - test("unsafeGetAndSetBoolean"); - test("unsafeGetAndSetByte"); - test("unsafeGetAndSetChar"); - test("unsafeGetAndSetShort"); - test("unsafeGetAndSetInt"); - test("unsafeGetAndSetLong"); - test("unsafeGetAndSetReference"); - } - - public static void fieldInstance() { - JdkInternalMiscUnsafeAccessTestBoolean.testFieldInstance(); - } - - @Test - public void testFieldInstance() { - test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "fieldInstance"); - } - - public static void array() { - JdkInternalMiscUnsafeAccessTestBoolean.testArray(); - } - - @Test - public void testArray() { - test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "array"); - } - - public static void fieldStatic() { - JdkInternalMiscUnsafeAccessTestBoolean.testFieldStatic(); - } - - @Test - public void testFieldStatic() { - test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "fieldStatic"); - } - - public static void assertEquals(Object seen, Object expected, String message) { - if (seen != expected) { - throw new AssertionError(message + " - seen: " + seen + ", expected: " + expected); - } - } - - public static class JdkInternalMiscUnsafeAccessTestBoolean { - static final int ITERATIONS = 100000; - - static final int WEAK_ATTEMPTS = 10; - - static final long V_OFFSET; - - static final Object STATIC_V_BASE; - - static final long STATIC_V_OFFSET; - - static final int ARRAY_OFFSET; - - static final int ARRAY_SHIFT; - - static { - try { - Field staticVField = UnsafeReplacementsTest.JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("staticV"); - STATIC_V_BASE = unsafe.staticFieldBase(staticVField); - STATIC_V_OFFSET = unsafe.staticFieldOffset(staticVField); - } catch (Exception e) { - throw new RuntimeException(e); - } - - try { - Field vField = UnsafeReplacementsTest.JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); - V_OFFSET = unsafe.objectFieldOffset(vField); - } catch (Exception e) { - throw new RuntimeException(e); - } - - ARRAY_OFFSET = unsafe.arrayBaseOffset(boolean[].class); - int ascale = unsafe.arrayIndexScale(boolean[].class); - ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); - } - - static boolean staticV; - - boolean v; - - @BytecodeParserForceInline - public static void testFieldInstance() { - JdkInternalMiscUnsafeAccessTestBoolean t = new JdkInternalMiscUnsafeAccessTestBoolean(); - for (int c = 0; c < ITERATIONS; c++) { - testAccess(t, V_OFFSET); - } - } - - public static void testFieldStatic() { - for (int c = 0; c < ITERATIONS; c++) { - testAccess(STATIC_V_BASE, STATIC_V_OFFSET); - } - } - - public static void testArray() { - boolean[] array = new boolean[10]; - for (int c = 0; c < ITERATIONS; c++) { - for (int i = 0; i < array.length; i++) { - testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); - } - } - } - - // Checkstyle: stop - @BytecodeParserForceInline - public static void testAccess(Object base, long offset) { - // Advanced compare - { - boolean r = unsafe.compareAndExchangeBoolean(base, offset, false, true); - assertEquals(r, false, "success compareAndExchange boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "success compareAndExchange boolean value"); - } - - { - boolean r = unsafe.compareAndExchangeBoolean(base, offset, false, false); - assertEquals(r, true, "failing compareAndExchange boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "failing compareAndExchange boolean value"); - } - - { - boolean r = unsafe.compareAndExchangeBooleanAcquire(base, offset, true, false); - assertEquals(r, true, "success compareAndExchangeAcquire boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); - } - - { - boolean r = unsafe.compareAndExchangeBooleanAcquire(base, offset, true, false); - assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); - } - - { - boolean r = unsafe.compareAndExchangeBooleanRelease(base, offset, false, true); - assertEquals(r, false, "success compareAndExchangeRelease boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "success compareAndExchangeRelease boolean value"); - } - - { - boolean r = unsafe.compareAndExchangeBooleanRelease(base, offset, false, false); - assertEquals(r, true, "failing compareAndExchangeRelease boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); - } - - { - boolean success = false; - for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = unsafe.weakCompareAndSetBooleanPlain(base, offset, true, false); - } - assertEquals(success, true, "weakCompareAndSetPlain boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, false, "weakCompareAndSetPlain boolean value"); - } - - { - boolean success = false; - for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = unsafe.weakCompareAndSetBooleanAcquire(base, offset, false, true); - } - assertEquals(success, true, "weakCompareAndSetAcquire boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "weakCompareAndSetAcquire boolean"); - } - - { - boolean success = false; - for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = unsafe.weakCompareAndSetBooleanRelease(base, offset, true, false); - } - assertEquals(success, true, "weakCompareAndSetRelease boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, false, "weakCompareAndSetRelease boolean"); - } - - { - boolean success = false; - for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = unsafe.weakCompareAndSetBoolean(base, offset, false, true); - } - assertEquals(success, true, "weakCompareAndSet boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "weakCompareAndSet boolean"); - } - - unsafe.putBoolean(base, offset, false); - - // Compare set and get - { - boolean o = unsafe.getAndSetBoolean(base, offset, true); - assertEquals(o, false, "getAndSet boolean"); - boolean x = unsafe.getBoolean(base, offset); - assertEquals(x, true, "getAndSet boolean value"); - } - - } - // Checkstyle: resume - } - - public static boolean unsafeGetPutBoolean() { - Container container = new Container(); - unsafe.putBoolean(container, booleanOffset, true); - return unsafe.getBoolean(container, booleanOffset); - } - - public static byte unsafeGetPutByte() { - Container container = new Container(); - unsafe.putByte(container, byteOffset, (byte) 0x12); - return unsafe.getByte(container, byteOffset); - } - - public static short unsafeGetPutShort() { - Container container = new Container(); - unsafe.putShort(container, shortOffset, (short) 0x1234); - return unsafe.getShort(container, shortOffset); - } - - public static char unsafeGetPutChar() { - Container container = new Container(); - unsafe.putChar(container, charOffset, 'x'); - return unsafe.getChar(container, charOffset); - } - - public static int unsafeGetPutInt() { - Container container = new Container(); - unsafe.putInt(container, intOffset, 0x01234567); - return unsafe.getInt(container, intOffset); - } - - public static long unsafeGetPutLong() { - Container container = new Container(); - unsafe.putLong(container, longOffset, 0x01234567890ABCDEFL); - return unsafe.getLong(container, longOffset); - } - - public static float unsafeGetPutFloat() { - Container container = new Container(); - unsafe.putFloat(container, floatOffset, 1.234F); - return unsafe.getFloat(container, floatOffset); - } - - public static double unsafeGetPutDouble() { - Container container = new Container(); - unsafe.putDouble(container, doubleOffset, 1.23456789); - 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); - return unsafe.getBooleanOpaque(container, booleanOffset); - } - - public static byte unsafeGetPutByteOpaque() { - Container container = new Container(); - unsafe.putByteOpaque(container, byteOffset, (byte) 0x12); - return unsafe.getByteOpaque(container, byteOffset); - } - - public static short unsafeGetPutShortOpaque() { - Container container = new Container(); - unsafe.putShortOpaque(container, shortOffset, (short) 0x1234); - return unsafe.getShortOpaque(container, shortOffset); - } - - public static char unsafeGetPutCharOpaque() { - Container container = new Container(); - unsafe.putCharOpaque(container, charOffset, 'x'); - return unsafe.getCharOpaque(container, charOffset); - } - - public static int unsafeGetPutIntOpaque() { - Container container = new Container(); - unsafe.putIntOpaque(container, intOffset, 0x01234567); - return unsafe.getIntOpaque(container, intOffset); - } - - public static long unsafeGetPutLongOpaque() { - Container container = new Container(); - unsafe.putLongOpaque(container, longOffset, 0x01234567890ABCDEFL); - return unsafe.getLongOpaque(container, longOffset); - } - - public static float unsafeGetPutFloatOpaque() { - Container container = new Container(); - unsafe.putFloatOpaque(container, floatOffset, 1.234F); - return unsafe.getFloatOpaque(container, floatOffset); - } - - public static double unsafeGetPutDoubleOpaque() { - Container container = new Container(); - unsafe.putDoubleOpaque(container, doubleOffset, 1.23456789); - 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); - return unsafe.getBooleanAcquire(container, booleanOffset); - } - - public static byte unsafeGetPutByteRA() { - Container container = new Container(); - unsafe.putByteRelease(container, byteOffset, (byte) 0x12); - return unsafe.getByteAcquire(container, byteOffset); - } - - public static short unsafeGetPutShortRA() { - Container container = new Container(); - unsafe.putShortRelease(container, shortOffset, (short) 0x1234); - return unsafe.getShortAcquire(container, shortOffset); - } - - public static char unsafeGetPutCharRA() { - Container container = new Container(); - unsafe.putCharRelease(container, charOffset, 'x'); - return unsafe.getCharAcquire(container, charOffset); - } - - public static int unsafeGetPutIntRA() { - Container container = new Container(); - unsafe.putIntRelease(container, intOffset, 0x01234567); - return unsafe.getIntAcquire(container, intOffset); - } - - public static long unsafeGetPutLongRA() { - Container container = new Container(); - unsafe.putLongRelease(container, longOffset, 0x01234567890ABCDEFL); - return unsafe.getLongAcquire(container, longOffset); - } - - public static float unsafeGetPutFloatRA() { - Container container = new Container(); - unsafe.putFloatRelease(container, floatOffset, 1.234F); - return unsafe.getFloatAcquire(container, floatOffset); - } - - public static double unsafeGetPutDoubleRA() { - Container container = new Container(); - unsafe.putDoubleRelease(container, doubleOffset, 1.23456789); - 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); - return unsafe.getBooleanVolatile(container, booleanOffset); - } - - public static byte unsafeGetPutByteVolatile() { - Container container = new Container(); - unsafe.putByteVolatile(container, byteOffset, (byte) 0x12); - return unsafe.getByteVolatile(container, byteOffset); - } - - public static short unsafeGetPutShortVolatile() { - Container container = new Container(); - unsafe.putShortVolatile(container, shortOffset, (short) 0x1234); - return unsafe.getShortVolatile(container, shortOffset); - } - - public static char unsafeGetPutCharVolatile() { - Container container = new Container(); - unsafe.putCharVolatile(container, charOffset, 'x'); - return unsafe.getCharVolatile(container, charOffset); - } - - public static int unsafeGetPutIntVolatile() { - Container container = new Container(); - unsafe.putIntVolatile(container, intOffset, 0x01234567); - return unsafe.getIntVolatile(container, intOffset); - } - - public static long unsafeGetPutLongVolatile() { - Container container = new Container(); - unsafe.putLongVolatile(container, longOffset, 0x01234567890ABCDEFL); - return unsafe.getLongVolatile(container, longOffset); - } - - public static float unsafeGetPutFloatVolatile() { - Container container = new Container(); - unsafe.putFloatVolatile(container, floatOffset, 1.234F); - return unsafe.getFloatVolatile(container, floatOffset); - } - - public static double unsafeGetPutDoubleVolatile() { - Container container = new Container(); - unsafe.putDoubleVolatile(container, doubleOffset, 1.23456789); - 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"); - testGraph("unsafeGetPutByte"); - testGraph("unsafeGetPutShort"); - testGraph("unsafeGetPutChar"); - testGraph("unsafeGetPutInt"); - testGraph("unsafeGetPutLong"); - testGraph("unsafeGetPutFloat"); - testGraph("unsafeGetPutDouble"); - testGraph("unsafeGetPutObject"); - - test("unsafeGetPutBoolean"); - test("unsafeGetPutByte"); - test("unsafeGetPutShort"); - test("unsafeGetPutChar"); - test("unsafeGetPutInt"); - test("unsafeGetPutLong"); - test("unsafeGetPutFloat"); - test("unsafeGetPutDouble"); - test("unsafeGetPutObject"); - } - - @Test - public void testUnsafeGetPutOpaque() { - testGraph("unsafeGetPutBooleanOpaque"); - testGraph("unsafeGetPutByteOpaque"); - testGraph("unsafeGetPutShortOpaque"); - testGraph("unsafeGetPutCharOpaque"); - testGraph("unsafeGetPutIntOpaque"); - testGraph("unsafeGetPutLongOpaque"); - testGraph("unsafeGetPutFloatOpaque"); - testGraph("unsafeGetPutDoubleOpaque"); - testGraph("unsafeGetPutObjectOpaque"); - - test("unsafeGetPutBooleanOpaque"); - test("unsafeGetPutByteOpaque"); - test("unsafeGetPutShortOpaque"); - test("unsafeGetPutCharOpaque"); - test("unsafeGetPutIntOpaque"); - test("unsafeGetPutLongOpaque"); - test("unsafeGetPutFloatOpaque"); - test("unsafeGetPutDoubleOpaque"); - test("unsafeGetPutObjectOpaque"); - } - - @Test - public void testUnsafeGetPutReleaseAcquire() { - testGraph("unsafeGetPutBooleanRA"); - testGraph("unsafeGetPutByteRA"); - testGraph("unsafeGetPutShortRA"); - testGraph("unsafeGetPutCharRA"); - testGraph("unsafeGetPutIntRA"); - testGraph("unsafeGetPutLongRA"); - testGraph("unsafeGetPutFloatRA"); - testGraph("unsafeGetPutDoubleRA"); - testGraph("unsafeGetPutReferenceRA"); - - test("unsafeGetPutBooleanRA"); - test("unsafeGetPutByteRA"); - test("unsafeGetPutShortRA"); - test("unsafeGetPutCharRA"); - test("unsafeGetPutIntRA"); - test("unsafeGetPutLongRA"); - test("unsafeGetPutFloatRA"); - test("unsafeGetPutDoubleRA"); - test("unsafeGetPutReferenceRA"); - } - - @Test - public void testUnsafeGetPutVolatile() { - testGraph("unsafeGetPutBooleanVolatile"); - testGraph("unsafeGetPutByteVolatile"); - testGraph("unsafeGetPutShortVolatile"); - testGraph("unsafeGetPutCharVolatile"); - testGraph("unsafeGetPutIntVolatile"); - testGraph("unsafeGetPutLongVolatile"); - testGraph("unsafeGetPutFloatVolatile"); - testGraph("unsafeGetPutDoubleVolatile"); - testGraph("unsafeGetPutReferenceVolatile"); - - test("unsafeGetPutBooleanVolatile"); - test("unsafeGetPutByteVolatile"); - test("unsafeGetPutShortVolatile"); - test("unsafeGetPutCharVolatile"); - test("unsafeGetPutIntVolatile"); - 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/VarHandleTest.java deleted file mode 100644 --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/VarHandleTest.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 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; - -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; - -import org.graalvm.compiler.core.test.GraalCompilerTest; -import org.graalvm.compiler.debug.GraalError; -import org.graalvm.compiler.graph.Node; -import org.graalvm.compiler.nodes.StartNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.extended.MembarNode; -import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; -import org.graalvm.compiler.nodes.memory.ReadNode; -import org.graalvm.compiler.nodes.memory.WriteNode; -import jdk.internal.vm.compiler.word.LocationIdentity; -import org.junit.Assert; -import org.junit.Test; - -import jdk.vm.ci.meta.ResolvedJavaMethod; - -public class VarHandleTest extends GraalCompilerTest { - - static class Holder { - /* Field is declared volatile, but accessed with non-volatile semantics in the tests. */ - volatile int volatileField = 42; - - /* Field is declared non-volatile, but accessed with volatile semantics in the tests. */ - int field = 2018; - - static final VarHandle VOLATILE_FIELD; - static final VarHandle FIELD; - - static { - try { - VOLATILE_FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "volatileField", int.class); - FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "field", int.class); - } catch (ReflectiveOperationException ex) { - throw GraalError.shouldNotReachHere(ex); - } - } - } - - public static int testRead1Snippet(Holder h) { - /* Explicitly access the volatile field with non-volatile access semantics. */ - return (int) Holder.VOLATILE_FIELD.get(h); - } - - public static int testRead2Snippet(Holder h) { - /* Explicitly access the volatile field with volatile access semantics. */ - return (int) Holder.VOLATILE_FIELD.getVolatile(h); - } - - public static int testRead3Snippet(Holder h) { - /* Explicitly access the non-volatile field with non-volatile access semantics. */ - return (int) Holder.FIELD.get(h); - } - - public static int testRead4Snippet(Holder h) { - /* Explicitly access the non-volatile field with volatile access semantics. */ - return (int) Holder.FIELD.getVolatile(h); - } - - public static void testWrite1Snippet(Holder h) { - /* Explicitly access the volatile field with non-volatile access semantics. */ - Holder.VOLATILE_FIELD.set(h, 123); - } - - public static void testWrite2Snippet(Holder h) { - /* Explicitly access the volatile field with volatile access semantics. */ - Holder.VOLATILE_FIELD.setVolatile(h, 123); - } - - public static void testWrite3Snippet(Holder h) { - /* Explicitly access the non-volatile field with non-volatile access semantics. */ - Holder.FIELD.set(h, 123); - } - - public static void testWrite4Snippet(Holder h) { - /* Explicitly access the non-volatile field with volatile access semantics. */ - Holder.FIELD.setVolatile(h, 123); - } - - void testAccess(String name, int expectedReads, int expectedWrites, int expectedMembars, int expectedAnyKill) { - ResolvedJavaMethod method = getResolvedJavaMethod(name); - StructuredGraph graph = parseForCompile(method); - compile(method, graph); - Assert.assertEquals(expectedReads, graph.getNodes().filter(ReadNode.class).count()); - Assert.assertEquals(expectedWrites, graph.getNodes().filter(WriteNode.class).count()); - Assert.assertEquals(expectedMembars, graph.getNodes().filter(MembarNode.class).count()); - Assert.assertEquals(expectedAnyKill, countAnyKill(graph)); - } - - @Test - public void testRead1() { - testAccess("testRead1Snippet", 1, 0, 0, 0); - } - - @Test - public void testRead2() { - testAccess("testRead2Snippet", 1, 0, 2, 2); - } - - @Test - public void testRead3() { - testAccess("testRead3Snippet", 1, 0, 0, 0); - } - - @Test - public void testRead4() { - testAccess("testRead4Snippet", 1, 0, 2, 2); - } - - @Test - public void testWrite1() { - testAccess("testWrite1Snippet", 0, 1, 0, 0); - } - - @Test - public void testWrite2() { - testAccess("testWrite2Snippet", 0, 1, 2, 2); - } - - @Test - public void testWrite3() { - testAccess("testWrite3Snippet", 0, 1, 0, 0); - } - - @Test - public void testWrite4() { - testAccess("testWrite4Snippet", 0, 1, 2, 2); - } - - private static int countAnyKill(StructuredGraph graph) { - int anyKillCount = 0; - int startNodes = 0; - for (Node n : graph.getNodes()) { - if (n instanceof StartNode) { - startNodes++; - } else if (n instanceof MemoryCheckpoint.Single) { - MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n; - if (single.getLocationIdentity().isAny()) { - anyKillCount++; - } - } else if (n instanceof MemoryCheckpoint.Multi) { - MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n; - for (LocationIdentity loc : multi.getLocationIdentities()) { - if (loc.isAny()) { - anyKillCount++; - break; - } - } - } - } - // Ignore single StartNode. - Assert.assertEquals(1, startNodes); - return anyKillCount; - } -} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/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 new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/UnsafeReplacementsTest.java @@ -0,0 +1,766 @@ +/* + * 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.test; + +import jdk.vm.ci.aarch64.AArch64; +import jdk.vm.ci.amd64.AMD64; +import jdk.vm.ci.code.TargetDescription; +import org.graalvm.compiler.api.test.Graal; +import org.graalvm.compiler.core.phases.HighTier; +import org.graalvm.compiler.options.OptionValues; +import org.graalvm.compiler.replacements.test.MethodSubstitutionTest; +import org.graalvm.compiler.runtime.RuntimeProvider; +import org.graalvm.compiler.test.AddExports; +import org.junit.Test; + +import java.lang.reflect.Field; + +@AddExports("java.base/jdk.internal.misc") +public class UnsafeReplacementsTest extends MethodSubstitutionTest { + + static class Container { + public volatile boolean booleanField; + public volatile byte byteField = 17; + public volatile char charField = 1025; + public volatile short shortField = 2232; + public volatile int intField = 0xcafebabe; + public volatile long longField = 0xdedababafafaL; + public volatile float floatField = 0.125f; + public volatile double doubleField = 0.125; + } + + static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); + static Container dummyValue = new Container(); + static Container newDummyValue = new Container(); + static long booleanOffset; + static long byteOffset; + static long charOffset; + static long shortOffset; + static long intOffset; + static long longOffset; + static long floatOffset; + static long doubleOffset; + + static { + try { + booleanOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("booleanField")); + byteOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("byteField")); + charOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("charField")); + shortOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("shortField")); + intOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("intField")); + longOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("longField")); + floatOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("floatField")); + doubleOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("doubleField")); + } catch (NoSuchFieldException e) { + throw new RuntimeException(e); + } + } + + public static boolean unsafeCompareAndSetBoolean() { + Container container = new Container(); + return unsafe.compareAndSetBoolean(container, booleanOffset, false, true); + } + + public static boolean unsafeCompareAndSetByte() { + Container container = new Container(); + return unsafe.compareAndSetByte(container, byteOffset, (byte) 17, (byte) 121); + } + + public static boolean unsafeCompareAndSetChar() { + Container container = new Container(); + return unsafe.compareAndSetChar(container, charOffset, (char) 1025, (char) 1777); + } + + public static boolean unsafeCompareAndSetShort() { + Container container = new Container(); + return unsafe.compareAndSetShort(container, shortOffset, (short) 2232, (short) 12111); + } + + public static boolean unsafeCompareAndSetInt() { + Container container = new Container(); + return unsafe.compareAndSetInt(container, intOffset, 0xcafebabe, 0xbabefafa); + } + + public static boolean unsafeCompareAndSetLong() { + Container container = new Container(); + return unsafe.compareAndSetLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL); + } + + public static boolean unsafeCompareAndSetFloat() { + Container container = new Container(); + return unsafe.compareAndSetFloat(container, floatOffset, 0.125f, 0.25f); + } + + public static boolean unsafeCompareAndSetDouble() { + Container container = new Container(); + return unsafe.compareAndSetDouble(container, doubleOffset, 0.125, 0.25); + } + + public static boolean unsafeCompareAndExchangeBoolean() { + Container container = new Container(); + return unsafe.compareAndExchangeBoolean(container, booleanOffset, false, true); + } + + public static byte unsafeCompareAndExchangeByte() { + Container container = new Container(); + return unsafe.compareAndExchangeByte(container, byteOffset, (byte) 17, (byte) 31); + } + + public static char unsafeCompareAndExchangeChar() { + Container container = new Container(); + return unsafe.compareAndExchangeChar(container, charOffset, (char) 1025, (char) 4502); + } + + public static short unsafeCompareAndExchangeShort() { + Container container = new Container(); + return unsafe.compareAndExchangeShort(container, shortOffset, (short) 2232, (short) 8121); + } + + public static int unsafeCompareAndExchangeInt() { + Container container = new Container(); + return unsafe.compareAndExchangeInt(container, intOffset, 0xcafebabe, 0xbabefafa); + } + + public static long unsafeCompareAndExchangeLong() { + Container container = new Container(); + return unsafe.compareAndExchangeLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL); + } + + public static float unsafeCompareAndExchangeFloat() { + Container container = new Container(); + return unsafe.compareAndExchangeFloat(container, floatOffset, 0.125f, 0.25f); + } + + public static double unsafeCompareAndExchangeDouble() { + Container container = new Container(); + return unsafe.compareAndExchangeDouble(container, doubleOffset, 0.125, 0.25); + } + + @Test + public void testCompareAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64) { + testGraph("unsafeCompareAndSetBoolean"); + testGraph("unsafeCompareAndSetByte"); + testGraph("unsafeCompareAndSetChar"); + testGraph("unsafeCompareAndSetShort"); + testGraph("unsafeCompareAndSetInt"); + testGraph("unsafeCompareAndSetLong"); + testGraph("unsafeCompareAndSetFloat"); + testGraph("unsafeCompareAndSetDouble"); + testGraph("unsafeCompareAndExchangeBoolean"); + testGraph("unsafeCompareAndExchangeByte"); + testGraph("unsafeCompareAndExchangeChar"); + testGraph("unsafeCompareAndExchangeShort"); + testGraph("unsafeCompareAndExchangeInt"); + testGraph("unsafeCompareAndExchangeLong"); + testGraph("unsafeCompareAndExchangeFloat"); + testGraph("unsafeCompareAndExchangeDouble"); + } + test("unsafeCompareAndSetBoolean"); + test("unsafeCompareAndSetByte"); + test("unsafeCompareAndSetChar"); + test("unsafeCompareAndSetShort"); + test("unsafeCompareAndSetInt"); + test("unsafeCompareAndSetLong"); + test("unsafeCompareAndSetFloat"); + test("unsafeCompareAndSetDouble"); + test("unsafeCompareAndExchangeBoolean"); + test("unsafeCompareAndExchangeByte"); + test("unsafeCompareAndExchangeChar"); + test("unsafeCompareAndExchangeShort"); + test("unsafeCompareAndExchangeInt"); + test("unsafeCompareAndExchangeLong"); + test("unsafeCompareAndExchangeFloat"); + test("unsafeCompareAndExchangeDouble"); + } + + public static int unsafeGetAndAddByte() { + Container container = new Container(); + return unsafe.getAndAddByte(container, byteOffset, (byte) 2); + } + + public static int unsafeGetAndAddChar() { + Container container = new Container(); + return unsafe.getAndAddChar(container, charOffset, (char) 250); + } + + public static int unsafeGetAndAddShort() { + Container container = new Container(); + return unsafe.getAndAddShort(container, shortOffset, (short) 1250); + } + + public static int unsafeGetAndAddInt() { + Container container = new Container(); + return unsafe.getAndAddInt(container, intOffset, 104501); + } + + public static long unsafeGetAndAddLong() { + Container container = new Container(); + return unsafe.getAndAddLong(container, longOffset, 0x123456abcdL); + } + + @Test + public void testGetAndAdd() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64) { + testGraph("unsafeGetAndAddByte"); + testGraph("unsafeGetAndAddChar"); + testGraph("unsafeGetAndAddShort"); + } + if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { + testGraph("unsafeGetAndAddInt"); + testGraph("unsafeGetAndAddLong"); + } + test("unsafeGetAndAddByte"); + test("unsafeGetAndAddChar"); + test("unsafeGetAndAddShort"); + test("unsafeGetAndAddInt"); + test("unsafeGetAndAddLong"); + } + + public static boolean unsafeGetAndSetBoolean() { + Container container = new Container(); + return unsafe.getAndSetBoolean(container, booleanOffset, true); + } + + public static byte unsafeGetAndSetByte() { + Container container = new Container(); + return unsafe.getAndSetByte(container, byteOffset, (byte) 129); + } + + public static char unsafeGetAndSetChar() { + Container container = new Container(); + return unsafe.getAndSetChar(container, charOffset, (char) 21111); + } + + public static short unsafeGetAndSetShort() { + Container container = new Container(); + return unsafe.getAndSetShort(container, shortOffset, (short) 21111); + } + + public static int unsafeGetAndSetInt() { + Container container = new Container(); + return unsafe.getAndSetInt(container, intOffset, 0x1234af); + } + + public static long unsafeGetAndSetLong() { + Container container = new Container(); + return unsafe.getAndSetLong(container, longOffset, 0x12345678abL); + } + + @Test + public void testGetAndSet() { + TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget(); + if (target.arch instanceof AMD64) { + testGraph("unsafeGetAndSetBoolean"); + testGraph("unsafeGetAndSetByte"); + testGraph("unsafeGetAndSetChar"); + testGraph("unsafeGetAndSetShort"); + } + if (target.arch instanceof AMD64 || target.arch instanceof AArch64) { + testGraph("unsafeGetAndSetInt"); + testGraph("unsafeGetAndSetLong"); + } + test("unsafeGetAndSetBoolean"); + test("unsafeGetAndSetByte"); + test("unsafeGetAndSetChar"); + test("unsafeGetAndSetShort"); + test("unsafeGetAndSetInt"); + test("unsafeGetAndSetLong"); + } + + public static void fieldInstance() { + JdkInternalMiscUnsafeAccessTestBoolean.testFieldInstance(); + } + + @Test + public void testFieldInstance() { + test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "fieldInstance"); + } + + public static void array() { + JdkInternalMiscUnsafeAccessTestBoolean.testArray(); + } + + @Test + public void testArray() { + test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "array"); + } + + public static void fieldStatic() { + JdkInternalMiscUnsafeAccessTestBoolean.testFieldStatic(); + } + + @Test + public void testFieldStatic() { + test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "fieldStatic"); + } + + public static void assertEquals(Object seen, Object expected, String message) { + if (seen != expected) { + throw new AssertionError(message + " - seen: " + seen + ", expected: " + expected); + } + } + + public static class JdkInternalMiscUnsafeAccessTestBoolean { + static final int ITERATIONS = 100000; + + static final int WEAK_ATTEMPTS = 10; + + static final long V_OFFSET; + + static final Object STATIC_V_BASE; + + static final long STATIC_V_OFFSET; + + static final int ARRAY_OFFSET; + + static final int ARRAY_SHIFT; + + static { + try { + Field staticVField = UnsafeReplacementsTest.JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("staticV"); + STATIC_V_BASE = unsafe.staticFieldBase(staticVField); + STATIC_V_OFFSET = unsafe.staticFieldOffset(staticVField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + try { + Field vField = UnsafeReplacementsTest.JdkInternalMiscUnsafeAccessTestBoolean.class.getDeclaredField("v"); + V_OFFSET = unsafe.objectFieldOffset(vField); + } catch (Exception e) { + throw new RuntimeException(e); + } + + ARRAY_OFFSET = unsafe.arrayBaseOffset(boolean[].class); + int ascale = unsafe.arrayIndexScale(boolean[].class); + ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); + } + + static boolean staticV; + + boolean v; + + @BytecodeParserForceInline + public static void testFieldInstance() { + JdkInternalMiscUnsafeAccessTestBoolean t = new JdkInternalMiscUnsafeAccessTestBoolean(); + for (int c = 0; c < ITERATIONS; c++) { + testAccess(t, V_OFFSET); + } + } + + public static void testFieldStatic() { + for (int c = 0; c < ITERATIONS; c++) { + testAccess(STATIC_V_BASE, STATIC_V_OFFSET); + } + } + + public static void testArray() { + boolean[] array = new boolean[10]; + for (int c = 0; c < ITERATIONS; c++) { + for (int i = 0; i < array.length; i++) { + testAccess(array, (((long) i) << ARRAY_SHIFT) + ARRAY_OFFSET); + } + } + } + + // Checkstyle: stop + @BytecodeParserForceInline + public static void testAccess(Object base, long offset) { + // Advanced compare + { + boolean r = unsafe.compareAndExchangeBoolean(base, offset, false, true); + assertEquals(r, false, "success compareAndExchange boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "success compareAndExchange boolean value"); + } + + { + boolean r = unsafe.compareAndExchangeBoolean(base, offset, false, false); + assertEquals(r, true, "failing compareAndExchange boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "failing compareAndExchange boolean value"); + } + + { + boolean r = unsafe.compareAndExchangeBooleanAcquire(base, offset, true, false); + assertEquals(r, true, "success compareAndExchangeAcquire boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, false, "success compareAndExchangeAcquire boolean value"); + } + + { + boolean r = unsafe.compareAndExchangeBooleanAcquire(base, offset, true, false); + assertEquals(r, false, "failing compareAndExchangeAcquire boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, false, "failing compareAndExchangeAcquire boolean value"); + } + + { + boolean r = unsafe.compareAndExchangeBooleanRelease(base, offset, false, true); + assertEquals(r, false, "success compareAndExchangeRelease boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "success compareAndExchangeRelease boolean value"); + } + + { + boolean r = unsafe.compareAndExchangeBooleanRelease(base, offset, false, false); + assertEquals(r, true, "failing compareAndExchangeRelease boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "failing compareAndExchangeRelease boolean value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = unsafe.weakCompareAndSetBooleanPlain(base, offset, true, false); + } + assertEquals(success, true, "weakCompareAndSetPlain boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, false, "weakCompareAndSetPlain boolean value"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = unsafe.weakCompareAndSetBooleanAcquire(base, offset, false, true); + } + assertEquals(success, true, "weakCompareAndSetAcquire boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "weakCompareAndSetAcquire boolean"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = unsafe.weakCompareAndSetBooleanRelease(base, offset, true, false); + } + assertEquals(success, true, "weakCompareAndSetRelease boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, false, "weakCompareAndSetRelease boolean"); + } + + { + boolean success = false; + for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { + success = unsafe.weakCompareAndSetBoolean(base, offset, false, true); + } + assertEquals(success, true, "weakCompareAndSet boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "weakCompareAndSet boolean"); + } + + unsafe.putBoolean(base, offset, false); + + // Compare set and get + { + boolean o = unsafe.getAndSetBoolean(base, offset, true); + assertEquals(o, false, "getAndSet boolean"); + boolean x = unsafe.getBoolean(base, offset); + assertEquals(x, true, "getAndSet boolean value"); + } + + } + // Checkstyle: resume + } + + public static boolean unsafeGetPutBoolean() { + Container container = new Container(); + unsafe.putBoolean(container, booleanOffset, true); + return unsafe.getBoolean(container, booleanOffset); + } + + public static byte unsafeGetPutByte() { + Container container = new Container(); + unsafe.putByte(container, byteOffset, (byte) 0x12); + return unsafe.getByte(container, byteOffset); + } + + public static short unsafeGetPutShort() { + Container container = new Container(); + unsafe.putShort(container, shortOffset, (short) 0x1234); + return unsafe.getShort(container, shortOffset); + } + + public static char unsafeGetPutChar() { + Container container = new Container(); + unsafe.putChar(container, charOffset, 'x'); + return unsafe.getChar(container, charOffset); + } + + public static int unsafeGetPutInt() { + Container container = new Container(); + unsafe.putInt(container, intOffset, 0x01234567); + return unsafe.getInt(container, intOffset); + } + + public static long unsafeGetPutLong() { + Container container = new Container(); + unsafe.putLong(container, longOffset, 0x01234567890ABCDEFL); + return unsafe.getLong(container, longOffset); + } + + public static float unsafeGetPutFloat() { + Container container = new Container(); + unsafe.putFloat(container, floatOffset, 1.234F); + return unsafe.getFloat(container, floatOffset); + } + + public static double unsafeGetPutDouble() { + Container container = new Container(); + unsafe.putDouble(container, doubleOffset, 1.23456789); + return unsafe.getDouble(container, doubleOffset); + } + + public static boolean unsafeGetPutBooleanOpaque() { + Container container = new Container(); + unsafe.putBooleanOpaque(container, booleanOffset, true); + return unsafe.getBooleanOpaque(container, booleanOffset); + } + + public static byte unsafeGetPutByteOpaque() { + Container container = new Container(); + unsafe.putByteOpaque(container, byteOffset, (byte) 0x12); + return unsafe.getByteOpaque(container, byteOffset); + } + + public static short unsafeGetPutShortOpaque() { + Container container = new Container(); + unsafe.putShortOpaque(container, shortOffset, (short) 0x1234); + return unsafe.getShortOpaque(container, shortOffset); + } + + public static char unsafeGetPutCharOpaque() { + Container container = new Container(); + unsafe.putCharOpaque(container, charOffset, 'x'); + return unsafe.getCharOpaque(container, charOffset); + } + + public static int unsafeGetPutIntOpaque() { + Container container = new Container(); + unsafe.putIntOpaque(container, intOffset, 0x01234567); + return unsafe.getIntOpaque(container, intOffset); + } + + public static long unsafeGetPutLongOpaque() { + Container container = new Container(); + unsafe.putLongOpaque(container, longOffset, 0x01234567890ABCDEFL); + return unsafe.getLongOpaque(container, longOffset); + } + + public static float unsafeGetPutFloatOpaque() { + Container container = new Container(); + unsafe.putFloatOpaque(container, floatOffset, 1.234F); + return unsafe.getFloatOpaque(container, floatOffset); + } + + public static double unsafeGetPutDoubleOpaque() { + Container container = new Container(); + unsafe.putDoubleOpaque(container, doubleOffset, 1.23456789); + return unsafe.getDoubleOpaque(container, doubleOffset); + } + + public static boolean unsafeGetPutBooleanRA() { + Container container = new Container(); + unsafe.putBooleanRelease(container, booleanOffset, true); + return unsafe.getBooleanAcquire(container, booleanOffset); + } + + public static byte unsafeGetPutByteRA() { + Container container = new Container(); + unsafe.putByteRelease(container, byteOffset, (byte) 0x12); + return unsafe.getByteAcquire(container, byteOffset); + } + + public static short unsafeGetPutShortRA() { + Container container = new Container(); + unsafe.putShortRelease(container, shortOffset, (short) 0x1234); + return unsafe.getShortAcquire(container, shortOffset); + } + + public static char unsafeGetPutCharRA() { + Container container = new Container(); + unsafe.putCharRelease(container, charOffset, 'x'); + return unsafe.getCharAcquire(container, charOffset); + } + + public static int unsafeGetPutIntRA() { + Container container = new Container(); + unsafe.putIntRelease(container, intOffset, 0x01234567); + return unsafe.getIntAcquire(container, intOffset); + } + + public static long unsafeGetPutLongRA() { + Container container = new Container(); + unsafe.putLongRelease(container, longOffset, 0x01234567890ABCDEFL); + return unsafe.getLongAcquire(container, longOffset); + } + + public static float unsafeGetPutFloatRA() { + Container container = new Container(); + unsafe.putFloatRelease(container, floatOffset, 1.234F); + return unsafe.getFloatAcquire(container, floatOffset); + } + + public static double unsafeGetPutDoubleRA() { + Container container = new Container(); + unsafe.putDoubleRelease(container, doubleOffset, 1.23456789); + return unsafe.getDoubleAcquire(container, doubleOffset); + } + + public static boolean unsafeGetPutBooleanVolatile() { + Container container = new Container(); + unsafe.putBooleanVolatile(container, booleanOffset, true); + return unsafe.getBooleanVolatile(container, booleanOffset); + } + + public static byte unsafeGetPutByteVolatile() { + Container container = new Container(); + unsafe.putByteVolatile(container, byteOffset, (byte) 0x12); + return unsafe.getByteVolatile(container, byteOffset); + } + + public static short unsafeGetPutShortVolatile() { + Container container = new Container(); + unsafe.putShortVolatile(container, shortOffset, (short) 0x1234); + return unsafe.getShortVolatile(container, shortOffset); + } + + public static char unsafeGetPutCharVolatile() { + Container container = new Container(); + unsafe.putCharVolatile(container, charOffset, 'x'); + return unsafe.getCharVolatile(container, charOffset); + } + + public static int unsafeGetPutIntVolatile() { + Container container = new Container(); + unsafe.putIntVolatile(container, intOffset, 0x01234567); + return unsafe.getIntVolatile(container, intOffset); + } + + public static long unsafeGetPutLongVolatile() { + Container container = new Container(); + unsafe.putLongVolatile(container, longOffset, 0x01234567890ABCDEFL); + return unsafe.getLongVolatile(container, longOffset); + } + + public static float unsafeGetPutFloatVolatile() { + Container container = new Container(); + unsafe.putFloatVolatile(container, floatOffset, 1.234F); + return unsafe.getFloatVolatile(container, floatOffset); + } + + public static double unsafeGetPutDoubleVolatile() { + Container container = new Container(); + unsafe.putDoubleVolatile(container, doubleOffset, 1.23456789); + return unsafe.getDoubleVolatile(container, doubleOffset); + } + + @Test + public void testUnsafeGetPutPlain() { + testGraph("unsafeGetPutBoolean"); + testGraph("unsafeGetPutByte"); + testGraph("unsafeGetPutShort"); + testGraph("unsafeGetPutChar"); + testGraph("unsafeGetPutInt"); + testGraph("unsafeGetPutLong"); + testGraph("unsafeGetPutFloat"); + testGraph("unsafeGetPutDouble"); + + test("unsafeGetPutBoolean"); + test("unsafeGetPutByte"); + test("unsafeGetPutShort"); + test("unsafeGetPutChar"); + test("unsafeGetPutInt"); + test("unsafeGetPutLong"); + test("unsafeGetPutFloat"); + test("unsafeGetPutDouble"); + } + + @Test + public void testUnsafeGetPutOpaque() { + testGraph("unsafeGetPutBooleanOpaque"); + testGraph("unsafeGetPutByteOpaque"); + testGraph("unsafeGetPutShortOpaque"); + testGraph("unsafeGetPutCharOpaque"); + testGraph("unsafeGetPutIntOpaque"); + testGraph("unsafeGetPutLongOpaque"); + testGraph("unsafeGetPutFloatOpaque"); + testGraph("unsafeGetPutDoubleOpaque"); + + test("unsafeGetPutBooleanOpaque"); + test("unsafeGetPutByteOpaque"); + test("unsafeGetPutShortOpaque"); + test("unsafeGetPutCharOpaque"); + test("unsafeGetPutIntOpaque"); + test("unsafeGetPutLongOpaque"); + test("unsafeGetPutFloatOpaque"); + test("unsafeGetPutDoubleOpaque"); + } + + @Test + public void testUnsafeGetPutReleaseAcquire() { + testGraph("unsafeGetPutBooleanRA"); + testGraph("unsafeGetPutByteRA"); + testGraph("unsafeGetPutShortRA"); + testGraph("unsafeGetPutCharRA"); + testGraph("unsafeGetPutIntRA"); + testGraph("unsafeGetPutLongRA"); + testGraph("unsafeGetPutFloatRA"); + testGraph("unsafeGetPutDoubleRA"); + + test("unsafeGetPutBooleanRA"); + test("unsafeGetPutByteRA"); + test("unsafeGetPutShortRA"); + test("unsafeGetPutCharRA"); + test("unsafeGetPutIntRA"); + test("unsafeGetPutLongRA"); + test("unsafeGetPutFloatRA"); + test("unsafeGetPutDoubleRA"); + } + + @Test + public void testUnsafeGetPutVolatile() { + testGraph("unsafeGetPutBooleanVolatile"); + testGraph("unsafeGetPutByteVolatile"); + testGraph("unsafeGetPutShortVolatile"); + testGraph("unsafeGetPutCharVolatile"); + testGraph("unsafeGetPutIntVolatile"); + testGraph("unsafeGetPutLongVolatile"); + testGraph("unsafeGetPutFloatVolatile"); + testGraph("unsafeGetPutDoubleVolatile"); + + test("unsafeGetPutBooleanVolatile"); + test("unsafeGetPutByteVolatile"); + test("unsafeGetPutShortVolatile"); + test("unsafeGetPutCharVolatile"); + test("unsafeGetPutIntVolatile"); + test("unsafeGetPutLongVolatile"); + test("unsafeGetPutFloatVolatile"); + test("unsafeGetPutDoubleVolatile"); + } +} diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/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 new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/test/VarHandleTest.java @@ -0,0 +1,182 @@ +/* + * 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.test; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; + +import org.graalvm.compiler.core.test.GraalCompilerTest; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.MembarNode; +import org.graalvm.compiler.nodes.memory.MemoryCheckpoint; +import org.graalvm.compiler.nodes.memory.ReadNode; +import org.graalvm.compiler.nodes.memory.WriteNode; +import jdk.internal.vm.compiler.word.LocationIdentity; +import org.junit.Assert; +import org.junit.Test; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +public class VarHandleTest extends GraalCompilerTest { + + static class Holder { + /* Field is declared volatile, but accessed with non-volatile semantics in the tests. */ + volatile int volatileField = 42; + + /* Field is declared non-volatile, but accessed with volatile semantics in the tests. */ + int field = 2018; + + static final VarHandle VOLATILE_FIELD; + static final VarHandle FIELD; + + static { + try { + VOLATILE_FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "volatileField", int.class); + FIELD = MethodHandles.lookup().findVarHandle(Holder.class, "field", int.class); + } catch (ReflectiveOperationException ex) { + throw GraalError.shouldNotReachHere(ex); + } + } + } + + public static int testRead1Snippet(Holder h) { + /* Explicitly access the volatile field with non-volatile access semantics. */ + return (int) Holder.VOLATILE_FIELD.get(h); + } + + public static int testRead2Snippet(Holder h) { + /* Explicitly access the volatile field with volatile access semantics. */ + return (int) Holder.VOLATILE_FIELD.getVolatile(h); + } + + public static int testRead3Snippet(Holder h) { + /* Explicitly access the non-volatile field with non-volatile access semantics. */ + return (int) Holder.FIELD.get(h); + } + + public static int testRead4Snippet(Holder h) { + /* Explicitly access the non-volatile field with volatile access semantics. */ + return (int) Holder.FIELD.getVolatile(h); + } + + public static void testWrite1Snippet(Holder h) { + /* Explicitly access the volatile field with non-volatile access semantics. */ + Holder.VOLATILE_FIELD.set(h, 123); + } + + public static void testWrite2Snippet(Holder h) { + /* Explicitly access the volatile field with volatile access semantics. */ + Holder.VOLATILE_FIELD.setVolatile(h, 123); + } + + public static void testWrite3Snippet(Holder h) { + /* Explicitly access the non-volatile field with non-volatile access semantics. */ + Holder.FIELD.set(h, 123); + } + + public static void testWrite4Snippet(Holder h) { + /* Explicitly access the non-volatile field with volatile access semantics. */ + Holder.FIELD.setVolatile(h, 123); + } + + void testAccess(String name, int expectedReads, int expectedWrites, int expectedMembars, int expectedAnyKill) { + ResolvedJavaMethod method = getResolvedJavaMethod(name); + StructuredGraph graph = parseForCompile(method); + compile(method, graph); + Assert.assertEquals(expectedReads, graph.getNodes().filter(ReadNode.class).count()); + Assert.assertEquals(expectedWrites, graph.getNodes().filter(WriteNode.class).count()); + Assert.assertEquals(expectedMembars, graph.getNodes().filter(MembarNode.class).count()); + Assert.assertEquals(expectedAnyKill, countAnyKill(graph)); + } + + @Test + public void testRead1() { + testAccess("testRead1Snippet", 1, 0, 0, 0); + } + + @Test + public void testRead2() { + testAccess("testRead2Snippet", 1, 0, 2, 2); + } + + @Test + public void testRead3() { + testAccess("testRead3Snippet", 1, 0, 0, 0); + } + + @Test + public void testRead4() { + testAccess("testRead4Snippet", 1, 0, 2, 2); + } + + @Test + public void testWrite1() { + testAccess("testWrite1Snippet", 0, 1, 0, 0); + } + + @Test + public void testWrite2() { + testAccess("testWrite2Snippet", 0, 1, 2, 2); + } + + @Test + public void testWrite3() { + testAccess("testWrite3Snippet", 0, 1, 0, 0); + } + + @Test + public void testWrite4() { + testAccess("testWrite4Snippet", 0, 1, 2, 2); + } + + private static int countAnyKill(StructuredGraph graph) { + int anyKillCount = 0; + int startNodes = 0; + for (Node n : graph.getNodes()) { + if (n instanceof StartNode) { + startNodes++; + } else if (n instanceof MemoryCheckpoint.Single) { + MemoryCheckpoint.Single single = (MemoryCheckpoint.Single) n; + if (single.getLocationIdentity().isAny()) { + anyKillCount++; + } + } else if (n instanceof MemoryCheckpoint.Multi) { + MemoryCheckpoint.Multi multi = (MemoryCheckpoint.Multi) n; + for (LocationIdentity loc : multi.getLocationIdentities()) { + if (loc.isAny()) { + anyKillCount++; + break; + } + } + } + } + // Ignore single StartNode. + Assert.assertEquals(1, startNodes); + return anyKillCount; + } +} 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 --- /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 --- 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 @@ 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 @@ } } 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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 @@ @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 @@ 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 @@ @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 --- 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 @@ 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 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 @@ 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 @@ 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 --- 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 @@ out.printf("\n"); createImports(out, plugins); out.printf("\n"); + for (GeneratedPlugin plugin : plugins) { + plugin.generate(processor, out); + 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"); createPluginFactoryMethod(out, plugins); out.printf("}\n"); } @@ -164,7 +163,7 @@ 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 --- 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 @@ } @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 --- /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 --- 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 --- /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 --- 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 @@ @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 --- 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 @@ @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 @@ 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 @@ } // 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 --- 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.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 @@ 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 --- /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 --- /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 --- 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 --- /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 --- 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.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 @@ */ 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 --- 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 @@ @Test public void test() throws Throwable { + assumeManagementLibraryIsLoadable(); try { Class.forName("java.lang.instrument.Instrumentation"); } catch (ClassNotFoundException ex) { @@ -198,7 +199,7 @@ } } - @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 --- 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 @@ 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 --- 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.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 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 @@ 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 @@ 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 @@ 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 @@ } @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 --- 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.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 @@ return target; } + public MetaAccessProvider getMetaAccess() { + return metaAccess; + } + @Override @SuppressWarnings("try") public void lower(Node n, LoweringTool tool) { @@ -440,13 +447,14 @@ } } + 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 @@ 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 @@ 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 @@ 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 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,24 +1118,36 @@ 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 = readOrCreateArrayLength(n, array, tool, graph); + + LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength, NodeView.DEFAULT); + if (boundsCheck.isTautology()) { + return null; + } + 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); } - - LogicNode boundsCheck = IntegerBelowNode.create(n.index(), arrayLength, NodeView.DEFAULT); - if (boundsCheck.isTautology()) { - return null; - } - return tool.createGuard(n, graph.addOrUniqueWithInputs(boundsCheck), BoundsCheckException, InvalidateReprofile); + return arrayLength; } protected GuardingNode createNullCheck(ValueNode object, FixedNode before, LoweringTool tool) { @@ -1150,10 +1170,10 @@ 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 --- 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 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 --- 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 @@ 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 @@ 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 --- 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 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 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 --- 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.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.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.GraalError; import org.graalvm.compiler.debug.TimerKey; import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.graph.NodeSourcePosition; -import org.graalvm.compiler.graph.Node.NodeIntrinsic; import org.graalvm.compiler.java.GraphBuilderPhase; import org.graalvm.compiler.java.GraphBuilderPhase.Instance; import org.graalvm.compiler.nodes.CallTargetNode; @@ -311,6 +313,37 @@ 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 --- 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.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 --- 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 @@ */ 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 @@ } } } + + 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 --- 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 @@ 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 @@ // 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 @@ @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/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java new file mode 100644 --- /dev/null +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/ArrayRegionEqualsNode.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +package org.graalvm.compiler.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.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; +import org.graalvm.compiler.nodes.ValueNodeUtil; +import org.graalvm.compiler.nodes.memory.MemoryAccess; +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 static org.graalvm.compiler.nodeinfo.InputType.Memory; + +// JaCoCo Exclude + +/** + * 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 { + + public static final NodeClass TYPE = NodeClass.create(ArrayRegionEqualsNode.class); + + /** {@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(kind); + } + + @Override + public MemoryNode getLastLocationAccess() { + return lastLocationAccess; + } + + @Override + public void setLastLocationAccess(MemoryNode lla) { + updateUsages(ValueNodeUtil.asNode(lastLocationAccess), ValueNodeUtil.asNode(lla)); + lastLocationAccess = lla; + } +} 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 --- 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 @@ 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 --- 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 @@ } @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 --- 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.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 @@ * {@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 @@ 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 --- 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.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.List; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugDumpHandler; @@ -46,6 +46,7 @@ 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 @@ 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 --- 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 @@ -114,6 +114,13 @@ } /** + * 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. */ public static class Subprocess { 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 --- 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.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 @@ 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 --- 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 @@ JavaKind accessKind = load.accessKind(); JavaKind componentKind = type.getComponentType().getJavaKind(); long offset = load.offset().asJavaConstant().asLong(); - int index = VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); - 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); + int index = VirtualArrayNode.entryIndexForOffset(tool.getMetaAccess(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); + if (index >= 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 @@ if (store.offset().isConstant()) { long offset = store.offset().asJavaConstant().asLong(); boolean overflowAccess = isOverflowAccess(accessKind, componentKind); - int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); + int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(tool.getMetaAccess(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE); return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects); } else { processIdentity(state, location); diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java @@ -858,7 +858,7 @@ // rewrite to a zero constant of the larger kind debug.log("Rewriting entry %s to constant of larger size", valueIndex); states[i].setEntry(object, valueIndex, ConstantNode.defaultForKind(twoSlotKinds[valueIndex], graph())); - states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph())); + states[i].setEntry(object, valueIndex + 1, ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccess(), graph())); } else { compatible = false; break outer; @@ -890,7 +890,7 @@ // skip an entry after a long/double value that occupies two int slots valueIndex++; phis[valueIndex] = null; - values[valueIndex] = ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccessProvider(), graph()); + values[valueIndex] = ConstantNode.forConstant(JavaConstant.forIllegal(), tool.getMetaAccess(), graph()); } valueIndex++; } diff --git a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java --- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java +++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java @@ -28,7 +28,6 @@ import java.util.List; -import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider; import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.graph.Node; @@ -97,25 +96,10 @@ } @Override - public MetaAccessProvider getMetaAccessProvider() { - return metaAccess; - } - - @Override - public ConstantReflectionProvider getConstantReflectionProvider() { - return constantReflection; - } - - @Override public ConstantFieldProvider getConstantFieldProvider() { return constantFieldProvider; } - @Override - public ArrayOffsetProvider getArrayOffsetProvider() { - return loweringProvider; - } - public void reset(PartialEscapeBlockState newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) { deleted = false; state = newState; @@ -168,7 +152,7 @@ * 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 @@ 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 --- 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.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 @@ @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 @@ 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 @@ 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 --- 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 @@ 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 --- 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 @@ 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 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 --- /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 --- 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 @@ 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 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(); + } }