8177046: Update Graal

Update Graal, make appropriate changes to AOT, and the build system.

Reviewed-by: kvn
This commit is contained in:
Igor Veresov 2017-03-22 13:42:45 -07:00
parent 2fd9f38a31
commit d405f1648b
907 changed files with 25594 additions and 20934 deletions

View File

@ -47,11 +47,9 @@ ifeq ($(INCLUDE_GRAAL), true)
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
$(SRC_DIR)/org.graalvm.compiler.common/src \
$(SRC_DIR)/org.graalvm.compiler.core/src \
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
$(SRC_DIR)/org.graalvm.compiler.asm/src \
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
@ -68,6 +66,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
@ -102,6 +101,7 @@ ifeq ($(INCLUDE_GRAAL), true)
SRC := \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
$(SRC_DIR)/org.graalvm.util/src \
, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
@ -114,9 +114,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
$(SRC_DIR)/org.graalvm.compiler.common/src \
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
$(SRC_DIR)/org.graalvm.compiler.api.collections/src \
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
$(SRC_DIR)/org.graalvm.compiler.code/src \
$(SRC_DIR)/org.graalvm.compiler.core.common/src \
@ -125,6 +123,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \

View File

@ -37,7 +37,6 @@ SRC_DIR := $(HOTSPOT_TOPDIR)/src/$(MODULE)/share/classes
PROC_SRC_SUBDIRS := \
org.graalvm.compiler.code \
org.graalvm.compiler.common \
org.graalvm.compiler.core \
org.graalvm.compiler.core.aarch64 \
org.graalvm.compiler.core.amd64 \

View File

@ -40,14 +40,15 @@ import jdk.tools.jaotc.binformat.macho.JMachORelocObject;
import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.options.OptionValues;
/**
* A format-agnostic container class that holds various components of a binary.
*
* <p>
* This class holds information necessary to create platform-specific binary containers such as
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac
* OS or PEContainer for MS Windows operating systems.
* ELFContainer for Linux and Solaris operating systems or MachOContainer for Mac OS or PEContainer
* for MS Windows operating systems.
*
* <p>
* Method APIs provided by this class are used to construct and populate platform-independent
@ -58,6 +59,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
* Methods to record and access code section contents, symbols and relocations are provided.
*/
public class BinaryContainer implements SymbolTable {
private final OptionValues graalOptions;
private final int codeSegmentSize;
@ -259,8 +261,12 @@ public class BinaryContainer implements SymbolTable {
* Allocates a {@code BinaryContainer} object whose content will be generated in a file with the
* prefix {@code prefix}. It also initializes internal code container, symbol table and
* relocation tables.
*
* @param graalOptions
*/
public BinaryContainer(GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
public BinaryContainer(OptionValues graalOptions, GraalHotSpotVMConfig graalHotSpotVMConfig, GraphBuilderConfiguration graphBuilderConfig, String jvmVersion) {
this.graalOptions = graalOptions;
this.codeSegmentSize = graalHotSpotVMConfig.codeSegmentSize;
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
@ -305,17 +311,17 @@ public class BinaryContainer implements SymbolTable {
graalHotSpotVMConfig.useCMSGC,
graalHotSpotVMConfig.useTLAB,
graalHotSpotVMConfig.useBiasedLocking,
TieredAOT.getValue(),
TieredAOT.getValue(graalOptions),
graalHotSpotVMConfig.enableContended,
graalHotSpotVMConfig.restrictContended,
graphBuilderConfig.omitAssertions()
};
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().shift,
graalHotSpotVMConfig.getKlassEncoding().shift,
int[] intFlags = { graalHotSpotVMConfig.getOopEncoding().getShift(),
graalHotSpotVMConfig.getKlassEncoding().getShift(),
graalHotSpotVMConfig.contendedPaddingWidth,
graalHotSpotVMConfig.fieldsAllocationStyle,
1 << graalHotSpotVMConfig.getOopEncoding().alignment,
1 << graalHotSpotVMConfig.logMinObjAlignment(),
graalHotSpotVMConfig.codeSegmentSize,
};
// @formatter:on
@ -511,8 +517,7 @@ public class BinaryContainer implements SymbolTable {
JPECoffRelocObject pecoffobj = new JPECoffRelocObject(this, outputFileName, aotVersion);
pecoffobj.createPECoffRelocObject(relocationTable, symbolTable.values());
break;
}
else
} else
throw new InternalError("Unsupported platform: " + osName);
}
}

View File

@ -23,17 +23,12 @@
package jdk.tools.jaotc;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
import java.util.ListIterator;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.GraalCompiler;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.Debug.Scope;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotCompiledCodeBuilder;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
@ -43,8 +38,7 @@ import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValue.OverrideScope;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.PhaseSuite;
@ -62,6 +56,7 @@ import jdk.vm.ci.meta.TriState;
public class AOTBackend {
private final Main main;
private final OptionValues graalOptions;
private final HotSpotBackend backend;
@ -71,8 +66,9 @@ public class AOTBackend {
private final HighTierContext highTierContext;
private final GraalFilters filters;
public AOTBackend(Main main, HotSpotBackend backend, GraalFilters filters) {
public AOTBackend(Main main, OptionValues graalOptions, HotSpotBackend backend, GraalFilters filters) {
this.main = main;
this.graalOptions = graalOptions;
this.backend = backend;
this.filters = filters;
providers = backend.getProviders();
@ -87,23 +83,21 @@ public class AOTBackend {
private Suites getSuites() {
// create suites every time, as we modify options for the compiler
return backend.getSuites().getDefaultSuites();
return backend.getSuites().getDefaultSuites(graalOptions);
}
private LIRSuites getLirSuites() {
// create suites every time, as we modify options for the compiler
return backend.getSuites().getDefaultLIRSuites();
return backend.getSuites().getDefaultLIRSuites(graalOptions);
}
@SuppressWarnings("try")
public CompilationResult compileMethod(ResolvedJavaMethod resolvedMethod) {
try (OverrideScope s = OptionValue.override(ImmutableCode, true, GeneratePIC, true)) {
StructuredGraph graph = buildStructuredGraph(resolvedMethod);
if (graph != null) {
return compileGraph(resolvedMethod, graph);
}
return null;
StructuredGraph graph = buildStructuredGraph(resolvedMethod);
if (graph != null) {
return compileGraph(resolvedMethod, graph);
}
return null;
}
/**
@ -115,7 +109,7 @@ public class AOTBackend {
@SuppressWarnings("try")
private StructuredGraph buildStructuredGraph(ResolvedJavaMethod javaMethod) {
try (Scope s = Debug.scope("AOTParseMethod")) {
StructuredGraph graph = new StructuredGraph(javaMethod, StructuredGraph.AllowAssumptions.NO, false, CompilationIdentifier.INVALID_COMPILATION_ID);
StructuredGraph graph = new StructuredGraph.Builder(graalOptions).method(javaMethod).useProfilingInfo(false).build();
graphBuilderSuite.apply(graph, highTierContext);
return graph;
} catch (Throwable e) {

View File

@ -33,6 +33,7 @@ import org.graalvm.compiler.debug.DebugEnvironment;
import org.graalvm.compiler.debug.Management;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.debug.internal.DebugScope;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
@ -54,6 +55,8 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
private final Main main;
private OptionValues graalOptions;
/**
* The compilation id of this task.
*/
@ -73,8 +76,9 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
*/
private CompiledMethodInfo result;
public AOTCompilationTask(Main main, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
public AOTCompilationTask(Main main, OptionValues graalOptions, AOTCompiledClass holder, ResolvedJavaMethod method, AOTBackend aotBackend) {
this.main = main;
this.graalOptions = graalOptions;
this.id = ids.getAndIncrement();
this.holder = holder;
this.method = method;
@ -91,14 +95,14 @@ public class AOTCompilationTask implements Runnable, Comparable<Object> {
// Ensure a debug configuration for this thread is initialized
if (Debug.isEnabled() && DebugScope.getConfig() == null) {
DebugEnvironment.initialize(TTY.out);
DebugEnvironment.ensureInitialized(graalOptions);
}
AOTCompiler.logCompilation(MiscUtils.uniqueMethodName(method), "Compiling");
final long threadId = Thread.currentThread().getId();
final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue() && !TTY.isSuppressed();
final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue() && !TTY.isSuppressed();
final boolean printCompilation = GraalCompilerOptions.PrintCompilation.getValue(graalOptions) && !TTY.isSuppressed();
final boolean printAfterCompilation = GraalCompilerOptions.PrintAfterCompilation.getValue(graalOptions) && !TTY.isSuppressed();
if (printCompilation) {
TTY.println(getMethodDescription() + "...");
}

View File

@ -31,12 +31,16 @@ import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class AOTCompiler {
private final Main main;
private final OptionValues graalOptions;
private CompileQueue compileQueue;
private final AOTBackend backend;
@ -102,11 +106,13 @@ public class AOTCompiler {
/**
* @param main
* @param graalOptions
* @param aotBackend
* @param threads number of compilation threads
*/
public AOTCompiler(Main main, AOTBackend aotBackend, final int threads) {
public AOTCompiler(Main main, OptionValues graalOptions, AOTBackend aotBackend, final int threads) {
this.main = main;
this.graalOptions = graalOptions;
this.compileQueue = new CompileQueue(threads);
this.backend = aotBackend;
}
@ -146,7 +152,7 @@ public class AOTCompiler {
* @param method method to be enqueued
*/
private void enqueueMethod(AOTCompiledClass aotClass, ResolvedJavaMethod method) {
AOTCompilationTask task = new AOTCompilationTask(main, aotClass, method, backend);
AOTCompilationTask task = new AOTCompilationTask(main, graalOptions, aotClass, method, backend);
try {
compileQueue.execute(task);
} catch (RejectedExecutionException e) {

View File

@ -36,6 +36,7 @@ import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.Debug.Scope;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.stubs.Stub;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
@ -180,7 +181,8 @@ class DataBuilder {
@SuppressWarnings("try")
private AOTCompiledClass retrieveStubCode() {
ArrayList<CompiledMethodInfo> stubs = new ArrayList<>();
for (Stub stub : Stub.getStubs()) {
HotSpotForeignCallsProvider foreignCallsProvider = backend.getProviders().getForeignCalls();
for (Stub stub : foreignCallsProvider.getStubs()) {
try (Scope scope = Debug.scope("CompileStubs")) {
CompilationResult result = stub.getCompilationResult(backend);
CompiledMethodInfo cm = new CompiledMethodInfo(result, new AOTStub(stub, backend));

View File

@ -60,11 +60,15 @@ import jdk.tools.jaotc.collect.module.ModuleSourceProvider;
import jdk.tools.jaotc.utils.Timer;
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
import org.graalvm.compiler.hotspot.HotSpotGraalOptionValues;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.java.GraphBuilderPhase;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.tiers.HighTierContext;
@ -76,11 +80,6 @@ import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.runtime.JVMCI;
public class Main implements LogPrinter {
static {
GeneratePIC.setValue(true);
ImmutableCode.setValue(true);
}
static class BadArgs extends Exception {
private static final long serialVersionUID = 1L;
final String key;
@ -132,7 +131,7 @@ public class Main implements LogPrinter {
abstract void process(Main task, String opt, String arg) throws BadArgs;
}
static Option[] recognizedOptions = { new Option(" --output <file> Output file name", true, "--output") {
static Option[] recognizedOptions = {new Option(" --output <file> Output file name", true, "--output") {
@Override
void process(Main task, String opt, String arg) {
String name = arg;
@ -172,7 +171,7 @@ public class Main implements LogPrinter {
}, new Option(" --compile-for-tiered Generate profiling code for tiered compilation", false, "--compile-for-tiered") {
@Override
void process(Main task, String opt, String arg) {
TieredAOT.setValue(true);
task.options.tiered = true;
}
}, new Option(" --compile-with-assertions Compile with java assertions", false, "--compile-with-assertions") {
@Override
@ -265,6 +264,7 @@ public class Main implements LogPrinter {
public boolean help;
public boolean version;
public boolean compileWithAssertions;
public boolean tiered;
}
/* package */final Options options = new Options();
@ -307,7 +307,7 @@ public class Main implements LogPrinter {
printlnInfo("Compiling " + options.outputName + "...");
final long start = System.currentTimeMillis();
if (!run()) {
return EXIT_ABNORMAL;
return EXIT_ABNORMAL;
}
final long end = System.currentTimeMillis();
printlnInfo("Total time: " + (end - start) + " ms");
@ -351,8 +351,7 @@ public class Main implements LogPrinter {
}
/**
* Visual Studio supported versions
* Search Order is: VS2013, VS2015, VS2012
* Visual Studio supported versions Search Order is: VS2013, VS2015, VS2012
*/
public enum VSVERSIONS {
VS2013("VS120COMNTOOLS", "C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\bin\\amd64\\link.exe"),
@ -367,20 +366,23 @@ public class Main implements LogPrinter {
this.wkp = wellknownpath;
}
String EnvVariable() { return envvariable; }
String WellKnownPath() { return wkp; }
String EnvVariable() {
return envvariable;
}
String WellKnownPath() {
return wkp;
}
}
/**
* Search for Visual Studio link.exe
* Search Order is: VS2013, VS2015, VS2012
* Search for Visual Studio link.exe Search Order is: VS2013, VS2015, VS2012
*/
private static String getWindowsLinkPath() {
String link = "\\VC\\bin\\amd64\\link.exe";
/**
* First try searching the paths pointed to by
* the VS environment variables.
* First try searching the paths pointed to by the VS environment variables.
*/
for (VSVERSIONS vs : VSVERSIONS.values()) {
String vspath = System.getenv(vs.EnvVariable());
@ -388,13 +390,13 @@ public class Main implements LogPrinter {
File commonTools = new File(vspath);
File vsRoot = commonTools.getParentFile().getParentFile();
File linkPath = new File(vsRoot, link);
if (linkPath.exists()) return linkPath.getPath();
if (linkPath.exists())
return linkPath.getPath();
}
}
/**
* If we didn't find via the VS environment variables,
* try the well known paths
* If we didn't find via the VS environment variables, try the well known paths
*/
for (VSVERSIONS vs : VSVERSIONS.values()) {
String wkp = vs.WellKnownPath();
@ -438,7 +440,13 @@ public class Main implements LogPrinter {
printInfo(classesToCompile.size() + " classes found");
}
GraalJVMCICompiler graalCompiler = (GraalJVMCICompiler) JVMCI.getRuntime().getCompiler();
OptionValues graalOptions = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
// Setting -Dgraal.TieredAOT overrides --compile-for-tiered
if (!TieredAOT.hasBeenSet(graalOptions)) {
graalOptions = new OptionValues(graalOptions, TieredAOT, options.tiered);
}
graalOptions = new OptionValues(HotSpotGraalOptionValues.HOTSPOT_OPTIONS, GeneratePIC, true, ImmutableCode, true);
GraalJVMCICompiler graalCompiler = HotSpotGraalCompilerFactory.createCompiler(JVMCI.getRuntime(), graalOptions, CompilerConfigurationFactory.selectFactory(null, graalOptions));
HotSpotGraalRuntimeProvider runtime = (HotSpotGraalRuntimeProvider) graalCompiler.getGraalRuntime();
HotSpotHostBackend backend = (HotSpotHostBackend) runtime.getCapability(RuntimeProvider.class).getHostBackend();
MetaAccessProvider metaAccess = backend.getProviders().getMetaAccess();
@ -458,8 +466,8 @@ public class Main implements LogPrinter {
System.gc();
}
AOTBackend aotBackend = new AOTBackend(this, backend, filters);
AOTCompiler compiler = new AOTCompiler(this, aotBackend, options.threads);
AOTBackend aotBackend = new AOTBackend(this, graalOptions, backend, filters);
AOTCompiler compiler = new AOTCompiler(this, graalOptions, aotBackend, options.threads);
classes = compiler.compileClasses(classes);
GraalHotSpotVMConfig graalHotSpotVMConfig = runtime.getVMConfig();
@ -475,7 +483,7 @@ public class Main implements LogPrinter {
System.gc();
}
BinaryContainer binaryContainer = new BinaryContainer(graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, JVM_VERSION);
DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
dataBuilder.prepareData();
@ -524,11 +532,9 @@ public class Main implements LogPrinter {
if (name.endsWith(".so")) {
objectFileName = name.substring(0, name.length() - ".so".length());
}
else if (name.endsWith(".dylib")) {
} else if (name.endsWith(".dylib")) {
objectFileName = name.substring(0, name.length() - ".dylib".length());
}
else if (name.endsWith(".dll")) {
} else if (name.endsWith(".dll")) {
objectFileName = name.substring(0, name.length() - ".dll".length());
}
@ -536,34 +542,32 @@ public class Main implements LogPrinter {
case "Linux":
// libraryFileName = options.outputName + ".so";
objectFileName = objectFileName + ".o";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerCmd = linkerPath + " -shared -z noexecstack -o " + libraryFileName + " " + objectFileName;
break;
case "SunOS":
// libraryFileName = options.outputName + ".so";
objectFileName = objectFileName + ".o";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerCmd = linkerPath + " -shared -o " + libraryFileName + " " + objectFileName;
break;
case "Mac OS X":
// libraryFileName = options.outputName + ".dylib";
objectFileName = objectFileName + ".o";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerPath = (options.linkerpath != null) ? options.linkerpath : "ld";
linkerCmd = linkerPath + " -dylib -o " + libraryFileName + " " + objectFileName;
break;
default:
if (osName.startsWith("Windows")) {
// libraryFileName = options.outputName + ".dll";
objectFileName = objectFileName + ".obj";
linkerPath = (options.linkerpath != null) ?
options.linkerpath : getWindowsLinkPath();
linkerPath = (options.linkerpath != null) ? options.linkerpath : getWindowsLinkPath();
if (linkerPath == null) {
throw new InternalError("Can't locate Microsoft Visual Studio amd64 link.exe");
}
linkerCmd = linkerPath + " /DLL /OPT:NOREF /NOLOGO /NOENTRY" + " /OUT:" + libraryFileName + " " + objectFileName;
break;
}
else
} else
throw new InternalError("Unsupported platform: " + osName);
}

View File

@ -17,18 +17,22 @@ suite = {
"sha1" : "476d9a44cd19d6b55f81571077dfa972a4f8a083",
"bootClassPathAgent" : "true",
},
"ASM5" : {
"sha1" : "0da08b8cce7bbf903602a25a3a163ae252435795",
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-5.0.4.jar"],
},
"ASM_TREE5" : {
"sha1" : "396ce0c07ba2b481f25a70195c7c94922f0d1b0b",
"urls" : ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/asm-tree-5.0.4.jar"],
"dependencies" : ["ASM5"],
},
},
"projects" : {
# ------------- Graal -------------
"org.graalvm.compiler.common" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "API,Graal",
},
"org.graalvm.compiler.serviceprovider" : {
"subDir" : "share/classes",
@ -50,7 +54,9 @@ suite = {
"org.graalvm.compiler.options" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : ["org.graalvm.util"],
"checkstyle" : "org.graalvm.compiler.graph",
"uses" : ["org.graalvm.compiler.options.OptionDescriptors"],
"javaCompliance" : "1.8",
"workingSets" : "Graal",
},
@ -82,6 +88,11 @@ suite = {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"checkstyle" : "org.graalvm.compiler.graph",
"uses" : [
"org.graalvm.compiler.debug.DebugConfigCustomizer",
"org.graalvm.compiler.debug.DebugInitializationParticipant",
"org.graalvm.compiler.debug.TTYStreamProvider",
],
"dependencies" : [
"org.graalvm.compiler.serviceprovider",
"org.graalvm.compiler.options"
@ -108,7 +119,6 @@ suite = {
"sourceDirs" : ["src"],
"dependencies" : [
"org.graalvm.compiler.graph",
"org.graalvm.compiler.common",
],
"annotationProcessors" : ["GRAAL_SERVICEPROVIDER_PROCESSOR"],
"checkstyle" : "org.graalvm.compiler.graph",
@ -116,7 +126,7 @@ suite = {
"workingSets" : "Graal",
},
"org.graalvm.compiler.api.collections" : {
"org.graalvm.util" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"checkstyle" : "org.graalvm.compiler.graph",
@ -124,6 +134,18 @@ suite = {
"workingSets" : "API,Graal",
},
"org.graalvm.util.test" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [
"mx:JUNIT",
"org.graalvm.util",
],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "API,Graal",
},
"org.graalvm.compiler.api.directives" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
@ -179,6 +201,11 @@ suite = {
"org.graalvm.compiler.replacements",
"org.graalvm.compiler.runtime",
],
"imports" : [
# All other internal packages are exported dynamically -
# see org.graalvm.compiler.hotspot.HotSpotGraalJVMCIServiceLocator
"jdk.internal.module",
],
"checkstyle" : "org.graalvm.compiler.graph",
"annotationProcessors" : [
"GRAAL_NODEINFO_PROCESSOR",
@ -320,7 +347,6 @@ suite = {
"dependencies" : [
"org.graalvm.compiler.nodeinfo",
"org.graalvm.compiler.core.common",
"org.graalvm.compiler.api.collections",
],
"javaCompliance" : "1.8",
"annotationProcessors" : [
@ -347,6 +373,9 @@ suite = {
"org.graalvm.compiler.asm" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [
"org.graalvm.compiler.core.common"
],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "Graal,Assembler",
@ -356,7 +385,6 @@ suite = {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [
"org.graalvm.compiler.debug",
"org.graalvm.compiler.asm",
],
"checkstyle" : "org.graalvm.compiler.graph",
@ -379,9 +407,7 @@ suite = {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [
"org.graalvm.compiler.debug",
"org.graalvm.compiler.asm",
"org.graalvm.compiler.common"
],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
@ -711,6 +737,18 @@ suite = {
"workingSets" : "Graal",
},
"org.graalvm.compiler.loop.test" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : [
"org.graalvm.compiler.loop",
"org.graalvm.compiler.core.test"
],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "Graal,Test",
},
"org.graalvm.compiler.loop.phases" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
@ -731,6 +769,7 @@ suite = {
"org.graalvm.compiler.virtual",
"org.graalvm.compiler.loop.phases",
],
"uses" : ["org.graalvm.compiler.core.match.MatchStatementSet"],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"annotationProcessors" : [
@ -908,7 +947,9 @@ suite = {
"org.graalvm.compiler.graph.test",
"org.graalvm.compiler.printer",
"JAVA_ALLOCATION_INSTRUMENTER",
"ASM_TREE5",
],
"uses" : ["org.graalvm.compiler.options.OptionDescriptors"],
"annotationProcessors" : ["GRAAL_NODEINFO_PROCESSOR"],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
@ -929,21 +970,6 @@ suite = {
"findbugs" : "false",
},
# ------------- Salver -------------
"org.graalvm.compiler.salver" : {
"subDir" : "share/classes",
"sourceDirs" : ["src"],
"dependencies" : ["org.graalvm.compiler.phases"],
"annotationProcessors" : [
"GRAAL_OPTIONS_PROCESSOR",
"GRAAL_SERVICEPROVIDER_PROCESSOR",
],
"checkstyle" : "org.graalvm.compiler.graph",
"javaCompliance" : "1.8",
"workingSets" : "Graal",
},
# ------------- AOT -------------
"jdk.tools.jaotc" : {
@ -1073,7 +1099,6 @@ suite = {
"org.graalvm.compiler.replacements.amd64",
"org.graalvm.compiler.core.sparc",
"org.graalvm.compiler.replacements.sparc",
"org.graalvm.compiler.salver",
],
"distDependencies" : [
"GRAAL_API",
@ -1197,7 +1222,6 @@ suite = {
"org.graalvm.compiler.replacements.amd64",
"org.graalvm.compiler.core.sparc",
"org.graalvm.compiler.replacements.sparc",
"org.graalvm.compiler.salver",
"org.graalvm.compiler.hotspot.aarch64",
"org.graalvm.compiler.hotspot.amd64",
"org.graalvm.compiler.hotspot.sparc",

View File

@ -39,6 +39,7 @@ module jdk.internal.vm.compiler {
uses org.graalvm.compiler.debug.TTYStreamProvider;
uses org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
uses org.graalvm.compiler.hotspot.HotSpotBackendFactory;
uses org.graalvm.compiler.options.OptionValuesAccess;
uses org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
exports org.graalvm.compiler.api.directives to jdk.aot;

View File

@ -1,57 +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.api.collections;
import java.util.Map;
import java.util.Set;
/**
* A factory for creating collections.
*/
public interface CollectionsProvider {
/**
* Creates a set that uses reference-equality in place of object-equality when comparing
* entries.
*/
<E> Set<E> newIdentitySet();
/**
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
*/
<K, V> Map<K, V> newIdentityMap();
/**
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
*
* @param expectedMaxSize the expected maximum size of the map
*/
<K, V> Map<K, V> newIdentityMap(int expectedMaxSize);
/**
* Creates a map that uses reference-equality in place of object-equality when comparing keys.
*
* @param initFrom the returned map is populated with the entries in this map
*/
<K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom);
}

View File

@ -1,146 +0,0 @@
/*
* Copyright (c) 2016, 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.api.directives.test;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValue.OverrideScope;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@SuppressWarnings("try")
public class AllocationInstrumentationTest extends GraalCompilerTest {
private TinyInstrumentor instrumentor;
public AllocationInstrumentationTest() {
HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
method.setNotInlineable();
try {
instrumentor = new TinyInstrumentor(AllocationInstrumentationTest.class, "instrumentation");
} catch (IOException e) {
Assert.fail("unable to initialize the instrumentor: " + e);
}
}
public static class ClassA {
// This method should be marked as not inlineable
public void notInlinedMethod() {
}
}
public static boolean allocationWasExecuted;
private static void resetFlag() {
allocationWasExecuted = false;
}
static void instrumentation() {
GraalDirectives.instrumentationBeginForPredecessor();
allocationWasExecuted = true;
GraalDirectives.instrumentationEnd();
}
public static void notEscapeSnippet() {
@SuppressWarnings("unused")
ClassA a = new ClassA(); // a does not escape
}
@Test
public void testNotEscape() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "notEscapeSnippet", Opcodes.NEW);
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "notEscapeSnippet");
executeExpected(method, null); // ensure the method is fully resolved
resetFlag();
// The allocation in the snippet does not escape and will be optimized away. We expect
// the instrumentation is removed.
InstalledCode code = getCode(method);
code.executeVarargs();
Assert.assertFalse("allocation should not take place", allocationWasExecuted);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static void mustEscapeSnippet() {
ClassA a = new ClassA();
a.notInlinedMethod(); // a escapses
}
@Test
public void testMustEscape() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "mustEscapeSnippet", Opcodes.NEW);
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "mustEscapeSnippet");
executeExpected(method, null); // ensure the method is fully resolved
resetFlag();
// The allocation in the snippet escapes. We expect the instrumentation is preserved.
InstalledCode code = getCode(method);
code.executeVarargs();
Assert.assertTrue("allocation should take place", allocationWasExecuted);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static void partialEscapeSnippet(boolean condition) {
ClassA a = new ClassA();
if (condition) {
a.notInlinedMethod(); // a escapes in the then-clause
}
}
@Test
public void testPartialEscape() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
Class<?> clazz = instrumentor.instrument(AllocationInstrumentationTest.class, "partialEscapeSnippet", Opcodes.NEW);
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "partialEscapeSnippet");
executeExpected(method, null, true); // ensure the method is fully resolved
resetFlag();
// The allocation in the snippet escapes in the then-clause, and will be relocated to
// this branch. We expect the instrumentation follows and will only be effective when
// the then-clause is taken.
InstalledCode code = getCode(method);
code.executeVarargs(false);
Assert.assertFalse("allocation should not take place", allocationWasExecuted);
code.executeVarargs(true);
Assert.assertTrue("allocation should take place", allocationWasExecuted);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
}

View File

@ -70,7 +70,7 @@ public class DeoptimizeDirectiveTest extends GraalCompilerTest {
Result actual;
try {
actual = new Result(code.executeVarargs(), null);
} catch (Throwable e) {
} catch (Exception e) {
actual = new Result(null, e);
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2016, 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.api.directives.test;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValue.OverrideScope;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class IsMethodInlineDirectiveTest extends GraalCompilerTest {
public IsMethodInlineDirectiveTest() {
HotSpotResolvedJavaMethod calleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeSnippet");
calleeSnippet.shouldBeInlined();
HotSpotResolvedJavaMethod calleeWithInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(IsMethodInlineDirectiveTest.class, "calleeWithInstrumentationSnippet");
calleeWithInstrumentationSnippet.shouldBeInlined();
}
public static boolean rootMethodSnippet() {
return GraalDirectives.isMethodInlined();
}
@SuppressWarnings("try")
@Test
public void testRootMethod() {
ResolvedJavaMethod method = getResolvedJavaMethod("rootMethodSnippet");
executeExpected(method, null); // ensure the method is fully resolved
// The target method is not inlined. We expect the result to be false.
InstalledCode code = getCode(method);
try {
Result result = new Result(code.executeVarargs(), null);
assertEquals(new Result(false, null), result);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static boolean calleeSnippet() {
return GraalDirectives.isMethodInlined();
}
public static boolean callerSnippet() {
return calleeSnippet();
}
@Test
public void testInlinedCallee() {
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
executeExpected(method, null); // ensure the method is fully resolved
// calleeSnippet will be inlined. We expect the result to be true.
InstalledCode code = getCode(method);
try {
Result result = new Result(code.executeVarargs(), null);
assertEquals(new Result(true, null), result);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
static boolean isCalleeInlined;
static boolean isCallerInlined;
public static void calleeWithInstrumentationSnippet() {
GraalDirectives.instrumentationBegin();
isCalleeInlined = GraalDirectives.isMethodInlined();
GraalDirectives.instrumentationEnd();
}
public static void callerSnippet1() {
calleeWithInstrumentationSnippet();
GraalDirectives.instrumentationBegin();
isCallerInlined = GraalDirectives.isMethodInlined();
GraalDirectives.instrumentationEnd();
}
@SuppressWarnings("try")
@Test
public void testInlinedCalleeWithInstrumentation() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
executeExpected(method, null); // ensure the method is fully resolved
isCalleeInlined = false;
isCallerInlined = false;
// calleeWithInstrumentationSnippet will be inlined. We expect the flag1 set in
// calleeWithInstrumentationSnippet to be true, and the flag2 set in callerSnippet1 to
// be false.
InstalledCode code = getCode(method);
code.executeVarargs();
assertTrue("calleWithInstrumentationSnippet should be inlined", isCalleeInlined);
assertFalse("callerSnippet1 should not be inlined", isCallerInlined);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (c) 2016, 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.api.directives.test;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValue.OverrideScope;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@SuppressWarnings("try")
public class LockInstrumentationTest extends GraalCompilerTest {
private TinyInstrumentor instrumentor;
public LockInstrumentationTest() {
HotSpotResolvedJavaMethod method = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(ClassA.class, "notInlinedMethod");
method.setNotInlineable();
try {
instrumentor = new TinyInstrumentor(LockInstrumentationTest.class, "instrumentation");
} catch (IOException e) {
Assert.fail("unable to initialize the instrumentor: " + e);
}
}
public static class ClassA {
// This method should be marked as not inlineable
public void notInlinedMethod() {
}
}
public static final Object lock = new Object();
public static boolean lockAfterCheckPoint;
public static boolean checkpoint;
private static void resetFlags() {
lockAfterCheckPoint = false;
checkpoint = false;
}
static void instrumentation() {
GraalDirectives.instrumentationBeginForPredecessor();
lockAfterCheckPoint = checkpoint;
GraalDirectives.instrumentationEnd();
}
public static void lockSnippet() {
synchronized (lock) {
checkpoint = true;
ClassA a = new ClassA();
a.notInlinedMethod();
}
}
@Test
public void testLock() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "lockSnippet", Opcodes.MONITORENTER);
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "lockSnippet");
executeExpected(method, null); // ensure the method is fully resolved
resetFlags();
// The monitorenter anchors. We expect the instrumentation set the flag before passing
// the checkpoint.
InstalledCode code = getCode(method);
code.executeVarargs();
Assert.assertFalse("expected lock was performed before checkpoint", lockAfterCheckPoint);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static void postponeLockSnippet() {
ClassA a = new ClassA();
synchronized (a) {
checkpoint = true;
a.notInlinedMethod();
}
}
@Test
public void testNonEscapeLock() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
Class<?> clazz = instrumentor.instrument(LockInstrumentationTest.class, "postponeLockSnippet", Opcodes.MONITORENTER);
ResolvedJavaMethod method = getResolvedJavaMethod(clazz, "postponeLockSnippet");
executeExpected(method, null); // ensure the method is fully resolved
resetFlags();
// The lock in the snippet will be relocated before the invocation to
// notInlinedMethod(), i.e., after the checkpoint. We expect the instrumentation follows
// and flag will be set to true.
InstalledCode code = getCode(method);
code.executeVarargs();
Assert.assertTrue("expected lock was performed after checkpoint", lockAfterCheckPoint);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
}

View File

@ -1,175 +0,0 @@
/*
* Copyright (c) 2016, 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.api.directives.test;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Objects;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.Debug.Scope;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValue.OverrideScope;
import org.graalvm.compiler.printer.IdealGraphPrinter;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class RootNameDirectiveTest extends GraalCompilerTest {
public RootNameDirectiveTest() {
HotSpotResolvedJavaMethod rootNameAtCalleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameAtCalleeSnippet");
rootNameAtCalleeSnippet.shouldBeInlined();
HotSpotResolvedJavaMethod rootNameWithinInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameWithinInstrumentationSnippet");
rootNameWithinInstrumentationSnippet.shouldBeInlined();
}
private static String toString(ResolvedJavaMethod method) {
return method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor();
}
public static String rootNameSnippet() {
return GraalDirectives.rootName();
}
@Test
public void testRootName() {
ResolvedJavaMethod method = getResolvedJavaMethod("rootNameSnippet");
executeExpected(method, null); // ensure the method is fully resolved
// The target snippet is already the root method. We expect the name of the target snippet
// is returned.
InstalledCode code = getCode(method);
try {
Result result = new Result(code.executeVarargs(), null);
assertEquals(new Result(toString(method), null), result);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
public static String rootNameAtCalleeSnippet() {
return GraalDirectives.rootName();
}
public static String callerSnippet() {
return rootNameAtCalleeSnippet();
}
@Test
public void testRootNameAtCallee() {
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
executeExpected(method, null); // ensure the method is fully resolved
// The target snippet is the compilation root of rootNameAtCalleeSnippet() because the later
// will be inlined. We expect the name of the target snippet is returned.
InstalledCode code = getCode(method);
try {
Result result = new Result(code.executeVarargs(), null);
assertEquals(new Result(toString(method), null), result);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
static String rootNameInCallee;
static String rootNameInCaller;
@BytecodeParserForceInline
public static void rootNameWithinInstrumentationSnippet() {
GraalDirectives.instrumentationBegin();
rootNameInCallee = GraalDirectives.rootName();
GraalDirectives.instrumentationEnd();
}
public static void callerSnippet1() {
rootNameWithinInstrumentationSnippet();
GraalDirectives.instrumentationBegin();
rootNameInCaller = GraalDirectives.rootName();
GraalDirectives.instrumentationEnd();
}
@SuppressWarnings("try")
private void assertEquals(StructuredGraph graph, InstalledCode code, Object expected, Object actual) {
if (!Objects.equal(expected, actual)) {
Formatter buf = new Formatter();
try (Scope s = Debug.sandbox("PrintingGraph", null)) {
Map<Object, Object> properties = new HashMap<>();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
IdealGraphPrinter printer = new IdealGraphPrinter(baos, true, getSnippetReflection());
printer.beginGroup("RootNameDirectiveTest", "RootNameDirectiveTest", graph.method(), -1, null);
properties.put("graph", graph.toString());
properties.put("scope", Debug.currentScope());
printer.print(graph, graph.method().format("%H.%n(%p)"), properties);
printer.endGroup();
printer.close();
buf.format("-- Graph -- %n%s", baos.toString());
} catch (Throwable e) {
buf.format("%nError printing graph: %s", e);
}
try {
CodeCacheProvider codeCache = getCodeCache();
Method disassemble = codeCache.getClass().getMethod("disassemble", InstalledCode.class);
buf.format("%n-- Code -- %n%s", disassemble.invoke(codeCache, code));
} catch (NoSuchMethodException e) {
// Not a HotSpotCodeCacheProvider
} catch (Exception e) {
buf.format("%nError disassembling code: %s", e);
}
Assert.assertEquals(buf.toString(), expected, actual);
}
}
@SuppressWarnings("try")
@Test
public void testRootNameWithinInstrumentationAtCallee() {
try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
executeExpected(method, null); // ensure the method is fully resolved
rootNameInCallee = null;
rootNameInCaller = null;
// We expect both rootName1 and rootName2 are set to the name of the target snippet.
StructuredGraph graph = parseForCompile(method);
InstalledCode code = getCode(method, graph);
code.executeVarargs();
assertEquals(graph, code, toString(method), rootNameInCallee);
assertEquals(graph, code, rootNameInCallee, rootNameInCaller);
} catch (Throwable e) {
throw new AssertionError(e);
}
}
}

View File

@ -1,242 +0,0 @@
/*
* Copyright (c) 2016, 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.api.directives.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.graalvm.compiler.test.ExportingClassLoader;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
import jdk.internal.org.objectweb.asm.tree.ClassNode;
import jdk.internal.org.objectweb.asm.tree.IincInsnNode;
import jdk.internal.org.objectweb.asm.tree.InsnList;
import jdk.internal.org.objectweb.asm.tree.JumpInsnNode;
import jdk.internal.org.objectweb.asm.tree.LabelNode;
import jdk.internal.org.objectweb.asm.tree.LineNumberNode;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
import jdk.internal.org.objectweb.asm.tree.VarInsnNode;
/**
* The {@code TinyInstrumentor} is a bytecode instrumentor using ASM bytecode manipulation
* framework. It injects given code snippet into a target method and creates a temporary class as
* the container. Because the target method is cloned into the temporary class, it is required that
* the target method is public static. Any referred method/field in the target method or the
* instrumentation snippet should be made public as well.
*/
public class TinyInstrumentor implements Opcodes {
private InsnList instrumentationInstructions;
private int instrumentationMaxLocal;
/**
* Create a instrumentor with a instrumentation snippet. The snippet is specified with the given
* class {@code instrumentationClass} and the given method name {@code methodName}.
*/
public TinyInstrumentor(Class<?> instrumentationClass, String methodName) throws IOException {
MethodNode instrumentationMethod = getMethodNode(instrumentationClass, methodName);
assert instrumentationMethod != null;
assert (instrumentationMethod.access | ACC_STATIC) != 0;
assert "()V".equals(instrumentationMethod.desc);
instrumentationInstructions = cloneInstructions(instrumentationMethod.instructions);
instrumentationMaxLocal = instrumentationMethod.maxLocals;
// replace return instructions with a goto unless there is a single return at the end. In
// that case, simply remove the return.
List<AbstractInsnNode> returnInstructions = new ArrayList<>();
for (AbstractInsnNode instruction : selectAll(instrumentationInstructions)) {
if (instruction instanceof LineNumberNode) {
instrumentationInstructions.remove(instruction);
} else if (instruction.getOpcode() == RETURN) {
returnInstructions.add(instruction);
}
}
LabelNode exit = new LabelNode();
if (returnInstructions.size() == 1) {
AbstractInsnNode returnInstruction = returnInstructions.get(0);
if (instrumentationInstructions.getLast() != returnInstruction) {
instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
}
instrumentationInstructions.remove(returnInstruction);
} else {
for (AbstractInsnNode returnInstruction : returnInstructions) {
instrumentationInstructions.insertBefore(returnInstruction, new JumpInsnNode(GOTO, exit));
instrumentationInstructions.remove(returnInstruction);
}
}
instrumentationInstructions.add(exit);
}
/**
* @return a {@link MethodNode} called {@code methodName} in the given class.
*/
private static MethodNode getMethodNode(Class<?> clazz, String methodName) throws IOException {
ClassReader classReader = new ClassReader(clazz.getName());
ClassNode classNode = new ClassNode();
classReader.accept(classNode, ClassReader.SKIP_FRAMES);
for (MethodNode methodNode : classNode.methods) {
if (methodNode.name.equals(methodName)) {
return methodNode;
}
}
return null;
}
/**
* Create a {@link ClassNode} with empty constructor.
*/
private static ClassNode emptyClass(String name) {
ClassNode classNode = new ClassNode();
classNode.visit(52, ACC_SUPER | ACC_PUBLIC, name.replace('.', '/'), null, "java/lang/Object", new String[]{});
MethodVisitor mv = classNode.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitMaxs(1, 1);
mv.visitEnd();
return classNode;
}
/**
* Helper method for iterating the given {@link InsnList}.
*/
private static Iterable<AbstractInsnNode> selectAll(InsnList instructions) {
return new Iterable<AbstractInsnNode>() {
@Override
public Iterator<AbstractInsnNode> iterator() {
return instructions.iterator();
}
};
}
/**
* Make a clone of the given {@link InsnList}.
*/
private static InsnList cloneInstructions(InsnList instructions) {
Map<LabelNode, LabelNode> labelMap = new HashMap<>();
for (AbstractInsnNode instruction : selectAll(instructions)) {
if (instruction instanceof LabelNode) {
LabelNode clone = new LabelNode(new Label());
LabelNode original = (LabelNode) instruction;
labelMap.put(original, clone);
}
}
InsnList clone = new InsnList();
for (AbstractInsnNode insn : selectAll(instructions)) {
clone.add(insn.clone(labelMap));
}
return clone;
}
/**
* Shifts all local variable slot references by a specified amount.
*/
private static void shiftLocalSlots(InsnList instructions, int offset) {
for (AbstractInsnNode insn : selectAll(instructions)) {
if (insn instanceof VarInsnNode) {
VarInsnNode varInsn = (VarInsnNode) insn;
varInsn.var += offset;
} else if (insn instanceof IincInsnNode) {
IincInsnNode iincInsn = (IincInsnNode) insn;
iincInsn.var += offset;
}
}
}
/**
* Instrument the target method specified by the class {@code targetClass} and the method name
* {@code methodName}. For each occurrence of the {@code opcode}, the instrumentor injects a
* copy of the instrumentation snippet.
*/
public Class<?> instrument(Class<?> targetClass, String methodName, int opcode) throws IOException, ClassNotFoundException {
return instrument(targetClass, methodName, opcode, true);
}
public Class<?> instrument(Class<?> targetClass, String methodName, int opcode, boolean insertAfter) throws IOException, ClassNotFoundException {
// create a container class
String className = targetClass.getName() + "$$" + methodName;
ClassNode classNode = emptyClass(className);
// duplicate the target method and add to the container class
MethodNode methodNode = getMethodNode(targetClass, methodName);
MethodNode newMethodNode = new MethodNode(methodNode.access, methodNode.name, methodNode.desc, methodNode.signature, methodNode.exceptions.toArray(new String[methodNode.exceptions.size()]));
methodNode.accept(newMethodNode);
classNode.methods.add(newMethodNode);
// perform bytecode instrumentation
for (AbstractInsnNode instruction : selectAll(newMethodNode.instructions)) {
if (instruction.getOpcode() == opcode) {
InsnList instrumentation = cloneInstructions(instrumentationInstructions);
shiftLocalSlots(instrumentation, newMethodNode.maxLocals);
newMethodNode.maxLocals += instrumentationMaxLocal;
if (insertAfter) {
newMethodNode.instructions.insert(instruction, instrumentation);
} else {
newMethodNode.instructions.insertBefore(instruction, instrumentation);
}
}
}
// dump a byte array and load the class with a dedicated loader to separate the namespace
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
byte[] bytes = classWriter.toByteArray();
return new Loader(className, bytes).findClass(className);
}
private static class Loader extends ExportingClassLoader {
private String className;
private byte[] bytes;
Loader(String className, byte[] bytes) {
super(TinyInstrumentor.class.getClassLoader());
this.className = className;
this.bytes = bytes;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name.equals(className)) {
return defineClass(name, bytes, 0, bytes.length);
} else {
return super.findClass(name);
}
}
}
}

View File

@ -22,8 +22,6 @@
*/
package org.graalvm.compiler.api.directives;
import java.nio.charset.Charset;
// JaCoCo Exclude
/**
@ -367,67 +365,4 @@ public final class GraalDirectives {
*/
public static void ensureVirtualizedHere(@SuppressWarnings("unused") Object object) {
}
/**
* Marks the beginning of an instrumentation boundary. The instrumentation code will be folded
* during compilation and will not affect inlining heuristics regarding graph size except one on
* compiled low-level graph size (e.g., {@code GraalOptions.SmallCompiledLowLevelGraphSize}).
*/
public static void instrumentationBegin() {
}
/**
* Marks the beginning of an instrumentation boundary and associates the instrumentation with
* the preceding bytecode. If the instrumented instruction is {@code new}, then instrumentation
* will adapt to optimizations concerning allocation, and only be executed if allocation really
* happens.
*
* Example (the instrumentation is associated with {@code new}):
*
* <blockquote>
*
* <pre>
* 0 new java.lang.Object
* 3 invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationBeginForPredecessor() : void
* 6 invokestatic AllocationProfiler.countActualAllocation() : void
* 9 invokestatic org.graalvm.compiler.api.directives.GraalDirectives.instrumentationEnd() : void
* 12 invokespecial java.lang.Object()
* </pre>
*
* </blockquote>
*
* @see #instrumentationBegin()
*/
public static void instrumentationBeginForPredecessor() {
}
/**
* Marks the end of the instrumentation boundary.
*
* @see #instrumentationBegin()
*/
public static void instrumentationEnd() {
}
/**
* @return true if the enclosing method is inlined.
*/
public static boolean isMethodInlined() {
return false;
}
private static final Charset UTF8 = Charset.forName("UTF-8");
/**
* @return the name of the root method for the current compilation task. If the enclosing method
* is inlined, it returns the name of the method into which it is inlined.
*/
public static String rootName() {
return new String(rawRootName(), UTF8);
}
public static byte[] rawRootName() {
return new byte[0];
}
}

View File

@ -54,4 +54,13 @@ public @interface Snippet {
@Target(ElementType.PARAMETER)
public @interface ConstantParameter {
}
/**
* Denotes a snippet parameter that will bound to a non-null value during snippet template
* instantiation.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface NonNullParameter {
}
}

View File

@ -31,7 +31,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.aarch64.AArch64Address;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;

View File

@ -226,12 +226,12 @@ class TestProtectedAssembler extends AArch64Assembler {
}
@Override
protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
super.adds(size, dst, src1, src2, shiftType, imm);
}
@Override
protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
super.subs(size, dst, src1, src2, shiftType, imm);
}
@ -261,7 +261,7 @@ class TestProtectedAssembler extends AArch64Assembler {
}
@Override
protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
super.subs(size, dst, src1, src2, extendType, shiftAmt);
}
@ -336,7 +336,7 @@ class TestProtectedAssembler extends AArch64Assembler {
}
@Override
protected void rbit(int size, Register dst, Register src) {
public void rbit(int size, Register dst, Register src) {
super.rbit(size, dst, src);
}

View File

@ -25,7 +25,7 @@ package org.graalvm.compiler.asm.aarch64;
import static jdk.vm.ci.aarch64.AArch64.zr;
import org.graalvm.compiler.asm.AbstractAddress;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.aarch64.AArch64;
@ -274,7 +274,7 @@ public final class AArch64Address extends AbstractAddress {
/**
* @return immediate in correct representation for the given addressing mode. For example in
* case of <code>addressingMode ==IMMEDIATE_UNSCALED </code> the value will be returned
* as the 9bit signed representation.
* as the 9-bit signed representation.
*/
public int getImmediate() {
switch (addressingMode) {
@ -282,12 +282,15 @@ public final class AArch64Address extends AbstractAddress {
case IMMEDIATE_POST_INDEXED:
case IMMEDIATE_PRE_INDEXED:
// 9-bit signed value
assert NumUtil.isSignedNbit(9, immediate);
return immediate & NumUtil.getNbitNumberInt(9);
case IMMEDIATE_SCALED:
// Unsigned value can be returned as-is.
assert NumUtil.isUnsignedNbit(9, immediate);
return immediate;
case PC_LITERAL:
// 21-bit signed value, but lower 2 bits are always 0 and are shifted out.
assert NumUtil.isSignedNbit(19, immediate >> 2);
return (immediate >> 2) & NumUtil.getNbitNumberInt(19);
default:
throw GraalError.shouldNotReachHere("Should only be called for addressing modes that use immediate values.");
@ -356,4 +359,29 @@ public final class AArch64Address extends AbstractAddress {
}
}
/**
* Loads an address into Register r.
*
* @param masm the macro assembler.
* @param r general purpose register. May not be null.
*/
public void lea(AArch64MacroAssembler masm, Register r) {
switch (addressingMode) {
case IMMEDIATE_UNSCALED:
if (immediate == 0 && base.equals(r)) { // it's a nop
break;
}
masm.add(64, r, base, immediate);
break;
case REGISTER_OFFSET:
masm.add(64, r, base, offset);
break;
case PC_LITERAL: {
masm.mov(r, getImmediate());
break;
}
default:
throw GraalError.shouldNotReachHere();
}
}
}

View File

@ -111,7 +111,7 @@ import static jdk.vm.ci.aarch64.AArch64.zr;
import java.util.Arrays;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
import org.graalvm.compiler.debug.GraalError;
@ -347,6 +347,11 @@ public abstract class AArch64Assembler extends Assembler {
return reg.encoding << RnOffset;
}
private static int maskField(int sizeInBits, int n) {
assert NumUtil.isSignedNbit(sizeInBits, n);
return n & NumUtil.getNbitNumberInt(sizeInBits);
}
/**
* Enumeration of all different instruction kinds: General32/64 are the general instructions
* (integer, branch, etc.), for 32-, respectively 64-bit operands. FP32/64 is the encoding for
@ -448,7 +453,7 @@ public abstract class AArch64Assembler extends Assembler {
private static final int LoadStoreFpFlagOffset = 26;
private static final int LoadLiteralImmeOffset = 5;
private static final int LoadStorePairOp = 0b101_0_010 << 23;
private static final int LoadStorePairOp = 0b101_0 << 26;
@SuppressWarnings("unused") private static final int LoadStorePairPostIndexOp = 0b101_0_001 << 23;
@SuppressWarnings("unused") private static final int LoadStorePairPreIndexOp = 0b101_0_011 << 23;
private static final int LoadStorePairImm7Offset = 15;
@ -978,7 +983,9 @@ public abstract class AArch64Assembler extends Assembler {
}
/**
*
* Load Pair of Registers calculates an address from a base register value and an immediate
* offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from
* two registers.
*/
public void ldp(int size, Register rt, Register rt2, AArch64Address address) {
assert size == 32 || size == 64;
@ -996,10 +1003,18 @@ public abstract class AArch64Assembler extends Assembler {
}
private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) {
int memop = type.encoding | instr.encoding | address.getImmediate() << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
int scaledOffset = maskField(7, address.getImmediateRaw()); // LDP/STP use a 7-bit scaled
// offset
int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
switch (address.getAddressingMode()) {
case IMMEDIATE_UNSCALED:
emitInt(memop | LoadStorePairOp);
case IMMEDIATE_SCALED:
emitInt(memop | LoadStorePairOp | (0b010 << 23));
break;
case IMMEDIATE_POST_INDEXED:
emitInt(memop | LoadStorePairOp | (0b001 << 23));
break;
case IMMEDIATE_PRE_INDEXED:
emitInt(memop | LoadStorePairOp | (0b011 << 23));
break;
default:
throw GraalError.shouldNotReachHere("Unhandled addressing mode: " + address.getAddressingMode());
@ -1471,7 +1486,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param shiftType any type but ROR.
* @param imm must be in range 0 to size - 1.
*/
protected void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
public void adds(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
addSubShiftedInstruction(ADDS, dst, src1, src2, shiftType, imm, generalFromSize(size));
}
@ -1499,7 +1514,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param shiftType any type but ROR.
* @param imm must be in range 0 to size - 1.
*/
protected void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
public void subs(int size, Register dst, Register src1, Register src2, ShiftType shiftType, int imm) {
addSubShiftedInstruction(SUBS, dst, src1, src2, shiftType, imm, generalFromSize(size));
}
@ -1571,7 +1586,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param extendType defines how src2 is extended to the same size as src1.
* @param shiftAmt must be in range 0 to 4.
*/
protected void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
public void subs(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
assert !dst.equals(sp);
assert !src1.equals(zr);
assert !src2.equals(sp);
@ -1786,7 +1801,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param dst general purpose register. May not be null, zero-register or the stackpointer.
* @param src source register. May not be null, zero-register or the stackpointer.
*/
protected void rbit(int size, Register dst, Register src) {
public void rbit(int size, Register dst, Register src) {
dataProcessing1SourceOp(RBIT, dst, src, generalFromSize(size));
}
@ -1934,7 +1949,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param src2 general purpose register. May not be null or the stackpointer.
* @param src3 general purpose register. May not be null or the stackpointer.
*/
protected void smaddl(Register dst, Register src1, Register src2, Register src3) {
public void smaddl(Register dst, Register src1, Register src2, Register src3) {
assert !dst.equals(sp);
assert !src1.equals(sp);
assert !src2.equals(sp);

View File

@ -39,7 +39,7 @@ import static jdk.vm.ci.aarch64.AArch64.zr;
import org.graalvm.compiler.asm.AbstractAddress;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.aarch64.AArch64;
@ -196,6 +196,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
break;
case ADD_TO_INDEX:
newIndex = allowOverwrite ? index : additionalReg;
assert !newIndex.equals(sp) && !newIndex.equals(zr);
if (plan.needsScratch) {
mov(additionalReg, scaledDisplacement);
add(signExtendIndex ? 32 : 64, newIndex, index, additionalReg);
@ -206,6 +207,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
break;
case ADD_TO_BASE:
newBase = allowOverwrite ? base : additionalReg;
assert !newBase.equals(sp) && !newBase.equals(zr);
if (plan.needsScratch) {
mov(additionalReg, displacement);
add(64, newBase, base, additionalReg);
@ -411,6 +413,19 @@ public class AArch64MacroAssembler extends AArch64Assembler {
assert !firstMove;
}
/**
* Generates a 32-bit immediate move code sequence. The immediate may later be updated by
* HotSpot.
*
* @param dst general purpose register. May not be null, stackpointer or zero-register.
* @param imm
*/
public void movNarrowAddress(Register dst, long imm) {
assert (imm & 0xFFFF_FFFF_0000_0000L) == 0;
movz(64, dst, (int) (imm >>> 16), 16);
movk(64, dst, (int) (imm & 0xffff), 0);
}
/**
* @return Number of instructions necessary to load immediate into register.
*/
@ -455,6 +470,19 @@ public class AArch64MacroAssembler extends AArch64Assembler {
}
}
/**
* Loads a srcSize value from address into rt zero-extending it if necessary.
*
* @param srcSize size of memory read in bits. Must be 8, 16 or 32 and smaller or equal to
* targetSize.
* @param rt general purpose register. May not be null or stackpointer.
* @param address all addressing modes allowed. May not be null.
*/
@Override
public void ldr(int srcSize, Register rt, AArch64Address address) {
super.ldr(srcSize, rt, address);
}
/**
* Conditional move. dst = src1 if condition else src2.
*
@ -482,52 +510,47 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* dst = src1 + src2.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src1 general purpose register. May not be null or stackpointer.
* @param dst general purpose register. May not be null.
* @param src1 general purpose register. May not be null.
* @param src2 general purpose register. May not be null or stackpointer.
*/
public void add(int size, Register dst, Register src1, Register src2) {
super.add(size, dst, src1, src2, ShiftType.LSL, 0);
if (dst.equals(sp) || src1.equals(sp)) {
super.add(size, dst, src1, src2, ExtendType.UXTX, 0);
} else {
super.add(size, dst, src1, src2, ShiftType.LSL, 0);
}
}
/**
* dst = src1 + src2 and sets condition flags.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src1 general purpose register. May not be null or stackpointer.
* @param dst general purpose register. May not be null.
* @param src1 general purpose register. May not be null.
* @param src2 general purpose register. May not be null or stackpointer.
*/
public void adds(int size, Register dst, Register src1, Register src2) {
super.adds(size, dst, src1, src2, getNopExtendType(size), 0);
if (dst.equals(sp) || src1.equals(sp)) {
super.adds(size, dst, src1, src2, ExtendType.UXTX, 0);
} else {
super.adds(size, dst, src1, src2, ShiftType.LSL, 0);
}
}
/**
* dst = src1 - src2 and sets condition flags.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src1 general purpose register. May not be null or stackpointer.
* @param dst general purpose register. May not be null.
* @param src1 general purpose register. May not be null.
* @param src2 general purpose register. May not be null or stackpointer.
*/
public void subs(int size, Register dst, Register src1, Register src2) {
super.subs(size, dst, src1, src2, getNopExtendType(size), 0);
}
/**
* Returns the ExtendType for the given size that corresponds to a no-op.
*
* I.e. when doing add X0, X1, X2, the actual instruction has the form add X0, X1, X2 UXTX.
*
* @param size
*/
private static ExtendType getNopExtendType(int size) {
if (size == 64) {
return ExtendType.UXTX;
} else if (size == 32) {
return ExtendType.UXTW;
if (dst.equals(sp) || src1.equals(sp)) {
super.subs(size, dst, src1, src2, ExtendType.UXTX, 0);
} else {
throw GraalError.shouldNotReachHere("No-op ");
super.subs(size, dst, src1, src2, ShiftType.LSL, 0);
}
}
@ -535,12 +558,16 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* dst = src1 - src2.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src1 general purpose register. May not be null or stackpointer.
* @param dst general purpose register. May not be null.
* @param src1 general purpose register. May not be null.
* @param src2 general purpose register. May not be null or stackpointer.
*/
public void sub(int size, Register dst, Register src1, Register src2) {
super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
if (dst.equals(sp) || src1.equals(sp)) {
super.sub(size, dst, src1, src2, ExtendType.UXTX, 0);
} else {
super.sub(size, dst, src1, src2, ShiftType.LSL, 0);
}
}
/**
@ -590,16 +617,26 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* dst = src + immediate.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src general purpose register. May not be null or stackpointer.
* @param immediate arithmetic immediate
* @param dst general purpose register. May not be null or zero-register.
* @param src general purpose register. May not be null or zero-register.
* @param immediate 32-bit signed int
*/
@Override
public void add(int size, Register dst, Register src, int immediate) {
assert (!dst.equals(zr) && !src.equals(zr));
if (immediate < 0) {
sub(size, dst, src, -immediate);
} else if (!(dst.equals(src) && immediate == 0)) {
super.add(size, dst, src, immediate);
} else if (isAimm(immediate)) {
if (!(dst.equals(src) && immediate == 0)) {
super.add(size, dst, src, immediate);
}
} else if (immediate >= -(1 << 24) && immediate < (1 << 24)) {
super.add(size, dst, src, immediate & -(1 << 12));
super.add(size, dst, dst, immediate & ((1 << 12) - 1));
} else {
assert !dst.equals(src);
mov(dst, immediate);
add(size, src, dst, dst);
}
}
@ -613,6 +650,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
*/
@Override
public void adds(int size, Register dst, Register src, int immediate) {
assert (!dst.equals(sp) && !src.equals(zr));
if (immediate < 0) {
subs(size, dst, src, -immediate);
} else if (!(dst.equals(src) && immediate == 0)) {
@ -624,16 +662,26 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* dst = src - immediate.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stackpointer.
* @param src general purpose register. May not be null or stackpointer.
* @param immediate arithmetic immediate
* @param dst general purpose register. May not be null or zero-register.
* @param src general purpose register. May not be null or zero-register.
* @param immediate 32-bit signed int
*/
@Override
public void sub(int size, Register dst, Register src, int immediate) {
assert (!dst.equals(zr) && !src.equals(zr));
if (immediate < 0) {
add(size, dst, src, -immediate);
} else if (!dst.equals(src) || immediate != 0) {
super.sub(size, dst, src, immediate);
} else if (isAimm(immediate)) {
if (!(dst.equals(src) && immediate == 0)) {
super.sub(size, dst, src, immediate);
}
} else if (immediate >= -(1 << 24) && immediate < (1 << 24)) {
super.sub(size, dst, src, immediate & -(1 << 12));
super.sub(size, dst, dst, immediate & ((1 << 12) - 1));
} else {
assert !dst.equals(src);
mov(dst, immediate);
sub(size, src, dst, dst);
}
}
@ -647,10 +695,11 @@ public class AArch64MacroAssembler extends AArch64Assembler {
*/
@Override
public void subs(int size, Register dst, Register src, int immediate) {
assert (!dst.equals(sp) && !src.equals(zr));
if (immediate < 0) {
adds(size, dst, src, -immediate);
} else if (!dst.equals(src) || immediate != 0) {
super.sub(size, dst, src, immediate);
super.subs(size, dst, src, immediate);
}
}
@ -675,6 +724,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* @param src2 general purpose register. May not be null or the stackpointer.
*/
public void umulh(int size, Register dst, Register src1, Register src2) {
assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp));
assert size == 32 || size == 64;
if (size == 64) {
super.umulh(dst, src1, src2);
@ -695,6 +745,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* @param src2 general purpose register. May not be null or the stackpointer.
*/
public void smulh(int size, Register dst, Register src1, Register src2) {
assert (!dst.equals(sp) && !src1.equals(sp) && !src2.equals(sp));
assert size == 32 || size == 64;
if (size == 64) {
super.smulh(dst, src1, src2);
@ -715,6 +766,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* @param d denominator. General purpose register. Divisor May not be null or the stackpointer.
*/
public void rem(int size, Register dst, Register n, Register d) {
assert (!dst.equals(sp) && !n.equals(sp) && !d.equals(sp));
// There is no irem or similar instruction. Instead we use the relation:
// n % d = n - Floor(n / d) * d if nd >= 0
// n % d = n - Ceil(n / d) * d else
@ -940,16 +992,14 @@ public class AArch64MacroAssembler extends AArch64Assembler {
/**
* Sign-extend value from src into dst.
*
* @param destSize destination register size. Has to be 32 or 64.
* @param srcSize source register size. May be 8, 16 or 32 and smaller than destSize.
* @param destSize destination register size. Must be 32 or 64.
* @param srcSize source register size. Must be smaller than destSize.
* @param dst general purpose register. May not be null, stackpointer or zero-register.
* @param src general purpose register. May not be null, stackpointer or zero-register.
*/
public void sxt(int destSize, int srcSize, Register dst, Register src) {
assert (destSize == 32 || destSize == 64) && srcSize < destSize;
assert srcSize == 8 || srcSize == 16 || srcSize == 32;
int[] srcSizeValues = {7, 15, 31};
super.sbfm(destSize, dst, src, 0, srcSizeValues[NumUtil.log2Ceil(srcSize / 8)]);
assert (srcSize < destSize && srcSize > 0);
super.sbfm(destSize, dst, src, 0, srcSize - 1);
}
/**
@ -1078,6 +1128,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* @param y general purpose register. May not be null or stackpointer.
*/
public void cmp(int size, Register x, Register y) {
assert size == 32 || size == 64;
super.subs(size, zr, x, y, ShiftType.LSL, 0);
}
@ -1089,6 +1140,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
* @param y comparison immediate, {@link #isComparisonImmediate(long)} has to be true for it.
*/
public void cmp(int size, Register x, int y) {
assert size == 32 || size == 64;
if (y < 0) {
super.adds(size, zr, x, -y);
} else {
@ -1108,6 +1160,54 @@ public class AArch64MacroAssembler extends AArch64Assembler {
super.ands(size, dst, x, y, ShiftType.LSL, 0);
}
/**
* Sets overflow flag according to result of x * y.
*
* @param size register size. Has to be 32 or 64.
* @param dst general purpose register. May not be null or stack-pointer.
* @param x general purpose register. May not be null or stackpointer.
* @param y general purpose register. May not be null or stackpointer.
*/
public void mulvs(int size, Register dst, Register x, Register y) {
try (ScratchRegister sc1 = getScratchRegister();
ScratchRegister sc2 = getScratchRegister()) {
switch (size) {
case 64: {
// Be careful with registers: it's possible that x, y, and dst are the same
// register.
Register rscratch1 = sc1.getRegister();
Register rscratch2 = sc2.getRegister();
mul(64, rscratch1, x, y); // Result bits 0..63
smulh(64, rscratch2, x, y); // Result bits 64..127
// Top is pure sign ext
subs(64, zr, rscratch2, rscratch1, ShiftType.ASR, 63);
// Copy all 64 bits of the result into dst
mov(64, dst, rscratch1);
mov(rscratch1, 0x80000000);
// Develop 0 (EQ), or 0x80000000 (NE)
cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE);
cmp(32, rscratch1, 1);
// 0x80000000 - 1 => VS
break;
}
case 32: {
Register rscratch1 = sc1.getRegister();
smaddl(rscratch1, x, y, zr);
// Copy the low 32 bits of the result into dst
mov(32, dst, rscratch1);
subs(64, zr, rscratch1, rscratch1, ExtendType.SXTW, 0);
// NE => overflow
mov(rscratch1, 0x80000000);
// Develop 0 (EQ), or 0x80000000 (NE)
cmov(32, rscratch1, rscratch1, zr, ConditionFlag.NE);
cmp(32, rscratch1, 1);
// 0x80000000 - 1 => VS
break;
}
}
}
}
/**
* When patching up Labels we have to know what kind of code to generate.
*/
@ -1353,7 +1453,8 @@ public class AArch64MacroAssembler extends AArch64Assembler {
super.b(branchOffset, branch);
break;
case JUMP_ADDRESS:
emitInt(jumpTarget, branch);
int offset = instruction >>> PatchLabelKind.INFORMATION_OFFSET;
emitInt(jumpTarget - offset, branch);
break;
case BRANCH_NONZERO:
case BRANCH_ZERO: {
@ -1404,4 +1505,14 @@ public class AArch64MacroAssembler extends AArch64Assembler {
public AbstractAddress getPlaceholder(int instructionStartPosition) {
return AArch64Address.PLACEHOLDER;
}
/**
* Loads an address into Register d.
*
* @param d general purpose register. May not be null.
* @param a AArch64Address the address of an operand.
*/
public void lea(Register d, AArch64Address a) {
a.lea(this, d);
}
}

View File

@ -65,6 +65,18 @@ public final class AMD64Address extends AbstractAddress {
this(base, Register.None, Scale.Times1, displacement);
}
/**
* Creates an {@link AMD64Address} with given base and index registers, scaling and 0
* displacement.
*
* @param base the base register
* @param index the index register
* @param scale the scaling factor
*/
public AMD64Address(Register base, Register index, Scale scale) {
this(base, index, scale, 0, -1);
}
/**
* Creates an {@link AMD64Address} with given base and index registers, scaling and
* displacement. This is the most general constructor.

View File

@ -22,10 +22,10 @@
*/
package org.graalvm.compiler.asm.amd64;
import static org.graalvm.compiler.asm.NumUtil.isByte;
import static org.graalvm.compiler.asm.NumUtil.isInt;
import static org.graalvm.compiler.asm.NumUtil.isShiftCount;
import static org.graalvm.compiler.asm.NumUtil.isUByte;
import static org.graalvm.compiler.core.common.NumUtil.isByte;
import static org.graalvm.compiler.core.common.NumUtil.isInt;
import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
import static org.graalvm.compiler.core.common.NumUtil.isUByte;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
@ -58,7 +58,7 @@ import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import jdk.vm.ci.amd64.AMD64;
@ -2494,6 +2494,24 @@ public class AMD64Assembler extends Assembler {
emitByte(0xC0 | encode);
}
void pcmpestri(Register dst, AMD64Address src, int imm8) {
assert supports(CPUFeature.SSE4_2);
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
emitByte(0x61);
emitOperandHelper(dst, src, 0);
emitByte(imm8);
}
void pcmpestri(Register dst, Register src, int imm8) {
assert supports(CPUFeature.SSE4_2);
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
emitByte(0x61);
emitByte(0xC0 | encode);
emitByte(imm8);
}
public final void push(Register src) {
int encode = prefixAndEncode(src.encoding);
emitByte(0x50 | encode);
@ -2633,6 +2651,16 @@ public class AMD64Assembler extends Assembler {
emitByte(imm8);
}
public final void psrldq(Register dst, int imm8) {
assert isUByte(imm8) : "invalid value";
assert dst.getRegisterCategory().equals(AMD64.XMM);
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
int encode = simdPrefixAndEncode(AMD64.xmm3, dst, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
emitByte(0x73);
emitByte(0xC0 | encode);
emitByte(imm8);
}
public final void pshufd(Register dst, Register src, int imm8) {
assert isUByte(imm8) : "invalid value";
assert dst.getRegisterCategory().equals(AMD64.XMM) && src.getRegisterCategory().equals(AMD64.XMM);
@ -3322,6 +3350,13 @@ public class AMD64Assembler extends Assembler {
}
}
public final void movdl(Register dst, AMD64Address src) {
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
emitByte(0x6E);
emitOperandHelper(dst, src, 0);
}
public final void movddup(Register dst, Register src) {
assert supports(CPUFeature.SSE3);
assert dst.getRegisterCategory().equals(AMD64.XMM);

View File

@ -22,11 +22,17 @@
*/
package org.graalvm.compiler.asm.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 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;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
@ -138,6 +144,10 @@ public class AMD64MacroAssembler extends AMD64Assembler {
cmpq(src1, src2);
}
public final void decrementl(Register reg) {
decrementl(reg, 1);
}
public final void decrementl(Register reg, int value) {
if (value == Integer.MIN_VALUE) {
subl(reg, value);
@ -321,4 +331,434 @@ public class AMD64MacroAssembler extends AMD64Assembler {
movdbl(dest, tmp);
addq(AMD64.rsp, AMD64Kind.DOUBLE.getSizeInBytes());
}
// IndexOf for constant substrings with size >= 8 chars
// which don't need to be loaded through stack.
public void stringIndexofC8(Register str1, Register str2,
Register cnt1, Register cnt2,
int intCnt2, 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.
movdqu(vec, new AMD64Address(str2, 0));
movl(cnt2, intCnt2);
movq(result, str1); // string addr
if (intCnt2 > 8) {
jmpb(scanToSubstr);
// Reload substr for rescan, this code
// is executed only for large substrings (> 8 chars)
bind(reloadSubstr);
movdqu(vec, new AMD64Address(str2, 0));
negq(cnt2); // Jumped here with negative cnt2, convert to positive
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
subl(cnt1, cnt2);
addl(cnt1, intCnt2);
movl(cnt2, intCnt2); // Now restore cnt2
decrementl(cnt1, 1); // Shift to next element
cmpl(cnt1, cnt2);
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
addq(result, 2);
} // (int_cnt2 > 8)
// Scan string for start of substr in 16-byte vectors
bind(scanToSubstr);
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
jccb(ConditionFlag.Below, foundCandidate); // CF == 1
subl(cnt1, 8);
jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string
cmpl(cnt1, cnt2);
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
addq(result, 16);
jmpb(scanToSubstr);
// Found a potential substr
bind(foundCandidate);
// Matched whole vector if first element matched (tmp(rcx) == 0).
if (intCnt2 == 8) {
jccb(ConditionFlag.Overflow, retFound); // OF == 1
} else { // int_cnt2 > 8
jccb(ConditionFlag.Overflow, foundSubstr);
}
// After pcmpestri tmp(rcx) contains matched element index
// Compute start addr of substr
leaq(result, new AMD64Address(result, tmp, Scale.Times2, 0));
// Make sure string is still long enough
subl(cnt1, tmp);
cmpl(cnt1, cnt2);
if (intCnt2 == 8) {
jccb(ConditionFlag.GreaterEqual, scanToSubstr);
} else { // int_cnt2 > 8
jccb(ConditionFlag.GreaterEqual, matchSubstrHead);
}
// Left less then substring.
bind(retNotFound);
movl(result, -1);
jmpb(exit);
if (intCnt2 > 8) {
// This code is optimized for the case when whole substring
// is matched if its head is matched.
bind(matchSubstrHead);
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
// Reload only string if does not match
jccb(ConditionFlag.NoOverflow, reloadStr); // OF == 0
Label contScanSubstr = new Label();
// Compare the rest of substring (> 8 chars).
bind(foundSubstr);
// First 8 chars are already matched.
negq(cnt2);
addq(cnt2, 8);
bind(scanSubstr);
subl(cnt1, 8);
cmpl(cnt2, -8); // Do not read beyond substring
jccb(ConditionFlag.LessEqual, contScanSubstr);
// Back-up strings to avoid reading beyond substring:
// cnt1 = cnt1 - cnt2 + 8
addl(cnt1, cnt2); // cnt2 is negative
addl(cnt1, 8);
movl(cnt2, 8);
negq(cnt2);
bind(contScanSubstr);
if (intCnt2 < 1024 * 1024 * 1024) {
movdqu(vec, new AMD64Address(str2, cnt2, Scale.Times2, intCnt2 * 2));
pcmpestri(vec, new AMD64Address(result, cnt2, Scale.Times2, intCnt2 * 2), 0x0d);
} else {
// calculate index in register to avoid integer overflow (int_cnt2*2)
movl(tmp, intCnt2);
addq(tmp, cnt2);
movdqu(vec, new AMD64Address(str2, tmp, Scale.Times2, 0));
pcmpestri(vec, new AMD64Address(result, tmp, Scale.Times2, 0), 0x0d);
}
// Need to reload strings pointers if not matched whole vector
jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0
addq(cnt2, 8);
jcc(ConditionFlag.Negative, scanSubstr);
// Fall through if found full substring
} // (int_cnt2 > 8)
bind(retFound);
// Found result if we matched full small substring.
// Compute substr offset
subq(result, str1);
shrl(result, 1); // index
bind(exit);
} // string_indexofC8
// Small strings are loaded through stack if they cross page boundary.
public void stringIndexOf(Register str1, Register str2,
Register cnt1, Register cnt2,
int intCnt2, Register result,
Register vec, Register tmp, int vmPageSize) {
//
// 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();
movq(tmp, rsp); // save old SP
if (intCnt2 > 0) { // small (< 8 chars) constant substring
if (intCnt2 == 1) { // One char
movzwl(result, new AMD64Address(str2, 0));
movdl(vec, result); // move 32 bits
} else if (intCnt2 == 2) { // Two chars
movdl(vec, new AMD64Address(str2, 0)); // move 32 bits
} else if (intCnt2 == 4) { // Four chars
movq(vec, new AMD64Address(str2, 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.
movdqu(vec, new AMD64Address(str2, (intCnt2 * 2) - 16));
psrldq(vec, 16 - (intCnt2 * 2));
}
} else { // not constant substring
cmpl(cnt2, 8);
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";
movl(result, str2); // We need only low 32 bits
andl(result, (vmPageSize - 1));
cmpl(result, (vmPageSize - 16));
jccb(ConditionFlag.BelowEqual, checkStr);
// Move small strings to stack to allow load 16 bytes into vec.
subq(rsp, 16);
int stackOffset = wordSize - 2;
push(cnt2);
bind(copySubstr);
movzwl(result, new AMD64Address(str2, cnt2, Scale.Times2, -2));
movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result);
decrementl(cnt2, 1);
jccb(ConditionFlag.NotZero, copySubstr);
pop(cnt2);
movq(str2, rsp); // New substring address
} // non constant
bind(checkStr);
cmpl(cnt1, 8);
jccb(ConditionFlag.AboveEqual, bigStrings);
// Check cross page boundary.
movl(result, str1); // We need only low 32 bits
andl(result, (vmPageSize - 1));
cmpl(result, (vmPageSize - 16));
jccb(ConditionFlag.BelowEqual, bigStrings);
subq(rsp, 16);
int stackOffset = -2;
if (intCnt2 < 0) { // not constant
push(cnt2);
stackOffset += wordSize;
}
movl(cnt2, cnt1);
bind(copyStr);
movzwl(result, new AMD64Address(str1, cnt2, Scale.Times2, -2));
movw(new AMD64Address(rsp, cnt2, Scale.Times2, stackOffset), result);
decrementl(cnt2, 1);
jccb(ConditionFlag.NotZero, copyStr);
if (intCnt2 < 0) { // not constant
pop(cnt2);
}
movq(str1, rsp); // New string address
bind(bigStrings);
// Load substring.
if (intCnt2 < 0) { // -1
movdqu(vec, new AMD64Address(str2, 0));
push(cnt2); // substr count
push(str2); // substr addr
push(str1); // string addr
} else {
// Small (< 8 chars) constant substrings are loaded already.
movl(cnt2, intCnt2);
}
push(tmp); // original SP
// Finished loading
// ========================================================
// Start search
//
movq(result, str1); // string addr
if (intCnt2 < 0) { // Only for non constant substring
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)
bind(reloadSubstr);
movq(str2, new AMD64Address(rsp, 2 * wordSize));
movl(cnt2, new AMD64Address(rsp, 3 * wordSize));
movdqu(vec, new AMD64Address(str2, 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.
subq(str1, result); // Restore counter
shrl(str1, 1);
addl(cnt1, str1);
decrementl(cnt1); // Shift to next element
cmpl(cnt1, cnt2);
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
addq(result, 2);
} // non constant
// Scan string for start of substr in 16-byte vectors
bind(scanToSubstr);
assert cnt1.equals(rdx) && cnt2.equals(rax) && tmp.equals(rcx) : "pcmpestri";
pcmpestri(vec, new AMD64Address(result, 0), 0x0d);
jccb(ConditionFlag.Below, foundCandidate); // CF == 1
subl(cnt1, 8);
jccb(ConditionFlag.LessEqual, retNotFound); // Scanned full string
cmpl(cnt1, cnt2);
jccb(ConditionFlag.Negative, retNotFound); // Left less then substring
addq(result, 16);
bind(adjustStr);
cmpl(cnt1, 8); // Do not read beyond string
jccb(ConditionFlag.GreaterEqual, scanToSubstr);
// Back-up string to avoid reading beyond string.
leaq(result, new AMD64Address(result, cnt1, Scale.Times2, -16));
movl(cnt1, 8);
jmpb(scanToSubstr);
// Found a potential substr
bind(foundCandidate);
// After pcmpestri tmp(rcx) contains matched element index
// Make sure string is still long enough
subl(cnt1, tmp);
cmpl(cnt1, cnt2);
jccb(ConditionFlag.GreaterEqual, foundSubstr);
// Left less then substring.
bind(retNotFound);
movl(result, -1);
jmpb(cleanup);
bind(foundSubstr);
// Compute start addr of substr
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.
cmpl(tmp, 8 - intCnt2);
jccb(ConditionFlag.Greater, adjustStr);
// Fall through if matched whole substring.
} else { // non constant
assert intCnt2 == -1 : "should be != 0";
addl(tmp, cnt2);
// Found result if we matched whole substring.
cmpl(tmp, 8);
jccb(ConditionFlag.LessEqual, retFound);
// Repeat search for small substring (<= 8 chars)
// from new point 'str1' without reloading substring.
cmpl(cnt2, 8);
// Have to check that we don't read beyond string.
jccb(ConditionFlag.LessEqual, adjustStr);
Label checkNext = new Label();
Label contScanSubstr = new Label();
Label retFoundLong = new Label();
// Compare the rest of substring (> 8 chars).
movq(str1, result);
cmpl(tmp, cnt2);
// First 8 chars are already matched.
jccb(ConditionFlag.Equal, checkNext);
bind(scanSubstr);
pcmpestri(vec, new AMD64Address(str1, 0), 0x0d);
// Need to reload strings pointers if not matched whole vector
jcc(ConditionFlag.NoOverflow, reloadSubstr); // OF == 0
bind(checkNext);
subl(cnt2, 8);
jccb(ConditionFlag.LessEqual, retFoundLong); // Found full substring
addq(str1, 16);
addq(str2, 16);
subl(cnt1, 8);
cmpl(cnt2, 8); // Do not read beyond substring
jccb(ConditionFlag.GreaterEqual, contScanSubstr);
// Back-up strings to avoid reading beyond substring.
leaq(str2, new AMD64Address(str2, cnt2, Scale.Times2, -16));
leaq(str1, new AMD64Address(str1, cnt2, Scale.Times2, -16));
subl(cnt1, cnt2);
movl(cnt2, 8);
addl(cnt1, 8);
bind(contScanSubstr);
movdqu(vec, new AMD64Address(str2, 0));
jmpb(scanSubstr);
bind(retFoundLong);
movq(str1, new AMD64Address(rsp, wordSize));
} // non constant
bind(retFound);
// Compute substr offset
subq(result, str1);
shrl(result, 1); // index
bind(cleanup);
pop(rsp); // restore SP
}
}

View File

@ -135,8 +135,8 @@ import java.util.Map;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.code.Register;

View File

@ -26,8 +26,6 @@ import static org.graalvm.compiler.core.common.CompilationRequestIdentifier.asCo
import java.lang.reflect.Method;
import org.junit.Assert;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.code.DisassemblerProvider;
@ -36,10 +34,12 @@ import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.Debug.Scope;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.runtime.RuntimeProvider;
import org.graalvm.compiler.serviceprovider.GraalServices;
import org.graalvm.compiler.test.AddExports;
import org.graalvm.compiler.test.GraalTest;
import org.junit.Assert;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.CodeCacheProvider;
@ -52,6 +52,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCI;
import jdk.vm.ci.runtime.JVMCIBackend;
@AddExports("jdk.internal.vm.ci/jdk.vm.ci.runtime")
public abstract class AssemblerTest extends GraalTest {
private final MetaAccessProvider metaAccess;
@ -62,6 +63,14 @@ public abstract class AssemblerTest extends GraalTest {
byte[] generateCode(CompilationResult compResult, TargetDescription target, RegisterConfig registerConfig, CallingConvention cc);
}
/**
* Gets the initial option values provided by the Graal runtime. These are option values
* typically parsed from the command line.
*/
public static OptionValues getInitialOptions() {
return Graal.getRequiredCapability(OptionValues.class);
}
public AssemblerTest() {
JVMCIBackend providers = JVMCI.getRuntime().getHostJVMCIBackend();
this.metaAccess = providers.getMetaAccess();
@ -79,7 +88,8 @@ public abstract class AssemblerTest extends GraalTest {
try (Scope s = Debug.scope("assembleMethod", method, codeCache)) {
RegisterConfig registerConfig = codeCache.getRegisterConfig();
CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, new StructuredGraph(method, AllowAssumptions.NO, compilationId), null).getCallingConvention();
StructuredGraph graph = new StructuredGraph.Builder(getInitialOptions()).method(method).compilationId(compilationId).build();
CallingConvention cc = backend.newLIRGenerationResult(compilationId, null, null, graph, null).getCallingConvention();
CompilationResult compResult = new CompilationResult();
byte[] targetCode = test.generateCode(compResult, codeCache.getTarget(), registerConfig, cc);

View File

@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.asm;
import org.graalvm.compiler.core.common.NumUtil;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

View File

@ -34,6 +34,7 @@ import java.util.List;
import java.util.Objects;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.util.EconomicSet;
import jdk.vm.ci.code.DebugInfo;
import jdk.vm.ci.code.StackSlot;
@ -363,9 +364,10 @@ public class CompilationResult {
*
* @param accessedFields the collected set of fields accessed during compilation
*/
public void setFields(Collection<ResolvedJavaField> accessedFields) {
assert accessedFields != null;
fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
public void setFields(EconomicSet<ResolvedJavaField> accessedFields) {
if (accessedFields != null) {
fields = accessedFields.toArray(new ResolvedJavaField[accessedFields.size()]);
}
}
/**

View File

@ -22,7 +22,7 @@
*/
package org.graalvm.compiler.code;
import org.graalvm.compiler.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.PermanentBailoutException;
/**
* Represents a bailout exception with a stack trace in terms of the Java source being compiled

View File

@ -90,6 +90,7 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
gen.setResult(this, new AArch64AddressValue(kind, baseValue, indexValue, displacement, scaled, addressingMode));
}
@Override
public ValueNode getBase() {
return base;
}
@ -102,6 +103,7 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
this.base = base;
}
@Override
public ValueNode getIndex() {
return index;
}
@ -121,4 +123,9 @@ public class AArch64AddressNode extends AddressNode implements LIRLowerable {
public void setDisplacement(int displacement) {
this.displacement = displacement;
}
@Override
public long getMaxConstantDisplacement() {
return Long.MAX_VALUE;
}
}

View File

@ -23,13 +23,16 @@
package org.graalvm.compiler.core.aarch64;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.aarch64.AArch64Kind.DWORD;
import static jdk.vm.ci.aarch64.AArch64Kind.QWORD;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.BSR;
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CLZ;
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CTZ;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.FloatConvert;
@ -41,12 +44,12 @@ import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp;
import org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode;
import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
import org.graalvm.compiler.lir.aarch64.AArch64ReinterpretOp;
import org.graalvm.compiler.lir.aarch64.AArch64SignExtendOp;
import org.graalvm.compiler.lir.aarch64.AArch64Unary;
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
import jdk.vm.ci.aarch64.AArch64Kind;
@ -91,11 +94,30 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
}
}
protected Value emitExtendMemory(boolean isSigned, AArch64Kind memoryKind, int resultBits, AArch64AddressValue address, LIRFrameState state) {
// Issue a zero extending load of the proper bit size and set the result to
// the proper kind.
Variable result = getLIRGen().newVariable(LIRKind.value(resultBits == 32 ? AArch64Kind.DWORD : AArch64Kind.QWORD));
int targetSize = resultBits <= 32 ? 32 : 64;
switch (memoryKind) {
case BYTE:
case WORD:
case DWORD:
case QWORD:
getLIRGen().append(new AArch64Unary.MemoryOp(isSigned, targetSize,
memoryKind.getSizeInBytes() * 8, result, address, state));
break;
default:
throw GraalError.shouldNotReachHere();
}
return result;
}
@Override
public Value emitMul(Value a, Value b, boolean setFlags) {
// TODO (das) setFlags handling - should be handled higher up. Ask for ideas at mailing list
assert !setFlags : "Set flags on multiplication is not supported";
return emitBinary(LIRKind.combine(a, b), getOpCode(a, AArch64ArithmeticOp.MUL, AArch64ArithmeticOp.FMUL), true, a, b);
AArch64ArithmeticOp intOp = setFlags ? AArch64ArithmeticOp.MULVS : AArch64ArithmeticOp.MUL;
return emitBinary(LIRKind.combine(a, b), getOpCode(a, intOp, AArch64ArithmeticOp.FMUL), true, a, b);
}
@Override
@ -223,7 +245,7 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
@Override
public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
assert fromBits <= toBits && (toBits == 32 || toBits == 64);
assert fromBits <= toBits && toBits <= 64;
if (fromBits == toBits) {
return inputVal;
}
@ -235,11 +257,21 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
@Override
public Value emitSignExtend(Value inputVal, int fromBits, int toBits) {
assert fromBits <= toBits && (toBits == 32 || toBits == 64);
LIRKind resultKind = getResultLirKind(toBits, inputVal);
assert fromBits <= toBits && toBits <= 64;
if (fromBits == toBits) {
return inputVal;
} else if (isJavaConstant(inputVal)) {
JavaConstant javaConstant = asJavaConstant(inputVal);
long constant;
if (javaConstant.isNull()) {
constant = 0;
} else {
constant = javaConstant.asLong();
}
int shiftCount = QWORD.getSizeInBytes() * 8 - fromBits;
return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
}
LIRKind resultKind = getResultLirKind(toBits, inputVal);
Variable result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new AArch64SignExtendOp(result, getLIRGen().asAllocatable(inputVal), fromBits, toBits));
return result;
@ -249,7 +281,8 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
if (resultBitSize == 64) {
return LIRKind.combine(inputValues).changeType(QWORD);
} else {
assert resultBitSize == 32;
// FIXME: I have no idea what this assert was ever for
// assert resultBitSize == 32;
return LIRKind.combine(inputValues).changeType(DWORD);
}
}
@ -352,8 +385,8 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
}
@Override
public Value emitBitScanForward(Value inputVal) {
return emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode.BSF, inputVal);
public Variable emitBitScanForward(Value value) {
throw GraalError.unimplemented();
}
@Override
@ -362,27 +395,23 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
}
@Override
public Value emitBitScanReverse(Value inputVal) {
// TODO (das) old implementation said to use emitCountLeadingZeros instead - need extra node
// for that though
return emitBitManipulation(BitManipulationOpCode.BSR, inputVal);
public Value emitBitScanReverse(Value value) {
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
getLIRGen().append(new AArch64BitManipulationOp(BSR, result, getLIRGen().asAllocatable(value)));
return result;
}
@Override
public Value emitCountLeadingZeros(Value value) {
return emitBitManipulation(BitManipulationOpCode.CLZ, value);
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
getLIRGen().append(new AArch64BitManipulationOp(CLZ, result, getLIRGen().asAllocatable(value)));
return result;
}
@Override
public Value emitCountTrailingZeros(Value value) {
throw GraalError.unimplemented();
}
private Variable emitBitManipulation(AArch64BitManipulationOp.BitManipulationOpCode op, Value inputVal) {
assert isNumericInteger(inputVal.getPlatformKind());
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
getLIRGen().append(new AArch64BitManipulationOp(op, result, input));
Variable result = getLIRGen().newVariable(LIRKind.combine(value).changeType(AArch64Kind.DWORD));
getLIRGen().append(new AArch64BitManipulationOp(CTZ, result, getLIRGen().asAllocatable(value)));
return result;
}

View File

@ -42,11 +42,14 @@ import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.aarch64.AArch64AddressValue;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
import org.graalvm.compiler.lir.aarch64.AArch64ArrayEqualsOp;
import org.graalvm.compiler.lir.aarch64.AArch64ByteSwapOp;
import org.graalvm.compiler.lir.aarch64.AArch64Compare;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.BranchOp;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.CondMoveOp;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move;
import org.graalvm.compiler.lir.aarch64.AArch64Move.CompareAndSwapOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
@ -56,6 +59,7 @@ import org.graalvm.compiler.lir.gen.LIRGenerator;
import org.graalvm.compiler.phases.util.Providers;
import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaConstant;
@ -121,8 +125,19 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
}
@Override
public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
Variable prevValue = newVariable(expectedValue.getValueKind());
Variable scratch = newVariable(LIRKind.value(AArch64Kind.DWORD));
append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
assert trueValue.getValueKind().equals(falseValue.getValueKind());
Variable result = newVariable(trueValue.getValueKind());
append(new CondMoveOp(result, ConditionFlag.EQ, asAllocatable(trueValue), asAllocatable(falseValue)));
return result;
}
@Override
public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
Variable result = newVariable(newValue.getValueKind());
Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
return result;
@ -271,13 +286,25 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
boolean mirrored;
AArch64Kind kind = (AArch64Kind) cmpKind;
if (kind.isInteger()) {
if (LIRValueUtil.isVariable(b)) {
left = load(b);
right = loadNonConst(a);
Value aExt = a;
Value bExt = b;
int compareBytes = cmpKind.getSizeInBytes();
// AArch64 compares 32 or 64 bits: sign extend a and b as required.
if (compareBytes < a.getPlatformKind().getSizeInBytes()) {
aExt = arithmeticLIRGen.emitSignExtend(a, compareBytes * 8, 64);
}
if (compareBytes < b.getPlatformKind().getSizeInBytes()) {
bExt = arithmeticLIRGen.emitSignExtend(b, compareBytes * 8, 64);
}
if (LIRValueUtil.isVariable(bExt)) {
left = load(bExt);
right = loadNonConst(aExt);
mirrored = true;
} else {
left = load(a);
right = loadNonConst(b);
left = load(aExt);
right = loadNonConst(bExt);
mirrored = false;
}
append(new AArch64Compare.CompareOp(left, loadNonCompareConst(right)));
@ -367,7 +394,7 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
public Variable emitIntegerTestMove(Value left, Value right, Value trueValue, Value falseValue) {
assert ((AArch64Kind) left.getPlatformKind()).isInteger() && ((AArch64Kind) right.getPlatformKind()).isInteger();
assert ((AArch64Kind) trueValue.getPlatformKind()).isInteger() && ((AArch64Kind) falseValue.getPlatformKind()).isInteger();
((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(trueValue.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
((AArch64ArithmeticLIRGenerator) getArithmetic()).emitBinary(left.getValueKind(), AArch64ArithmeticOp.ANDS, true, left, right);
Variable result = newVariable(trueValue.getValueKind());
append(new CondMoveOp(result, ConditionFlag.EQ, load(trueValue), load(falseValue)));
return result;
@ -385,22 +412,21 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
@Override
protected void emitTableSwitch(int lowKey, LabelRef defaultTarget, LabelRef[] targets, Value key) {
// Make copy of key since the TableSwitch destroys its input.
Variable tmp = emitMove(key);
Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
append(new AArch64ControlFlow.TableSwitchOp(lowKey, defaultTarget, targets, tmp, scratch));
append(new TableSwitchOp(lowKey, defaultTarget, targets, key, newVariable(LIRKind.value(target().arch.getWordKind())), newVariable(key.getValueKind())));
}
@Override
public Variable emitByteSwap(Value operand) {
// TODO (das) Do not generate until we support vector instructions
throw GraalError.unimplemented("Do not generate until we support vector instructions");
public Variable emitByteSwap(Value input) {
Variable result = newVariable(LIRKind.combine(input));
append(new AArch64ByteSwapOp(result, input));
return result;
}
@Override
public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
// TODO (das) Do not generate until we support vector instructions
throw GraalError.unimplemented("Do not generate until we support vector instructions");
Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
append(new AArch64ArrayEqualsOp(this, kind, result, array1, array2, asAllocatable(length)));
return result;
}
@Override
@ -443,4 +469,6 @@ public abstract class AArch64LIRGenerator extends LIRGenerator {
public void emitPause() {
append(new AArch64PauseOp());
}
public abstract void emitCCall(long address, CallingConvention nativeCallingConvention, Value[] args);
}

View File

@ -86,21 +86,25 @@ public class AArch64MoveFactory implements MoveFactory {
}
@Override
public boolean canInlineConstant(JavaConstant c) {
switch (c.getJavaKind()) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
return AArch64MacroAssembler.isMovableImmediate(c.asInt());
case Long:
return AArch64MacroAssembler.isMovableImmediate(c.asLong());
case Object:
return c.isNull();
default:
return false;
public boolean canInlineConstant(Constant con) {
if (con instanceof JavaConstant) {
JavaConstant c = (JavaConstant) con;
switch (c.getJavaKind()) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
return AArch64MacroAssembler.isMovableImmediate(c.asInt());
case Long:
return AArch64MacroAssembler.isMovableImmediate(c.asLong());
case Object:
return c.isNull();
default:
return false;
}
}
return false;
}
@Override

View File

@ -24,9 +24,14 @@
package org.graalvm.compiler.core.aarch64;
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.AArch64AddressValue;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.nodes.DeoptimizingNode;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.Access;
import jdk.vm.ci.aarch64.AArch64Kind;
@ -56,4 +61,18 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
protected AArch64ArithmeticLIRGenerator getArithmeticLIRGenerator() {
return (AArch64ArithmeticLIRGenerator) getLIRGeneratorTool().getArithmetic();
}
@MatchRule("(ZeroExtend Read=access)")
@MatchRule("(ZeroExtend FloatingRead=access)")
public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
AArch64Kind memoryKind = getMemoryKind(access);
return builder -> getArithmeticLIRGenerator().emitExtendMemory(false, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access));
}
@MatchRule("(SignExtend Read=access)")
@MatchRule("(SignExtend FloatingRead=access)")
public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
AArch64Kind memoryKind = getMemoryKind(access);
return builder -> getArithmeticLIRGenerator().emitExtendMemory(true, memoryKind, root.getResultBits(), (AArch64AddressValue) operand(access.getAddress()), getState(access));
}
}

View File

@ -38,8 +38,8 @@ public class AMD64AllocatorTest extends AllocatorTest {
@Before
public void checkAMD64() {
assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
}
@Test

View File

@ -24,22 +24,23 @@ package org.graalvm.compiler.core.amd64.test;
import static org.junit.Assume.assumeTrue;
import org.junit.Before;
import org.junit.Test;
import org.graalvm.compiler.lir.LIR;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer.MemoryConstOp;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.jtt.LIRTest;
import org.graalvm.compiler.lir.phases.LIRPhase;
import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.lir.phases.PreAllocationOptimizationPhase.PreAllocationOptimizationContext;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Before;
import org.junit.Test;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.code.TargetDescription;
public class MatchRuleTest extends LIRTest {
private static LIR lir;
private LIR lir;
@Before
public void checkAMD64() {
@ -54,13 +55,19 @@ public class MatchRuleTest extends LIRTest {
}
}
@Override
protected LIRSuites createLIRSuites(OptionValues options) {
LIRSuites suites = super.createLIRSuites(options);
suites.getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
return suites;
}
/**
* Verifies, if the match rules in AMD64NodeMatchRules do work on the graphs by compiling and
* checking if the expected LIR instruction show up.
*/
@Test
public void test1() {
getLIRSuites().getPreAllocationOptimizationStage().appendPhase(new CheckPhase());
compile(getResolvedJavaMethod("test1Snippet"), null);
boolean found = false;
for (LIRInstruction ins : lir.getLIRforBlock(lir.codeEmittingOrder()[0])) {
@ -83,7 +90,7 @@ public class MatchRuleTest extends LIRTest {
}
}
public static class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
public class CheckPhase extends LIRPhase<PreAllocationOptimizationContext> {
@Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PreAllocationOptimizationContext context) {
lir = lirGenRes.getLIR();

View File

@ -25,7 +25,7 @@ package org.graalvm.compiler.core.amd64;
import jdk.vm.ci.meta.JavaConstant;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.nodes.ValueNode;

View File

@ -87,6 +87,7 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
gen.setResult(this, new AMD64AddressValue(kind, baseValue, indexValue, scale, displacement));
}
@Override
public ValueNode getBase() {
return base;
}
@ -99,6 +100,7 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
this.base = base;
}
@Override
public ValueNode getIndex() {
return index;
}
@ -126,4 +128,9 @@ public class AMD64AddressNode extends AddressNode implements LIRLowerable {
public void setDisplacement(int displacement) {
this.displacement = displacement;
}
@Override
public long getMaxConstantDisplacement() {
return displacement;
}
}

View File

@ -74,7 +74,7 @@ import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntr
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
@ -1234,7 +1234,7 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
return;
} else if (c instanceof VMConstant) {
VMConstant vc = (VMConstant) c;
if (size == DWORD && !GeneratePIC.getValue()) {
if (size == DWORD && !GeneratePIC.getValue(getOptions())) {
getLIRGen().append(new AMD64BinaryConsumer.VMConstOp(CMP.getMIOpcode(DWORD, false), left, vc));
} else {
getLIRGen().append(new AMD64BinaryConsumer.DataOp(CMP.getRMOpcode(size), size, left, vc));

View File

@ -23,6 +23,7 @@
package org.graalvm.compiler.core.amd64;
import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
@ -31,10 +32,10 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
@ -72,6 +73,7 @@ import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
import org.graalvm.compiler.lir.amd64.AMD64Move.StackLeaOp;
import org.graalvm.compiler.lir.amd64.AMD64PauseOp;
import org.graalvm.compiler.lir.amd64.AMD64StringIndexOfOp;
import org.graalvm.compiler.lir.amd64.AMD64ZapRegistersOp;
import org.graalvm.compiler.lir.amd64.AMD64ZapStackOp;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
@ -112,10 +114,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
protected static final boolean canStoreConstant(JavaConstant c) {
// there is no immediate move of 64-bit constants on Intel
switch (c.getJavaKind()) {
case Long: {
long l = c.asLong();
return (int) l == l;
}
case Long:
return NumUtil.isInt(c.asLong());
case Double:
return false;
case Object:
@ -183,7 +183,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
}
@Override
public Variable emitCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
ValueKind<?> kind = newValue.getValueKind();
assert kind.equals(expectedValue.getValueKind());
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
@ -199,6 +199,33 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
return result;
}
@Override
public Value emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
ValueKind<?> kind = newValue.getValueKind();
assert kind.equals(expectedValue.getValueKind());
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
AMD64AddressValue addressValue = asAddressValue(address);
RegisterValue raxRes = AMD64.rax.asValue(kind);
emitMove(raxRes, expectedValue);
append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
Variable result = newVariable(kind);
emitMove(result, raxRes);
return result;
}
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 condition == Condition.EQ || condition == Condition.NE;
AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
RegisterValue raxValue = AMD64.rax.asValue(kind);
emitMove(raxValue, expectedValue);
append(new CompareAndSwapOp(memKind, raxValue, address, raxValue, asAllocatable(newValue)));
append(new BranchOp(condition, trueLabel, falseLabel, trueLabelProbability));
}
@Override
public Value emitAtomicReadAndAdd(Value address, Value delta) {
ValueKind<?> kind = delta.getValueKind();
@ -329,7 +356,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
throw GraalError.shouldNotReachHere("unexpected kind: " + cmpKind);
}
if (isJavaConstant(a)) {
if (isConstantValue(a)) {
return emitCompareMemoryConOp(size, asConstantValue(a), b, state);
} else {
return emitCompareRegMemoryOp(size, asAllocatable(a), b, state);
@ -399,7 +426,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
@Override
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
long maxOffset = linkage.getMaxCallTargetOffset();
if (maxOffset != (int) maxOffset && !GeneratePIC.getValue()) {
if (maxOffset != (int) maxOffset && !GeneratePIC.getValue(getResult().getLIR().getOptions())) {
append(new AMD64Call.DirectFarForeignCallOp(linkage, result, arguments, temps, info));
} else {
append(new AMD64Call.DirectNearForeignCallOp(linkage, result, arguments, temps, info));
@ -420,6 +447,24 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
return result;
}
/**
* Return a conservative estimate of the page size for use by the String.indexOf intrinsic.
*/
protected int getVMPageSize() {
return 4096;
}
@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()));
return result;
}
@Override
public void emitReturn(JavaKind kind, Value input) {
AllocatableValue operand = Value.ILLEGAL;

View File

@ -28,7 +28,7 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isStackSlotValue;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.type.DataPointerConstant;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
@ -54,15 +54,19 @@ public abstract class AMD64MoveFactory extends AMD64MoveFactoryBase {
}
@Override
public boolean canInlineConstant(JavaConstant c) {
switch (c.getJavaKind()) {
case Long:
return NumUtil.isInt(c.asLong());
case Object:
return c.isNull();
default:
return true;
public boolean canInlineConstant(Constant con) {
if (con instanceof JavaConstant) {
JavaConstant c = (JavaConstant) con;
switch (c.getJavaKind()) {
case Long:
return NumUtil.isInt(c.asLong());
case Object:
return c.isNull();
default:
return true;
}
}
return false;
}
@Override

View File

@ -26,15 +26,14 @@ package org.graalvm.compiler.core.amd64;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
import java.util.HashMap;
import java.util.Map;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.lir.VirtualStackSlot;
import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove;
import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
import org.graalvm.util.Equivalence;
import org.graalvm.util.EconomicMap;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Architecture;
@ -61,7 +60,7 @@ public abstract class AMD64MoveFactoryBase implements MoveFactory {
public static final class BackupSlotProvider {
private final FrameMapBuilder frameMapBuilder;
private Map<PlatformKind.Key, RegisterBackupPair> categorized;
private EconomicMap<PlatformKind.Key, RegisterBackupPair> categorized;
public BackupSlotProvider(FrameMapBuilder frameMapBuilder) {
this.frameMapBuilder = frameMapBuilder;
@ -70,7 +69,7 @@ public abstract class AMD64MoveFactoryBase implements MoveFactory {
protected RegisterBackupPair getScratchRegister(PlatformKind kind) {
PlatformKind.Key key = kind.getKey();
if (categorized == null) {
categorized = new HashMap<>();
categorized = EconomicMap.create(Equivalence.DEFAULT);
} else if (categorized.containsKey(key)) {
return categorized.get(key);
}

View File

@ -36,13 +36,13 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
import org.graalvm.compiler.asm.NumUtil;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.gen.NodeLIRBuilder;
@ -52,6 +52,7 @@ import org.graalvm.compiler.core.match.MatchRule;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRValueUtil;
import org.graalvm.compiler.lir.LabelRef;
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
@ -69,18 +70,22 @@ import org.graalvm.compiler.nodes.calc.ReinterpretNode;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
import org.graalvm.compiler.nodes.memory.Access;
import org.graalvm.compiler.nodes.memory.LIRLowerableAccess;
import org.graalvm.compiler.nodes.memory.WriteNode;
import org.graalvm.compiler.nodes.util.GraphUtil;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.amd64.AMD64.CPUFeature;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.meta.ValueKind;
public class AMD64NodeMatchRules extends NodeMatchRules {
@ -95,11 +100,15 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
return null;
}
protected AMD64Kind getMemoryKind(Access access) {
return (AMD64Kind) gen.getLIRKind(access.asNode().stamp()).getPlatformKind();
protected AMD64Kind getMemoryKind(LIRLowerableAccess access) {
return (AMD64Kind) getLirKind(access).getPlatformKind();
}
protected OperandSize getMemorySize(Access access) {
protected LIRKind getLirKind(LIRLowerableAccess access) {
return gen.getLIRKind(access.getAccessStamp());
}
protected OperandSize getMemorySize(LIRLowerableAccess access) {
switch (getMemoryKind(access)) {
case BYTE:
return OperandSize.BYTE;
@ -118,25 +127,36 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
}
}
protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, Access access) {
protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
Condition cond = compare.condition();
AMD64Kind kind = getMemoryKind(access);
boolean matchedAsConstant = false; // For assertion checking
if (value.isConstant()) {
JavaConstant constant = value.asJavaConstant();
if (constant != null && kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
// Only imm32 as long
return null;
if (constant != null) {
if (kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && !NumUtil.isInt(constant.asLong())) {
// Only imm32 as long
return null;
}
// A QWORD that can be encoded as int can be embedded as a constant
matchedAsConstant = kind == AMD64Kind.QWORD && !constant.getJavaKind().isObject() && NumUtil.isInt(constant.asLong());
}
if (kind == AMD64Kind.DWORD) {
// Any DWORD value should be embeddable as a constant
matchedAsConstant = true;
}
if (kind.isXMM()) {
Debug.log("Skipping constant compares for float kinds");
return null;
}
}
boolean matchedAsConstantFinal = matchedAsConstant;
// emitCompareBranchMemory expects the memory on the right, so mirror the condition if
// that's not true. It might be mirrored again the actual compare is emitted but that's
// ok.
/*
* emitCompareBranchMemory expects the memory on the right, so mirror the condition if
* that's not true. It might be mirrored again the actual compare is emitted but that's ok.
*/
Condition finalCondition = GraphUtil.unproxify(compare.getX()) == access ? cond.mirror() : cond;
return new ComplexMatchResult() {
@Override
@ -146,6 +166,11 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
boolean unorderedIsTrue = compare.unorderedIsTrue();
double trueLabelProbability = ifNode.probability(ifNode.trueSuccessor());
Value other = operand(value);
/*
* Check that patterns which were matched as a constant actually end up seeing a
* constant in the LIR.
*/
assert !matchedAsConstantFinal || !LIRValueUtil.isVariable(other) : "expected constant value " + value;
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
getLIRGeneratorTool().emitCompareBranchMemory(kind, other, address, getState(access), finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability);
return null;
@ -153,7 +178,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
};
}
private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, Access access) {
private ComplexMatchResult emitIntegerTestBranchMemory(IfNode x, ValueNode value, LIRLowerableAccess access) {
LabelRef trueLabel = getLIRBlock(x.trueSuccessor());
LabelRef falseLabel = getLIRBlock(x.falseSuccessor());
double trueLabelProbability = x.probability(x.trueSuccessor());
@ -181,15 +206,22 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
}
}
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access, ValueKind<?> addressKind) {
return builder -> {
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
LIRFrameState state = getState(access);
if (addressKind != null) {
address = address.withKind(addressKind);
}
return getArithmeticLIRGenerator().emitConvertMemoryOp(kind, op, size, address, state);
};
}
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
protected ComplexMatchResult emitConvertMemoryOp(PlatformKind kind, AMD64RMOp op, OperandSize size, Access access) {
return emitConvertMemoryOp(kind, op, size, access, null);
}
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits, ValueKind<?> addressKind) {
assert fromBits <= toBits && toBits <= 64;
AMD64Kind kind = null;
AMD64RMOp op;
@ -231,7 +263,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
}
}
if (kind != null && op != null) {
return emitConvertMemoryOp(kind, op, size, access);
return emitConvertMemoryOp(kind, op, size, access, addressKind);
}
return null;
}
@ -244,7 +276,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(If (IntegerTest Read=access value))")
@MatchRule("(If (IntegerTest FloatingRead=access value))")
public ComplexMatchResult integerTestBranchMemory(IfNode root, Access access, ValueNode value) {
public ComplexMatchResult integerTestBranchMemory(IfNode root, LIRLowerableAccess access, ValueNode value) {
return emitIntegerTestBranchMemory(root, value, access);
}
@ -262,7 +294,67 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(If (PointerEquals=compare value FloatingRead=access))")
@MatchRule("(If (ObjectEquals=compare value Read=access))")
@MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, Access access) {
public ComplexMatchResult ifCompareMemory(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
return emitCompareBranchMemory(root, compare, value, access);
}
@MatchRule("(If (ObjectEquals=compare value ValueCompareAndSwap=cas))")
@MatchRule("(If (PointerEquals=compare value ValueCompareAndSwap=cas))")
@MatchRule("(If (FloatEquals=compare value ValueCompareAndSwap=cas))")
@MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))")
public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) {
assert compare.condition() == Condition.EQ;
if (value == cas.getExpectedValue() && cas.usages().count() == 1) {
return builder -> {
LIRKind kind = getLirKind(cas);
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
double trueLabelProbability = root.probability(root.trueSuccessor());
Value expectedValue = operand(cas.getExpectedValue());
Value newValue = operand(cas.getNewValue());
AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, Condition.EQ, trueLabel, falseLabel, trueLabelProbability);
return null;
};
}
return null;
}
@MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
JavaConstant constant = value.asJavaConstant();
assert compare.condition() == Condition.EQ;
if (constant != null && cas.usages().count() == 1) {
long constantValue = constant.asLong();
boolean successIsTrue;
if (constantValue == 0) {
successIsTrue = false;
} else if (constantValue == 1) {
successIsTrue = true;
} else {
return null;
}
return builder -> {
LIRKind kind = getLirKind(cas);
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
double trueLabelProbability = root.probability(root.trueSuccessor());
Value expectedValue = operand(cas.getExpectedValue());
Value newValue = operand(cas.getNewValue());
AMD64AddressValue address = (AMD64AddressValue) operand(cas.getAddress());
Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
getLIRGeneratorTool().emitCompareAndSwapBranch(kind, address, expectedValue, newValue, condition, trueLabel, falseLabel, trueLabelProbability);
return null;
};
}
return null;
}
@MatchRule("(If (ObjectEquals=compare value FloatingRead=access))")
public ComplexMatchResult ifLogicCas(IfNode root, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
return emitCompareBranchMemory(root, compare, value, access);
}
@ -290,19 +382,19 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
return null;
}
private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, Access access) {
private ComplexMatchResult binaryRead(AMD64RMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
getState(access));
}
private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, Access access) {
private ComplexMatchResult binaryRead(AMD64RRMOp op, OperandSize size, ValueNode value, LIRLowerableAccess access) {
return builder -> getArithmeticLIRGenerator().emitBinaryMemory(op, size, getLIRGeneratorTool().asAllocatable(operand(value)), (AMD64AddressValue) operand(access.getAddress()),
getState(access));
}
@MatchRule("(Add value Read=access)")
@MatchRule("(Add value FloatingRead=access)")
public ComplexMatchResult addMemory(ValueNode value, Access access) {
public ComplexMatchResult addMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
TargetDescription target = getLIRGeneratorTool().target();
@ -319,7 +411,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(Sub value Read=access)")
@MatchRule("(Sub value FloatingRead=access)")
public ComplexMatchResult subMemory(ValueNode value, Access access) {
public ComplexMatchResult subMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
TargetDescription target = getLIRGeneratorTool().target();
@ -336,7 +428,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(Mul value Read=access)")
@MatchRule("(Mul value FloatingRead=access)")
public ComplexMatchResult mulMemory(ValueNode value, Access access) {
public ComplexMatchResult mulMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
TargetDescription target = getLIRGeneratorTool().target();
@ -353,7 +445,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(And value Read=access)")
@MatchRule("(And value FloatingRead=access)")
public ComplexMatchResult andMemory(ValueNode value, Access access) {
public ComplexMatchResult andMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
return null;
@ -364,7 +456,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(Or value Read=access)")
@MatchRule("(Or value FloatingRead=access)")
public ComplexMatchResult orMemory(ValueNode value, Access access) {
public ComplexMatchResult orMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
return null;
@ -375,7 +467,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(Xor value Read=access)")
@MatchRule("(Xor value FloatingRead=access)")
public ComplexMatchResult xorMemory(ValueNode value, Access access) {
public ComplexMatchResult xorMemory(ValueNode value, LIRLowerableAccess access) {
OperandSize size = getMemorySize(access);
if (size.isXmmType()) {
return null;
@ -395,20 +487,44 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(SignExtend Read=access)")
@MatchRule("(SignExtend FloatingRead=access)")
public ComplexMatchResult signExtend(SignExtendNode root, Access access) {
return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits());
public ComplexMatchResult signExtend(SignExtendNode root, LIRLowerableAccess access) {
return emitSignExtendMemory(access, root.getInputBits(), root.getResultBits(), null);
}
@MatchRule("(ZeroExtend Read=access)")
@MatchRule("(ZeroExtend FloatingRead=access)")
public ComplexMatchResult zeroExtend(ZeroExtendNode root, Access access) {
public ComplexMatchResult zeroExtend(ZeroExtendNode root, LIRLowerableAccess access) {
AMD64Kind memoryKind = getMemoryKind(access);
return builder -> getArithmeticLIRGenerator().emitZeroExtendMemory(memoryKind, root.getResultBits(), (AMD64AddressValue) operand(access.getAddress()), getState(access));
}
@MatchRule("(Narrow Read=access)")
@MatchRule("(Narrow FloatingRead=access)")
public ComplexMatchResult narrowRead(NarrowNode root, LIRLowerableAccess access) {
return new ComplexMatchResult() {
@Override
public Value evaluate(NodeLIRBuilder builder) {
AMD64AddressValue address = (AMD64AddressValue) operand(access.getAddress());
LIRKind addressKind = LIRKind.combineDerived(getLIRGeneratorTool().getLIRKind(root.asNode().stamp()),
address.getBase(), address.getIndex());
AMD64AddressValue newAddress = address.withKind(addressKind);
LIRKind readKind = getLIRGeneratorTool().getLIRKind(root.stamp());
return getArithmeticLIRGenerator().emitZeroExtendMemory((AMD64Kind) readKind.getPlatformKind(),
root.getResultBits(), newAddress, getState(access));
}
};
}
@MatchRule("(SignExtend (Narrow=narrow Read=access))")
@MatchRule("(SignExtend (Narrow=narrow FloatingRead=access))")
public ComplexMatchResult signExtendNarrowRead(SignExtendNode root, NarrowNode narrow, LIRLowerableAccess access) {
LIRKind kind = getLIRGeneratorTool().getLIRKind(narrow.stamp());
return emitSignExtendMemory(access, narrow.getResultBits(), root.getResultBits(), kind);
}
@MatchRule("(FloatConvert Read=access)")
@MatchRule("(FloatConvert FloatingRead=access)")
public ComplexMatchResult floatConvert(FloatConvertNode root, Access access) {
public ComplexMatchResult floatConvert(FloatConvertNode root, LIRLowerableAccess access) {
switch (root.getFloatConvert()) {
case D2F:
return emitConvertMemoryOp(AMD64Kind.SINGLE, SSEOp.CVTSD2SS, SD, access);
@ -437,7 +553,7 @@ public class AMD64NodeMatchRules extends NodeMatchRules {
@MatchRule("(Reinterpret Read=access)")
@MatchRule("(Reinterpret FloatingRead=access)")
public ComplexMatchResult reinterpret(ReinterpretNode root, Access access) {
public ComplexMatchResult reinterpret(ReinterpretNode root, LIRLowerableAccess access) {
return builder -> {
LIRKind kind = getLIRGeneratorTool().getLIRKind(root.stamp());
return emitReinterpretMemory(kind, access);

View File

@ -26,6 +26,7 @@ import org.graalvm.compiler.java.DefaultSuitesProvider;
import org.graalvm.compiler.lir.amd64.phases.StackMoveOptimizationPhase;
import org.graalvm.compiler.lir.phases.LIRSuites;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
public class AMD64SuitesProvider extends DefaultSuitesProvider {
@ -35,9 +36,9 @@ public class AMD64SuitesProvider extends DefaultSuitesProvider {
}
@Override
public LIRSuites createLIRSuites() {
LIRSuites lirSuites = super.createLIRSuites();
if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue()) {
public LIRSuites createLIRSuites(OptionValues options) {
LIRSuites lirSuites = super.createLIRSuites(options);
if (StackMoveOptimizationPhase.Options.LIROptStackMoveOptimizer.getValue(options)) {
/* Note: this phase must be inserted <b>after</b> RedundantMoveElimination */
lirSuites.getPostAllocationOptimizationStage().appendPhase(new StackMoveOptimizationPhase());
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common;
/**
* A {@linkplain RetryableBailoutException} that will be thrown if an on-going compilation in the
* compiler was cancelled.
*/
public final class CancellationBailoutException extends RetryableBailoutException {
private static final long serialVersionUID = 6551793589275293360L;
public CancellationBailoutException() {
super("Compilation cancelled.");
}
public static void cancelCompilation() {
throw new CancellationBailoutException();
}
}

View File

@ -1,132 +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.core.common;
import static org.graalvm.compiler.core.common.CollectionsFactory.Mode.STANDARD;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* Factory for creating collection objects used during compilation.
*/
public class CollectionsFactory {
private static final ThreadLocal<Mode> tl = new ThreadLocal<>();
public static class ModeScope implements AutoCloseable {
private final Mode previousMode;
public ModeScope(Mode previousMode) {
this.previousMode = previousMode;
}
@Override
public void close() {
tl.set(previousMode);
}
}
/**
* Constants denoting what type of collections are {@link CollectionsFactory#getMode()
* currently} returned by the factory.
*/
public enum Mode {
/**
* Denotes standard collections such as {@link HashSet} and {@link HashMap}.
*/
STANDARD,
/**
* Denotes collections that have a deterministic iteration order over their keys/entries.
*/
DETERMINISTIC_ITERATION_ORDER;
}
/**
* Gets the current mode determining the type of collection objects created by this factory.
*/
public static Mode getMode() {
Mode mode = tl.get();
return mode == null ? Mode.STANDARD : mode;
}
/**
* Updates the mode for the current thread.
*
* @return an object which when {@linkplain ModeScope#close() closed} will revert the mode of
* the current thread to the state before calling this method
*/
public static ModeScope changeMode(Mode mode) {
Mode previousMode = tl.get();
tl.set(mode);
return new ModeScope(previousMode);
}
public static <K, V> HashMap<K, V> newMap() {
return getMode() == STANDARD ? new HashMap<>() : new LinkedHashMap<>();
}
public static <K, V> HashMap<K, V> newMap(Map<K, V> m) {
return getMode() == STANDARD ? new HashMap<>(m) : new LinkedHashMap<>(m);
}
public static <K, V> HashMap<K, V> newMap(int initialCapacity) {
return getMode() == STANDARD ? new HashMap<>(initialCapacity) : new LinkedHashMap<>(initialCapacity);
}
public static <K, V> Map<K, V> newIdentityMap() {
return getMode() == STANDARD ? new IdentityHashMap<>() : new LinkedIdentityHashMap<>();
}
public static <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
return getMode() == STANDARD ? new IdentityHashMap<>(expectedMaxSize) : new LinkedIdentityHashMap<>();
}
public static <K, V> Map<K, V> newIdentityMap(Map<K, V> m) {
return getMode() == STANDARD ? new IdentityHashMap<>(m) : new LinkedIdentityHashMap<>(m);
}
/**
* Creates a set. If the current thread is {@linkplain CollectionsFactory#getMode() using}
* {@link Mode#DETERMINISTIC_ITERATION_ORDER} collections, the returned set will have an
* iteration order determined by the order in which elements are inserted in the set.
*/
public static <E> Set<E> newSet() {
return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>() : new LinkedHashSet<>();
}
/**
* @see #newSet()
*/
public static <E> Set<E> newSet(Collection<? extends E> c) {
return CollectionsFactory.getMode() == Mode.STANDARD ? new HashSet<>(c) : new LinkedHashSet<>(c);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -20,20 +20,18 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot;
package org.graalvm.compiler.core.common;
/**
* A compact representation of the different encoding strategies for Objects and metadata.
*/
public class CompressEncoding {
public final long base;
public final int shift;
public final int alignment;
public final class CompressEncoding {
private final long base;
private final int shift;
CompressEncoding(long base, int shift, int alignment) {
public CompressEncoding(long base, int shift) {
this.base = base;
this.shift = shift;
this.alignment = alignment;
}
public int compress(long ptr) {
@ -44,6 +42,22 @@ public class CompressEncoding {
}
}
public boolean hasBase() {
return base != 0;
}
public boolean hasShift() {
return shift != 0;
}
public long getBase() {
return base;
}
public int getShift() {
return shift;
}
public long uncompress(int ptr) {
if (ptr == 0) {
return 0L;
@ -54,14 +68,13 @@ public class CompressEncoding {
@Override
public String toString() {
return "base: " + base + " shift: " + shift + " alignment: " + alignment;
return "base: " + base + " shift: " + shift;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + alignment;
result = prime * result + (int) (base ^ (base >>> 32));
result = prime * result + shift;
return result;
@ -71,7 +84,7 @@ public class CompressEncoding {
public boolean equals(Object obj) {
if (obj instanceof CompressEncoding) {
CompressEncoding other = (CompressEncoding) obj;
return alignment == other.alignment && base == other.base && shift == other.shift;
return base == other.base && shift == other.shift;
} else {
return false;
}

View File

@ -22,10 +22,10 @@
*/
package org.graalvm.compiler.core.common;
import org.graalvm.compiler.debug.Assertions;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.StableOptionValue;
import org.graalvm.compiler.options.OptionKey;
/**
* This class encapsulates options that control the behavior of the Graal compiler.
@ -34,250 +34,242 @@ import org.graalvm.compiler.options.StableOptionValue;
public final class GraalOptions {
@Option(help = "Use compiler intrinsifications.", type = OptionType.Debug)
public static final OptionValue<Boolean> Intrinsify = new OptionValue<>(true);
public static final OptionKey<Boolean> Intrinsify = new OptionKey<>(true);
@Option(help = "Inline calls with monomorphic type profile.", type = OptionType.Expert)
public static final OptionValue<Boolean> InlineMonomorphicCalls = new OptionValue<>(true);
public static final OptionKey<Boolean> InlineMonomorphicCalls = new OptionKey<>(true);
@Option(help = "Inline calls with polymorphic type profile.", type = OptionType.Expert)
public static final OptionValue<Boolean> InlinePolymorphicCalls = new OptionValue<>(true);
public static final OptionKey<Boolean> InlinePolymorphicCalls = new OptionKey<>(true);
@Option(help = "Inline calls with megamorphic type profile (i.e., not all types could be recorded).", type = OptionType.Expert)
public static final OptionValue<Boolean> InlineMegamorphicCalls = new OptionValue<>(true);
public static final OptionKey<Boolean> InlineMegamorphicCalls = new OptionKey<>(true);
@Option(help = "Maximum desired size of the compiler graph in nodes.", type = OptionType.User)
public static final OptionValue<Integer> MaximumDesiredSize = new OptionValue<>(20000);
public static final OptionKey<Integer> MaximumDesiredSize = new OptionKey<>(20000);
@Option(help = "Minimum probability for methods to be inlined for megamorphic type profiles.", type = OptionType.Expert)
public static final OptionValue<Double> MegamorphicInliningMinMethodProbability = new OptionValue<>(0.33D);
public static final OptionKey<Double> MegamorphicInliningMinMethodProbability = new OptionKey<>(0.33D);
@Option(help = "Maximum level of recursive inlining.", type = OptionType.Expert)
public static final OptionValue<Integer> MaximumRecursiveInlining = new OptionValue<>(5);
public static final OptionKey<Integer> MaximumRecursiveInlining = new OptionKey<>(5);
@Option(help = "Graphs with less than this number of nodes are trivial and therefore always inlined.", type = OptionType.Expert)
public static final OptionValue<Integer> TrivialInliningSize = new OptionValue<>(10);
public static final OptionKey<Integer> TrivialInliningSize = new OptionKey<>(10);
@Option(help = "Inlining is explored up to this number of nodes in the graph for each call site.", type = OptionType.Expert)
public static final OptionValue<Integer> MaximumInliningSize = new OptionValue<>(300);
public static final OptionKey<Integer> MaximumInliningSize = new OptionKey<>(300);
@Option(help = "If the previous low-level graph size of the method exceeds the threshold, it is not inlined.", type = OptionType.Expert)
public static final OptionValue<Integer> SmallCompiledLowLevelGraphSize = new OptionValue<>(300);
public static final OptionKey<Integer> SmallCompiledLowLevelGraphSize = new OptionKey<>(300);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Double> LimitInlinedInvokes = new OptionValue<>(5.0);
public static final OptionKey<Double> LimitInlinedInvokes = new OptionKey<>(5.0);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> InlineEverything = new OptionValue<>(false);
public static final OptionKey<Boolean> InlineEverything = new OptionKey<>(false);
// escape analysis settings
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> PartialEscapeAnalysis = new OptionValue<>(true);
public static final OptionKey<Boolean> PartialEscapeAnalysis = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Integer> EscapeAnalysisIterations = new OptionValue<>(2);
public static final OptionKey<Integer> EscapeAnalysisIterations = new OptionKey<>(2);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Integer> EscapeAnalysisLoopCutoff = new OptionValue<>(20);
public static final OptionKey<Integer> EscapeAnalysisLoopCutoff = new OptionKey<>(20);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<String> EscapeAnalyzeOnly = new OptionValue<>(null);
public static final OptionKey<String> EscapeAnalyzeOnly = new OptionKey<>(null);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Integer> MaximumEscapeAnalysisArrayLength = new OptionValue<>(32);
public static final OptionKey<Integer> MaximumEscapeAnalysisArrayLength = new OptionKey<>(32);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> PEAInliningHints = new OptionValue<>(false);
public static final OptionKey<Boolean> PEAInliningHints = new OptionKey<>(false);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Double> TailDuplicationProbability = new OptionValue<>(0.5);
public static final OptionKey<Double> TailDuplicationProbability = new OptionKey<>(0.5);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Integer> TailDuplicationTrivialSize = new OptionValue<>(1);
public static final OptionKey<Integer> TailDuplicationTrivialSize = new OptionKey<>(1);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Integer> DeoptsToDisableOptimisticOptimization = new OptionValue<>(40);
public static final OptionKey<Integer> DeoptsToDisableOptimisticOptimization = new OptionKey<>(40);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> LoopPeeling = new OptionValue<>(true);
public static final OptionKey<Boolean> LoopPeeling = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> ReassociateInvariants = new OptionValue<>(true);
public static final OptionKey<Boolean> ReassociateInvariants = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> FullUnroll = new OptionValue<>(true);
public static final OptionKey<Boolean> FullUnroll = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> LoopUnswitch = new OptionValue<>(true);
public static final OptionKey<Boolean> LoopUnswitch = new OptionKey<>(true);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Float> MinimumPeelProbability = new OptionValue<>(0.35f);
public static final OptionKey<Float> MinimumPeelProbability = new OptionKey<>(0.35f);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Integer> LoopMaxUnswitch = new OptionValue<>(3);
public static final OptionKey<Integer> LoopMaxUnswitch = new OptionKey<>(3);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> UseLoopLimitChecks = new OptionValue<>(true);
public static final OptionKey<Boolean> UseLoopLimitChecks = new OptionKey<>(true);
// debugging settings
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> ZapStackOnMethodEntry = new OptionValue<>(false);
public static final OptionKey<Boolean> ZapStackOnMethodEntry = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> DeoptALot = new OptionValue<>(false);
public static final OptionKey<Boolean> DeoptALot = new OptionKey<>(false);
@Option(help = "Stress the code emitting explicit exception throwing code.", type = OptionType.Debug)
public static final OptionValue<Boolean> StressExplicitExceptionCode = new OptionValue<>(false);
public static final OptionKey<Boolean> StressExplicitExceptionCode = new OptionKey<>(false);
@Option(help = "Stress the code emitting invokes with explicit exception edges.", type = OptionType.Debug)
public static final OptionValue<Boolean> StressInvokeWithExceptionNode = new OptionValue<>(false);
public static final OptionKey<Boolean> StressInvokeWithExceptionNode = new OptionKey<>(false);
@Option(help = "Stress the code by emitting reads at earliest instead of latest point.", type = OptionType.Debug)
public static final OptionKey<Boolean> StressTestEarlyReads = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> VerifyPhases = new OptionValue<>(false);
public static final OptionKey<Boolean> VerifyPhases = new OptionKey<>(false);
// Debug settings:
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Integer> GCDebugStartCycle = new OptionValue<>(-1);
public static final OptionKey<Integer> GCDebugStartCycle = new OptionKey<>(-1);
@Option(help = "Perform platform dependent validation of the Java heap at returns", type = OptionType.Debug)
public static final OptionValue<Boolean> VerifyHeapAtReturn = new OptionValue<>(false);
public static final OptionKey<Boolean> VerifyHeapAtReturn = new OptionKey<>(false);
// Other printing settings
@Option(help = "Print profiling information when parsing a method's bytecode", type = OptionType.Debug)
public static final OptionValue<Boolean> PrintProfilingInformation = new OptionValue<>(false);
public static final OptionKey<Boolean> PrintProfilingInformation = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final StableOptionValue<Boolean> TraceEscapeAnalysis = new StableOptionValue<>(false);
public static final OptionKey<Boolean> TraceEscapeAnalysis = new OptionKey<>(false);
// HotSpot command line options
@Option(help = "Print inlining optimizations", type = OptionType.Debug)
public static final OptionValue<Boolean> HotSpotPrintInlining = new OptionValue<>(false);
public static final OptionKey<Boolean> HotSpotPrintInlining = new OptionKey<>(false);
// Register allocator debugging
@Option(help = "Comma separated list of registers that register allocation is limited to.", type = OptionType.Debug)
public static final OptionValue<String> RegisterPressure = new OptionValue<>(null);
public static final OptionKey<String> RegisterPressure = new OptionKey<>(null);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> ConditionalElimination = new OptionValue<>(true);
public static final OptionKey<Boolean> ConditionalElimination = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> RemoveNeverExecutedCode = new OptionValue<>(true);
public static final OptionKey<Boolean> RawConditionalElimination = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> UseExceptionProbability = new OptionValue<>(true);
public static final OptionKey<Boolean> ReplaceInputsWithConstantsBasedOnStamps = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> UseExceptionProbabilityForOperations = new OptionValue<>(true);
public static final OptionKey<Boolean> RemoveNeverExecutedCode = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OmitHotExceptionStacktrace = new OptionValue<>(false);
public static final OptionKey<Boolean> UseExceptionProbability = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> GenSafepoints = new OptionValue<>(true);
public static final OptionKey<Boolean> OmitHotExceptionStacktrace = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> GenLoopSafepoints = new OptionValue<>(true);
public static final OptionKey<Boolean> GenSafepoints = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> UseTypeCheckHints = new OptionValue<>(true);
public static final OptionKey<Boolean> GenLoopSafepoints = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionKey<Boolean> UseTypeCheckHints = new OptionKey<>(true);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> InlineVTableStubs = new OptionValue<>(true);
public static final OptionKey<Boolean> InlineVTableStubs = new OptionKey<>(true);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> AlwaysInlineVTableStubs = new OptionValue<>(false);
public static final OptionKey<Boolean> AlwaysInlineVTableStubs = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> ResolveClassBeforeStaticInvoke = new OptionValue<>(false);
public static final OptionKey<Boolean> ResolveClassBeforeStaticInvoke = new OptionKey<>(false);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> CanOmitFrame = new OptionValue<>(true);
public static final OptionKey<Boolean> CanOmitFrame = new OptionKey<>(true);
// Ahead of time compilation
@Option(help = "Try to avoid emitting code where patching is required", type = OptionType.Expert)
public static final OptionValue<Boolean> ImmutableCode = new OptionValue<>(false);
public static final OptionKey<Boolean> ImmutableCode = new OptionKey<>(false);
@Option(help = "Generate position independent code", type = OptionType.Expert)
public static final OptionValue<Boolean> GeneratePIC = new OptionValue<>(false);
public static final OptionKey<Boolean> GeneratePIC = new OptionKey<>(false);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> CallArrayCopy = new OptionValue<>(true);
public static final OptionKey<Boolean> CallArrayCopy = new OptionKey<>(true);
// Runtime settings
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> SupportJsrBytecodes = new OptionValue<>(true);
public static final OptionKey<Boolean> SupportJsrBytecodes = new OptionKey<>(true);
@Option(help = "", type = OptionType.Expert)
public static final OptionValue<Boolean> OptAssumptions = new OptionValue<>(true);
public static final OptionKey<Boolean> OptAssumptions = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptConvertDeoptsToGuards = new OptionValue<>(true);
public static final OptionKey<Boolean> OptConvertDeoptsToGuards = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptReadElimination = new OptionValue<>(true);
public static final OptionKey<Boolean> OptReadElimination = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Integer> ReadEliminationMaxLoopVisits = new OptionValue<>(5);
public static final OptionKey<Integer> ReadEliminationMaxLoopVisits = new OptionKey<>(5);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptDeoptimizationGrouping = new OptionValue<>(true);
public static final OptionKey<Boolean> OptDeoptimizationGrouping = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptScheduleOutOfLoops = new OptionValue<>(true);
public static final OptionKey<Boolean> OptScheduleOutOfLoops = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptEliminateGuards = new OptionValue<>(true);
public static final OptionKey<Boolean> OptEliminateGuards = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptImplicitNullChecks = new OptionValue<>(true);
public static final OptionKey<Boolean> OptImplicitNullChecks = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptClearNonLiveLocals = new OptionValue<>(true);
public static final OptionKey<Boolean> OptClearNonLiveLocals = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptLoopTransform = new OptionValue<>(true);
public static final OptionKey<Boolean> OptLoopTransform = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptFloatingReads = new OptionValue<>(true);
public static final OptionKey<Boolean> OptFloatingReads = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptEliminatePartiallyRedundantGuards = new OptionValue<>(true);
public static final OptionKey<Boolean> OptEliminatePartiallyRedundantGuards = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptFilterProfiledTypes = new OptionValue<>(true);
public static final OptionKey<Boolean> OptFilterProfiledTypes = new OptionKey<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptDevirtualizeInvokesOptimistically = new OptionValue<>(true);
@Option(help = "", type = OptionType.Debug)
public static final OptionValue<Boolean> OptPushThroughPi = new OptionValue<>(true);
public static final OptionKey<Boolean> OptDevirtualizeInvokesOptimistically = new OptionKey<>(true);
@Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
public static final OptionValue<Boolean> MatchExpressions = new OptionValue<>(true);
public static final OptionKey<Boolean> MatchExpressions = new OptionKey<>(true);
@Option(help = "Enable counters for various paths in snippets.", type = OptionType.Debug)
public static final OptionValue<Boolean> SnippetCounters = new OptionValue<>(false);
public static final OptionKey<Boolean> SnippetCounters = new OptionKey<>(false);
@Option(help = "Eagerly construct extra snippet info.", type = OptionType.Debug)
public static final OptionValue<Boolean> EagerSnippets = new OptionValue<>(false);
public static final OptionKey<Boolean> EagerSnippets = new OptionKey<>(false);
@Option(help = "Use a cache for snippet graphs.", type = OptionType.Debug)
public static final OptionValue<Boolean> UseSnippetGraphCache = new OptionValue<>(true);
public static final OptionKey<Boolean> UseSnippetGraphCache = new OptionKey<>(true);
@Option(help = "Enable expensive assertions", type = OptionType.Debug)
public static final OptionValue<Boolean> DetailedAsserts = new StableOptionValue<Boolean>() {
@Override
protected Boolean defaultValue() {
boolean enabled = false;
// turn detailed assertions on when the general assertions are on (misusing the assert keyword for this)
assert (enabled = true) == true;
return enabled;
}
};
@Option(help = "Enable Graal instrumentation")
public static final OptionValue<Boolean> UseGraalInstrumentation = new OptionValue<>(false);
@Option(help = "Enable expensive assertions.", type = OptionType.Debug)
public static final OptionKey<Boolean> DetailedAsserts = new OptionKey<>(Assertions.ENABLED);
@Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
public static final OptionValue<Boolean> TraceRA = new OptionValue<>(false);
public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
}

View File

@ -1,285 +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.core.common;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.Consumer;
/**
* A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of
* ensuring a deterministic execution order during a capturing compilation.
*/
final class LinkedIdentityHashMap<K, V> implements Map<K, V> {
private final LinkedHashMap<Id<K>, V> map;
LinkedIdentityHashMap() {
map = new LinkedHashMap<>();
}
LinkedIdentityHashMap(Map<K, V> m) {
map = new LinkedHashMap<>(m.size());
putAll(m);
}
LinkedIdentityHashMap(int expectedMaxSize) {
map = new LinkedHashMap<>(expectedMaxSize);
}
/**
* Wrapper for an object that gives uses the object's identity for the purpose of equality
* comparisons and computing a hash code.
*/
static final class Id<T> {
final T object;
Id(T object) {
assert object != null;
this.object = object;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj) {
return obj instanceof Id && ((Id<T>) obj).object == object;
}
@Override
public int hashCode() {
return System.identityHashCode(object);
}
}
@Override
public int size() {
return map.size();
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(id(key));
}
@SuppressWarnings("unchecked")
private Id<K> id(Object key) {
if (key == null) {
return null;
}
return new Id<>((K) key);
}
@Override
public boolean containsValue(Object value) {
return map.containsValue(value);
}
@Override
public V get(Object key) {
return map.get(id(key));
}
@Override
public V put(K key, V value) {
return map.put(id(key), value);
}
@Override
public V remove(Object key) {
return map.remove(id(key));
}
@Override
@SuppressWarnings("unchecked")
public void putAll(Map<? extends K, ? extends V> m) {
if (m == null) {
throw new NullPointerException();
}
if (m.getClass() == getClass()) {
LinkedIdentityHashMap<K, V> that = (LinkedIdentityHashMap<K, V>) m;
map.putAll(that.map);
} else {
for (K key : m.keySet()) {
map.put(id(key), m.get(key));
}
}
}
@Override
public void clear() {
map.clear();
}
final class KeySet extends AbstractSet<K> {
@Override
public int size() {
return map.size();
}
@Override
public void clear() {
map.clear();
}
@Override
public Iterator<K> iterator() {
return new Iterator<K>() {
final Iterator<Id<K>> i = map.keySet().iterator();
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public K next() {
return i.next().object;
}
@Override
public void remove() {
i.remove();
}
};
}
@Override
public boolean contains(Object o) {
return containsKey(o);
}
@Override
public boolean remove(Object o) {
return LinkedIdentityHashMap.this.remove(o) != null;
}
@Override
public Spliterator<K> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
}
@Override
public void forEach(Consumer<? super K> action) {
throw new UnsupportedOperationException();
}
}
@Override
public Set<K> keySet() {
return new KeySet();
}
@Override
public Collection<V> values() {
return map.values();
}
final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
@Override
public int size() {
return map.size();
}
@Override
public void clear() {
map.clear();
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new Iterator<Map.Entry<K, V>>() {
final Iterator<Map.Entry<Id<K>, V>> i = map.entrySet().iterator();
@Override
public boolean hasNext() {
return i.hasNext();
}
@Override
public Map.Entry<K, V> next() {
Map.Entry<Id<K>, V> e = i.next();
return new Map.Entry<K, V>() {
@Override
public K getKey() {
return e.getKey().object;
}
@Override
public V getValue() {
return e.getValue();
}
@Override
public V setValue(V value) {
return e.setValue(value);
}
};
}
@Override
public void remove() {
i.remove();
}
};
}
@Override
public boolean contains(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public Spliterator<Map.Entry<K, V>> spliterator() {
throw new UnsupportedOperationException();
}
@Override
public void forEach(Consumer<? super Map.Entry<K, V>> action) {
throw new UnsupportedOperationException();
}
}
@Override
public Set<Map.Entry<K, V>> entrySet() {
return new EntrySet();
}
}

View File

@ -22,8 +22,6 @@
*/
package org.graalvm.compiler.core.common;
import java.util.IdentityHashMap;
// JaCoCo Exclude
/**
@ -32,7 +30,7 @@ import java.util.IdentityHashMap;
*
* Clients of {@link LocationIdentity} must use {@link #equals(Object)}, not {@code ==}, when
* comparing two {@link LocationIdentity} values for equality. Likewise, they must not use
* {@link IdentityHashMap}s with {@link LocationIdentity} values as keys.
* {@link java.util.IdentityHashMap}s with {@link LocationIdentity} values as keys.
*/
public abstract class LocationIdentity {
@ -48,12 +46,39 @@ public abstract class LocationIdentity {
}
}
public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
private static final class InitLocationIdentity extends LocationIdentity {
@Override
public boolean isImmutable() {
return true;
}
@Override
public String toString() {
return "INIT_LOCATION";
}
}
public static final LocationIdentity ANY_LOCATION = new AnyLocationIdentity();
public static final LocationIdentity INIT_LOCATION = new InitLocationIdentity();
/**
* Indicates that the given location is the union of all possible mutable locations. A write to
* such a location kill all reads from mutable locations and a read from this location is killed
* by any write (except for initialization writes).
*/
public static LocationIdentity any() {
return ANY_LOCATION;
}
/**
* Location only allowed to be used for writes. Indicates that a completely new memory location
* is written. Kills no read. The previous value at the given location must be either
* uninitialized or null. Writes to this location do not need a GC pre-barrier.
*/
public static LocationIdentity init() {
return INIT_LOCATION;
}
/**
* Denotes a location is unchanging in all cases. Not that this is different than the Java
* notion of final which only requires definite assignment.
@ -68,6 +93,10 @@ public abstract class LocationIdentity {
return this == ANY_LOCATION;
}
public final boolean isInit() {
return this == INIT_LOCATION;
}
public final boolean isSingle() {
return this != ANY_LOCATION;
}

View File

@ -20,10 +20,12 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.asm;
package org.graalvm.compiler.core.common;
// JaCoCo Exclude
import jdk.vm.ci.code.CodeUtil;
/**
* A collection of static utility functions that check ranges of numbers.
*/
@ -183,4 +185,43 @@ public class NumUtil {
return 0xFFFFFFFFFFFFFFFFL;
}
}
/**
* Get the minimum value representable in a {@code bits} bit signed integer.
*/
public static long minValue(int bits) {
return CodeUtil.minValue(bits);
}
/**
* Get the maximum value representable in a {@code bits} bit signed integer.
*/
public static long maxValue(int bits) {
return CodeUtil.maxValue(bits);
}
/**
* Get the maximum value representable in a {@code bits} bit unsigned integer.
*/
public static long maxValueUnsigned(int bits) {
return getNbitNumberLong(bits);
}
public static long maxUnsigned(long a, long b) {
if (Long.compareUnsigned(a, b) > 0) {
return b;
}
return a;
}
public static long minUnsigned(long a, long b) {
if (Long.compareUnsigned(a, b) > 0) {
return a;
}
return b;
}
public static boolean sameSign(long a, long b) {
return a < 0 == b < 0;
}
}

View File

@ -20,7 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.common;
package org.graalvm.compiler.core.common;
import jdk.vm.ci.code.BailoutException;

View File

@ -20,7 +20,7 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.common;
package org.graalvm.compiler.core.common;
import jdk.vm.ci.code.BailoutException;

View File

@ -22,18 +22,15 @@
*/
package org.graalvm.compiler.core.common.alloc;
import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
import java.util.HashMap;
import java.util.Map;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.Equivalence;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterArray;
import jdk.vm.ci.code.RegisterConfig;
import jdk.vm.ci.meta.PlatformKind;
import org.graalvm.compiler.core.common.GraalOptions;
/**
* Configuration for register allocation. This is different to {@link RegisterConfig} as it only
* returns registers specified by {@link GraalOptions#RegisterPressure}.
@ -82,11 +79,10 @@ public class RegisterAllocationConfig {
}
protected RegisterArray initAllocatable(RegisterArray registers) {
if (RegisterPressure.getValue() != null && !RegisterPressure.getValue().equals(ALL_REGISTERS)) {
String[] names = RegisterPressure.getValue().split(",");
Register[] regs = new Register[names.length];
for (int i = 0; i < names.length; i++) {
regs[i] = findRegister(names[i], registers);
if (allocationRestrictedTo != null) {
Register[] regs = new Register[allocationRestrictedTo.length];
for (int i = 0; i < allocationRestrictedTo.length; i++) {
regs[i] = findRegister(allocationRestrictedTo[i], registers);
}
return new RegisterArray(regs);
}
@ -95,12 +91,18 @@ public class RegisterAllocationConfig {
}
protected final RegisterConfig registerConfig;
private final Map<PlatformKind.Key, AllocatableRegisters> categorized = new HashMap<>();
private final EconomicMap<PlatformKind.Key, AllocatableRegisters> categorized = EconomicMap.create(Equivalence.DEFAULT);
private final String[] allocationRestrictedTo;
private RegisterArray cachedRegisters;
public RegisterAllocationConfig(RegisterConfig registerConfig) {
/**
* @param allocationRestrictedTo if not {@code null}, register allocation will be restricted to
* registers whose names appear in this array
*/
public RegisterAllocationConfig(RegisterConfig registerConfig, String[] allocationRestrictedTo) {
assert registerConfig != null;
this.registerConfig = registerConfig;
this.allocationRestrictedTo = allocationRestrictedTo;
}
/**

View File

@ -22,9 +22,6 @@
*/
package org.graalvm.compiler.core.common.cfg;
import java.util.Collections;
import java.util.List;
public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
protected int id;
@ -34,7 +31,8 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
protected T[] successors;
private T dominator;
private List<T> dominated;
private T firstDominated;
private T dominatedSibling;
private int domNumber;
private int maxChildDomNumber;
@ -97,19 +95,27 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
this.domDepth = dominator.domDepth + 1;
}
/**
* Level in the dominator tree starting with 0 for the start block.
*/
public int getDominatorDepth() {
return domDepth;
}
public List<T> getDominated() {
if (dominated == null) {
return Collections.emptyList();
}
return dominated;
public T getFirstDominated() {
return this.firstDominated;
}
public void setDominated(List<T> blocks) {
dominated = blocks;
public void setFirstDominated(T block) {
this.firstDominated = block;
}
public T getDominatedSibling() {
return this.dominatedSibling;
}
public void setDominatedSibling(T block) {
this.dominatedSibling = block;
}
@Override
@ -158,4 +164,9 @@ public abstract class AbstractBlockBase<T extends AbstractBlockBase<T>> {
public abstract double probability();
public abstract T getDominator(int distance);
@Override
public int hashCode() {
return id;
}
}

View File

@ -81,6 +81,8 @@ public interface AbstractControlFlowGraph<T extends AbstractBlockBase<T>> {
return b;
} else if (b == null) {
return a;
} else if (a == b) {
return a;
} else {
int aDomDepth = a.getDominatorDepth();
int bDomDepth = b.getDominatorDepth();

View File

@ -45,11 +45,22 @@ public class CFGVerifier {
if (block.getDominator() != null) {
assert block.getDominator().getId() < block.getId();
assert block.getDominator().getDominated().contains(block);
AbstractBlockBase<?> domChild = block.getDominator().getFirstDominated();
while (domChild != null) {
if (domChild == block) {
break;
}
domChild = domChild.getDominatedSibling();
}
assert domChild != null : "dominators must contain block";
}
for (T dominated : block.getDominated()) {
T dominated = block.getFirstDominated();
while (dominated != null) {
assert dominated.getId() > block.getId();
assert dominated.getDominator() == block;
dominated = dominated.getDominatedSibling();
}
T postDominatorBlock = block.getPostdominator();

View File

@ -105,4 +105,9 @@ public abstract class Loop<T extends AbstractBlockBase<T>> {
}
return false;
}
@Override
public int hashCode() {
return index + depth * 31;
}
}

View File

@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.core.common.spi;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaField;
@ -32,6 +34,8 @@ public interface ConstantFieldProvider {
public interface ConstantFieldTool<T> {
OptionValues getOptions();
JavaConstant readValue();
JavaConstant getReceiver();

View File

@ -24,7 +24,7 @@ package org.graalvm.compiler.core.common.spi;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionKey;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaType;
@ -39,7 +39,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
static class Options {
@Option(help = "Determines whether to treat final fields with default values as constant.")//
public static final OptionValue<Boolean> TrustFinalDefaultFields = new OptionValue<>(true);
public static final OptionKey<Boolean> TrustFinalDefaultFields = new OptionKey<>(true);
}
protected JavaConstantFieldProvider(MetaAccessProvider metaAccess) {
@ -93,7 +93,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
@SuppressWarnings("unused")
protected boolean isFinalFieldValueConstant(ResolvedJavaField field, JavaConstant value, ConstantFieldTool<?> tool) {
return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue();
return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue(tool.getOptions());
}
@SuppressWarnings("unused")
@ -104,7 +104,7 @@ public abstract class JavaConstantFieldProvider implements ConstantFieldProvider
if (isWellKnownImplicitStableField(field)) {
return true;
}
if (field == stringHashField) {
if (field.equals(stringHashField)) {
return true;
}
return false;

View File

@ -59,8 +59,8 @@ public abstract class AbstractPointerStamp extends Stamp {
return result;
}
@Override
public Stamp join(Stamp stamp) {
protected Stamp defaultPointerJoin(Stamp stamp) {
assert getClass() == stamp.getClass();
AbstractPointerStamp other = (AbstractPointerStamp) stamp;
boolean joinNonNull = this.nonNull || other.nonNull;
boolean joinAlwaysNull = this.alwaysNull || other.alwaysNull;
@ -89,6 +89,42 @@ public abstract class AbstractPointerStamp extends Stamp {
return copyWith(false, false);
}
public static Stamp pointerNonNull(Stamp stamp) {
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
return pointer.asNonNull();
}
public static Stamp pointerMaybeNull(Stamp stamp) {
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
return pointer.asMaybeNull();
}
public static Stamp pointerAlwaysNull(Stamp stamp) {
AbstractPointerStamp pointer = (AbstractPointerStamp) stamp;
return pointer.asAlwaysNull();
}
public Stamp asNonNull() {
if (isEmpty()) {
return this;
}
return copyWith(true, false);
}
public Stamp asMaybeNull() {
if (isEmpty()) {
return this;
}
return copyWith(false, false);
}
public Stamp asAlwaysNull() {
if (isEmpty()) {
return this;
}
return copyWith(false, true);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {

View File

@ -27,11 +27,6 @@ import static jdk.vm.ci.meta.MetaUtil.getSimpleName;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaKind;
import org.graalvm.compiler.core.common.calc.FloatConvert;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
@ -52,6 +47,10 @@ import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Abs;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Neg;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Not;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
import org.graalvm.util.CollectionsUtil;
import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaKind;
/**
* Information about arithmetic operations.
@ -95,12 +94,6 @@ public final class ArithmeticOpTable {
public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
public ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
this(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, Stream.of(floatConvert));
}
public interface ArithmeticOpWrapper {
<OP> UnaryOp<OP> wrapUnaryOp(UnaryOp<OP> op);
@ -147,14 +140,13 @@ public final class ArithmeticOpTable {
IntegerConvertOp<SignExtend> signExtend = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getSignExtend());
IntegerConvertOp<Narrow> narrow = wrapIfNonNull(wrapper::wrapIntegerConvertOp, inner.getNarrow());
Stream<FloatConvertOp> floatConvert = Stream.of(inner.floatConvert).filter(Objects::nonNull).map(wrapper::wrapFloatConvertOp);
FloatConvertOp[] floatConvert = CollectionsUtil.filterAndMapToArray(inner.floatConvert, Objects::nonNull, wrapper::wrapFloatConvertOp, FloatConvertOp[]::new);
return new ArithmeticOpTable(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow, floatConvert);
}
private ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
protected ArithmeticOpTable(UnaryOp<Neg> neg, BinaryOp<Add> add, BinaryOp<Sub> sub, BinaryOp<Mul> mul, BinaryOp<Div> div, BinaryOp<Rem> rem, UnaryOp<Not> not, BinaryOp<And> and, BinaryOp<Or> or,
BinaryOp<Xor> xor, ShiftOp<Shl> shl, ShiftOp<Shr> shr, ShiftOp<UShr> ushr, UnaryOp<Abs> abs, UnaryOp<Sqrt> sqrt, IntegerConvertOp<ZeroExtend> zeroExtend,
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, Stream<FloatConvertOp> floatConvert) {
IntegerConvertOp<SignExtend> signExtend, IntegerConvertOp<Narrow> narrow, FloatConvertOp... floatConvert) {
this.neg = neg;
this.add = add;
this.sub = sub;
@ -174,7 +166,9 @@ public final class ArithmeticOpTable {
this.signExtend = signExtend;
this.narrow = narrow;
this.floatConvert = new FloatConvertOp[FloatConvert.values().length];
floatConvert.forEach(op -> this.floatConvert[op.getFloatConvert().ordinal()] = op);
for (FloatConvertOp op : floatConvert) {
this.floatConvert[op.getFloatConvert().ordinal()] = op;
}
this.hash = Objects.hash(neg, add, sub, mul, div, rem, not, and, or, xor, shl, shr, ushr, abs, sqrt, zeroExtend, signExtend, narrow);
}
@ -318,7 +312,7 @@ public final class ArithmeticOpTable {
}
public static String toString(Op... ops) {
return Arrays.asList(ops).stream().map(o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}").collect(Collectors.joining(","));
return CollectionsUtil.mapAndJoin(ops, o -> o == null ? "null" : o.operator + "{" + getSimpleName(o.getClass(), false) + "}", ",");
}
private boolean opsEquals(ArithmeticOpTable that) {
@ -742,6 +736,11 @@ public final class ArithmeticOpTable {
protected Narrow() {
super("Narrow");
}
@Override
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
return null;
}
}
protected IntegerConvertOp(String op) {
@ -755,5 +754,10 @@ public final class ArithmeticOpTable {
public IntegerConvertOp<T> unwrap() {
return this;
}
/**
* Computes the stamp of the input for the given output stamp.
*/
public abstract Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp);
}
}

View File

@ -46,7 +46,11 @@ public abstract class ArithmeticStamp extends Stamp {
@Override
public Stamp improveWith(Stamp other) {
return this.join(other);
if (this.isCompatible(other)) {
return this.join(other);
}
// Cannot improve, because stamps are not compatible.
return this;
}
@Override
@ -65,7 +69,7 @@ public abstract class ArithmeticStamp extends Stamp {
if (!(obj instanceof ArithmeticStamp)) {
return false;
}
assert Objects.equals(ops, ((ArithmeticStamp) obj).ops);
assert Objects.equals(ops, ((ArithmeticStamp) obj).ops) : ops + " vs. " + ((ArithmeticStamp) obj).ops;
return true;
}
}

View File

@ -301,10 +301,6 @@ public class FloatStamp extends PrimitiveStamp {
return null;
}
public boolean isConstant() {
return (nonNaN && Double.compare(lowerBound, upperBound) == 0);
}
private static final ArithmeticOpTable OPS = new ArithmeticOpTable(
new UnaryOp.Neg() {

View File

@ -31,6 +31,7 @@ import java.nio.ByteBuffer;
import java.util.Formatter;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.FloatConvertOp;
@ -54,41 +55,101 @@ import jdk.vm.ci.meta.SerializableConstant;
* The description consists of (inclusive) lower and upper bounds and up (may be set) and down
* (always set) bit-masks.
*/
public class IntegerStamp extends PrimitiveStamp {
public final class IntegerStamp extends PrimitiveStamp {
private final long lowerBound;
private final long upperBound;
private final long downMask;
private final long upMask;
public IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
private IntegerStamp(int bits, long lowerBound, long upperBound, long downMask, long upMask) {
super(bits, OPS);
this.lowerBound = lowerBound;
this.upperBound = upperBound;
this.downMask = downMask;
this.upMask = upMask;
assert lowerBound >= CodeUtil.minValue(bits) : this;
assert upperBound <= CodeUtil.maxValue(bits) : this;
assert (downMask & CodeUtil.mask(bits)) == downMask : this;
assert (upMask & CodeUtil.mask(bits)) == upMask : this;
}
public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
long lowerBound;
long upperBound;
if (((upMask >>> (bits - 1)) & 1) == 0) {
lowerBound = downMask;
upperBound = upMask;
} else if (((downMask >>> (bits - 1)) & 1) == 1) {
lowerBound = downMask;
upperBound = upMask;
public static IntegerStamp create(int bits, long lowerBoundInput, long upperBoundInput) {
return create(bits, lowerBoundInput, upperBoundInput, 0, CodeUtil.mask(bits));
}
public static IntegerStamp create(int bits, long lowerBoundInput, long upperBoundInput, long downMask, long upMask) {
assert (downMask & ~upMask) == 0 : String.format("\u21ca: %016x \u21c8: %016x", downMask, upMask);
// Set lower bound, use masks to make it more precise
long minValue = minValueForMasks(bits, downMask, upMask);
long lowerBoundTmp = Math.max(lowerBoundInput, minValue);
// Set upper bound, use masks to make it more precise
long maxValue = maxValueForMasks(bits, downMask, upMask);
long upperBoundTmp = Math.min(upperBoundInput, maxValue);
// Assign masks now with the bounds in mind.
final long boundedDownMask;
final long boundedUpMask;
long defaultMask = CodeUtil.mask(bits);
if (lowerBoundTmp == upperBoundTmp) {
boundedDownMask = lowerBoundTmp;
boundedUpMask = lowerBoundTmp;
} else if (lowerBoundTmp >= 0) {
int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBoundTmp);
long differentBits = lowerBoundTmp ^ upperBoundTmp;
int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
boundedUpMask = upperBoundTmp | -1L >>> (upperBoundLeadingZeros + sameBitCount);
boundedDownMask = upperBoundTmp & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
} else {
lowerBound = downMask | (-1L << (bits - 1));
upperBound = CodeUtil.maxValue(bits) & upMask;
if (upperBoundTmp >= 0) {
boundedUpMask = defaultMask;
boundedDownMask = 0;
} else {
int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBoundTmp);
long differentBits = lowerBoundTmp ^ upperBoundTmp;
int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
boundedUpMask = lowerBoundTmp | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
boundedDownMask = lowerBoundTmp & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
}
}
lowerBound = CodeUtil.convert(lowerBound, bits, false);
upperBound = CodeUtil.convert(upperBound, bits, false);
return new IntegerStamp(bits, lowerBound, upperBound, downMask, upMask);
return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask);
}
static long significantBit(long bits, long value) {
return (value >>> (bits - 1)) & 1;
}
static long minValueForMasks(int bits, long downMask, long upMask) {
if (significantBit(bits, upMask) == 0) {
// Value is always positive. Minimum value always positive.
assert significantBit(bits, downMask) == 0;
return downMask;
} else {
// Value can be positive or negative. Minimum value always negative.
return downMask | (-1L << (bits - 1));
}
}
static long maxValueForMasks(int bits, long downMask, long upMask) {
if (significantBit(bits, downMask) == 1) {
// Value is always negative. Maximum value always negative.
assert significantBit(bits, upMask) == 1;
return CodeUtil.signExtend(upMask, bits);
} else {
// Value can be positive or negative. Maximum value always positive.
return upMask & (CodeUtil.mask(bits) >>> 1);
}
}
public static IntegerStamp stampForMask(int bits, long downMask, long upMask) {
return new IntegerStamp(bits, minValueForMasks(bits, downMask, upMask), maxValueForMasks(bits, downMask, upMask), downMask, upMask);
}
@Override
@ -97,7 +158,7 @@ public class IntegerStamp extends PrimitiveStamp {
}
@Override
public Stamp empty() {
public IntegerStamp empty() {
return new IntegerStamp(getBits(), CodeUtil.maxValue(getBits()), CodeUtil.minValue(getBits()), CodeUtil.mask(getBits()), 0);
}
@ -230,23 +291,27 @@ public class IntegerStamp extends PrimitiveStamp {
StringBuilder str = new StringBuilder();
str.append('i');
str.append(getBits());
if (lowerBound == upperBound) {
str.append(" [").append(lowerBound).append(']');
} else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
}
if (downMask != 0) {
str.append(" \u21ca");
new Formatter(str).format("%016x", downMask);
}
if (upMask != CodeUtil.mask(getBits())) {
str.append(" \u21c8");
new Formatter(str).format("%016x", upMask);
if (hasValues()) {
if (lowerBound == upperBound) {
str.append(" [").append(lowerBound).append(']');
} else if (lowerBound != CodeUtil.minValue(getBits()) || upperBound != CodeUtil.maxValue(getBits())) {
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
}
if (downMask != 0) {
str.append(" \u21ca");
new Formatter(str).format("%016x", downMask);
}
if (upMask != CodeUtil.mask(getBits())) {
str.append(" \u21c8");
new Formatter(str).format("%016x", upMask);
}
} else {
str.append("<empty>");
}
return str.toString();
}
private Stamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
private IntegerStamp createStamp(IntegerStamp other, long newUpperBound, long newLowerBound, long newDownMask, long newUpMask) {
assert getBits() == other.getBits();
if (newLowerBound > newUpperBound || (newDownMask & (~newUpMask)) != 0 || (newUpMask == 0 && (newLowerBound > 0 || newUpperBound < 0))) {
return empty();
@ -255,7 +320,7 @@ public class IntegerStamp extends PrimitiveStamp {
} else if (newLowerBound == other.lowerBound && newUpperBound == other.upperBound && newDownMask == other.downMask && newUpMask == other.upMask) {
return other;
} else {
return new IntegerStamp(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
return IntegerStamp.create(getBits(), newLowerBound, newUpperBound, newDownMask, newUpMask);
}
}
@ -269,17 +334,16 @@ public class IntegerStamp extends PrimitiveStamp {
}
@Override
public Stamp join(Stamp otherStamp) {
public IntegerStamp join(Stamp otherStamp) {
if (otherStamp == this) {
return this;
}
IntegerStamp other = (IntegerStamp) otherStamp;
long newDownMask = downMask | other.downMask;
long newLowerBound = Math.max(lowerBound, other.lowerBound) | newDownMask;
long newLowerBound = Math.max(lowerBound, other.lowerBound);
long newUpperBound = Math.min(upperBound, other.upperBound);
long newUpMask = upMask & other.upMask;
IntegerStamp limit = StampFactory.forInteger(getBits(), newLowerBound, newUpperBound);
return createStamp(other, newUpperBound, newLowerBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
return createStamp(other, newUpperBound, newLowerBound, newDownMask, newUpMask);
}
@Override
@ -303,6 +367,24 @@ public class IntegerStamp extends PrimitiveStamp {
return false;
}
public long unsignedUpperBound() {
if (sameSignBounds()) {
return CodeUtil.zeroExtend(upperBound(), getBits());
}
return NumUtil.maxValueUnsigned(getBits());
}
public long unsignedLowerBound() {
if (sameSignBounds()) {
return CodeUtil.zeroExtend(lowerBound(), getBits());
}
return 0;
}
private boolean sameSignBounds() {
return NumUtil.sameSign(lowerBound, upperBound);
}
@Override
public int hashCode() {
final int prime = 31;
@ -369,6 +451,13 @@ public class IntegerStamp extends PrimitiveStamp {
return null;
}
public static boolean addCanOverflow(IntegerStamp a, IntegerStamp b) {
assert a.getBits() == b.getBits();
return addOverflowsPositively(a.upperBound(), b.upperBound(), a.getBits()) ||
addOverflowsNegatively(a.lowerBound(), b.lowerBound(), a.getBits());
}
public static boolean addOverflowsPositively(long x, long y, int bits) {
long result = x + y;
if (bits == 64) {
@ -430,15 +519,59 @@ public class IntegerStamp extends PrimitiveStamp {
}
}
public static boolean multiplicationCanOverflow(IntegerStamp a, IntegerStamp b) {
// see IntegerStamp#foldStamp for details
assert a.getBits() == b.getBits();
if (a.upMask() == 0) {
return false;
} else if (b.upMask() == 0) {
return false;
}
if (a.isUnrestricted()) {
return true;
}
if (b.isUnrestricted()) {
return true;
}
int bits = a.getBits();
long minNegA = a.lowerBound();
long maxNegA = Math.min(0, a.upperBound());
long minPosA = Math.max(0, a.lowerBound());
long maxPosA = a.upperBound();
long minNegB = b.lowerBound();
long maxNegB = Math.min(0, b.upperBound());
long minPosB = Math.max(0, b.lowerBound());
long maxPosB = b.upperBound();
boolean mayOverflow = false;
if (a.canBePositive()) {
if (b.canBePositive()) {
mayOverflow |= IntegerStamp.multiplicationOverflows(maxPosA, maxPosB, bits);
mayOverflow |= IntegerStamp.multiplicationOverflows(minPosA, minPosB, bits);
}
if (b.canBeNegative()) {
mayOverflow |= IntegerStamp.multiplicationOverflows(minPosA, maxNegB, bits);
mayOverflow |= IntegerStamp.multiplicationOverflows(maxPosA, minNegB, bits);
}
}
if (a.canBeNegative()) {
if (b.canBePositive()) {
mayOverflow |= IntegerStamp.multiplicationOverflows(maxNegA, minPosB, bits);
mayOverflow |= IntegerStamp.multiplicationOverflows(minNegA, maxPosB, bits);
}
if (b.canBeNegative()) {
mayOverflow |= IntegerStamp.multiplicationOverflows(minNegA, minNegB, bits);
mayOverflow |= IntegerStamp.multiplicationOverflows(maxNegA, maxNegB, bits);
}
}
return mayOverflow;
}
public static boolean subtractionCanOverflow(IntegerStamp x, IntegerStamp y) {
assert x.getBits() == y.getBits();
// Checkstyle: stop
long x_l = x.lowerBound();
long x_h = x.upperBound();
long y_l = y.lowerBound();
long y_h = y.upperBound();
// Checkstyle: resume
return subtractionOverflows(x_l, y_h, x.getBits()) || subtractionOverflows(x_h, y_l, x.getBits());
return subtractionOverflows(x.lowerBound(), y.upperBound(), x.getBits()) || subtractionOverflows(x.upperBound(), y.lowerBound(), x.getBits());
}
public static boolean subtractionOverflows(long x, long y, int bits) {
@ -618,7 +751,7 @@ public class IntegerStamp extends PrimitiveStamp {
* upper bound after multiplication.
*
* For example if we consider two stamps a & b that both contain
* negative and positive values, the product of minN_a * minN_b
* negative and positive values, the product of minNegA * minNegB
* (both the smallest negative value for each stamp) can only be the
* highest positive number. The other candidates can be computed in
* a similar fashion. Some of them can never be a new minimum or
@ -627,87 +760,86 @@ public class IntegerStamp extends PrimitiveStamp {
*
* @formatter:off
*
* [x..........0..........y]
* -------------------------
* [minN maxN minP maxP]
* where maxN = min(0,y) && minP = max(0,x)
* [x................0................y]
* -------------------------------------
* [minNeg maxNeg minPos maxPos]
*
* where maxNeg = min(0,y) && minPos = max(0,x)
*
*
* |minN_a maxN_a minP_a maxP_a
* _______|________________________________
* minN_b |MAX / : / MIN
* maxN_b | / MIN : MAX /
* |---------------+----------------
* minP_b | / MAX : MIN /
* maxP_b |MIN / : / MAX
* |minNegA maxNegA minPosA maxPosA
* _______ |____________________________________
* minNegB | MAX / : / MIN
* maxNegB | / MIN : MAX /
* |------------------+-----------------
* minPosB | / MAX : MIN /
* maxPosB | MIN / : / MAX
*
* @formatter:on
*/
// We materialize all factors here. If they are needed, the signs of
// the stamp will ensure the correct value is used.
// Checkstyle: stop
long minN_a = a.lowerBound();
long maxN_a = Math.min(0, a.upperBound());
long minP_a = Math.max(0, a.lowerBound());
long maxP_a = a.upperBound();
long minNegA = a.lowerBound();
long maxNegA = Math.min(0, a.upperBound());
long minPosA = Math.max(0, a.lowerBound());
long maxPosA = a.upperBound();
long minN_b = b.lowerBound();
long maxN_b = Math.min(0, b.upperBound());
long minP_b = Math.max(0, b.lowerBound());
long maxP_b = b.upperBound();
// Checkstyle: resume
long minNegB = b.lowerBound();
long maxNegB = Math.min(0, b.upperBound());
long minPosB = Math.max(0, b.lowerBound());
long maxPosB = b.upperBound();
// multiplication has shift semantics
long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
if (a.canBePositive()) {
if (b.canBePositive()) {
if (multiplicationOverflows(maxP_a, maxP_b, bits)) {
if (multiplicationOverflows(maxPosA, maxPosB, bits)) {
return a.unrestricted();
}
long maxCandidate = maxP_a * maxP_b;
if (multiplicationOverflows(minP_a, minP_b, bits)) {
long maxCandidate = maxPosA * maxPosB;
if (multiplicationOverflows(minPosA, minPosB, bits)) {
return a.unrestricted();
}
long minCandidate = minP_a * minP_b;
long minCandidate = minPosA * minPosB;
newLowerBound = Math.min(newLowerBound, minCandidate);
newUpperBound = Math.max(newUpperBound, maxCandidate);
}
if (b.canBeNegative()) {
if (multiplicationOverflows(minP_a, maxN_b, bits)) {
if (multiplicationOverflows(minPosA, maxNegB, bits)) {
return a.unrestricted();
}
long maxCandidate = minP_a * maxN_b;
if (multiplicationOverflows(maxP_a, minN_b, bits)) {
long maxCandidate = minPosA * maxNegB;
if (multiplicationOverflows(maxPosA, minNegB, bits)) {
return a.unrestricted();
}
long minCandidate = maxP_a * minN_b;
long minCandidate = maxPosA * minNegB;
newLowerBound = Math.min(newLowerBound, minCandidate);
newUpperBound = Math.max(newUpperBound, maxCandidate);
}
}
if (a.canBeNegative()) {
if (b.canBePositive()) {
if (multiplicationOverflows(maxN_a, minP_b, bits)) {
if (multiplicationOverflows(maxNegA, minPosB, bits)) {
return a.unrestricted();
}
long maxCandidate = maxN_a * minP_b;
if (multiplicationOverflows(minN_a, maxP_b, bits)) {
long maxCandidate = maxNegA * minPosB;
if (multiplicationOverflows(minNegA, maxPosB, bits)) {
return a.unrestricted();
}
long minCandidate = minN_a * maxP_b;
long minCandidate = minNegA * maxPosB;
newLowerBound = Math.min(newLowerBound, minCandidate);
newUpperBound = Math.max(newUpperBound, maxCandidate);
}
if (b.canBeNegative()) {
if (multiplicationOverflows(minN_a, minN_b, bits)) {
if (multiplicationOverflows(minNegA, minNegB, bits)) {
return a.unrestricted();
}
long maxCandidate = minN_a * minN_b;
if (multiplicationOverflows(maxN_a, maxN_b, bits)) {
long maxCandidate = minNegA * minNegB;
if (multiplicationOverflows(maxNegA, maxNegB, bits)) {
return a.unrestricted();
}
long minCandidate = maxN_a * maxN_b;
long minCandidate = maxNegA * maxNegB;
newLowerBound = Math.min(newLowerBound, minCandidate);
newUpperBound = Math.max(newUpperBound, maxCandidate);
}
@ -1083,22 +1215,28 @@ public class IntegerStamp extends PrimitiveStamp {
assert inputBits == stamp.getBits();
assert inputBits <= resultBits;
long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
if (stamp.lowerBound() < 0 && stamp.upperBound() >= 0) {
/* signed range including 0 and -1 */
/*
* after sign extension, the whole range from 0 to MAX_INT is
* possible
*/
return IntegerStamp.stampForMask(resultBits, downMask, upMask);
if (inputBits == resultBits) {
return input;
}
long lowerBound = CodeUtil.zeroExtend(stamp.lowerBound(), inputBits);
long upperBound = CodeUtil.zeroExtend(stamp.upperBound(), inputBits);
if (input.isEmpty()) {
return StampFactory.forInteger(resultBits).empty();
}
return new IntegerStamp(resultBits, lowerBound, upperBound, downMask, upMask);
long downMask = CodeUtil.zeroExtend(stamp.downMask(), inputBits);
long upMask = CodeUtil.zeroExtend(stamp.upMask(), inputBits);
long lowerBound = stamp.unsignedLowerBound();
long upperBound = stamp.unsignedUpperBound();
return IntegerStamp.create(resultBits, lowerBound, upperBound, downMask, upMask);
}
@Override
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
IntegerStamp stamp = (IntegerStamp) outStamp;
if (stamp.isEmpty()) {
return StampFactory.forInteger(inputBits).empty();
}
return StampFactory.forUnsignedInteger(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask(), stamp.upMask());
}
},
@ -1122,6 +1260,13 @@ public class IntegerStamp extends PrimitiveStamp {
return new IntegerStamp(resultBits, stamp.lowerBound(), stamp.upperBound(), downMask, upMask);
}
@Override
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
IntegerStamp stamp = (IntegerStamp) outStamp;
long mask = CodeUtil.mask(inputBits);
return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask() & mask, stamp.upMask() & mask);
}
},
new IntegerConvertOp.Narrow() {

View File

@ -22,6 +22,9 @@
*/
package org.graalvm.compiler.core.common.type;
import static jdk.vm.ci.code.CodeUtil.signExtend;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.code.CodeUtil;
@ -56,6 +59,11 @@ public class StampFactory {
public boolean equals(Object obj) {
return this == obj;
}
@Override
public String toString() {
return "NodeIntrinsicStamp";
}
}
// JaCoCo Exclude
@ -82,7 +90,7 @@ public class StampFactory {
} else {
mask = CodeUtil.mask(bits);
}
setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
setCache(kind, IntegerStamp.create(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
}
private static void setFloatCache(JavaKind kind) {
@ -156,7 +164,7 @@ public class StampFactory {
}
public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
return IntegerStamp.create(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
}
public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
@ -176,46 +184,35 @@ public class StampFactory {
*/
public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
}
public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
}
public static IntegerStamp forInteger(int bits) {
return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
}
public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
}
public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long downMask, long upMask) {
long lowerBound = signExtend(unsignedLowerBound, bits);
long upperBound = signExtend(unsignedUpperBound, bits);
if (!NumUtil.sameSign(lowerBound, upperBound)) {
lowerBound = CodeUtil.minValue(bits);
upperBound = CodeUtil.maxValue(bits);
}
long mask = CodeUtil.mask(bits);
return IntegerStamp.create(bits, lowerBound, upperBound, downMask & mask, upMask & mask);
}
public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
long defaultMask = CodeUtil.mask(bits);
if (lowerBound == upperBound) {
return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
}
final long downMask;
final long upMask;
if (lowerBound >= 0) {
int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
long differentBits = lowerBound ^ upperBound;
int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
} else {
if (upperBound >= 0) {
upMask = defaultMask;
downMask = 0;
} else {
int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
long differentBits = lowerBound ^ upperBound;
int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
}
}
return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
return IntegerStamp.create(bits, lowerBound, upperBound, 0, CodeUtil.mask(bits));
}
public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {

View File

@ -1,118 +0,0 @@
/*
* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common.util;
/**
* The {@code ArrayMap} class implements an efficient one-level map which is implemented as an
* array. Note that because of the one-level array inside, this data structure performs best when
* the range of integer keys is small and densely used. Note that the implementation can handle
* arbitrary intervals, including negative numbers, up to intervals of size 2^31 - 1.
*/
public class ArrayMap<T> {
private static final int INITIAL_SIZE = 5; // how big the initial array should be
private static final int EXTRA = 2; // how far on the left or right of a new element to grow
Object[] map;
int low;
/**
* Constructs a new {@code ArrayMap} with no initial assumptions.
*/
public ArrayMap() {
}
/**
* Constructs a new {@code ArrayMap} that initially covers the specified interval. Note that
* this map will automatically expand if necessary later.
*
* @param low the low index, inclusive
* @param high the high index, exclusive
*/
public ArrayMap(int low, int high) {
this.low = low;
this.map = new Object[high - low + 1];
}
/**
* Puts a new value in the map at the specified index.
*
* @param i the index at which to store the value
* @param value the value to store at the specified index
*/
public void put(int i, T value) {
int index = i - low;
if (map == null) {
// no map yet
map = new Object[INITIAL_SIZE];
low = index - 2;
map[INITIAL_SIZE / 2] = value;
} else if (index < 0) {
// grow backwards
growBackward(i, value);
} else if (index >= map.length) {
// grow forwards
growForward(i, value);
} else {
// no growth necessary
map[index] = value;
}
}
/**
* Gets the value at the specified index in the map.
*
* @param i the index
* @return the value at the specified index; {@code null} if there is no value at the specified
* index, or if the index is out of the currently stored range
*/
public T get(int i) {
int index = i - low;
if (map == null || index < 0 || index >= map.length) {
return null;
}
Class<T> type = null;
return Util.uncheckedCast(type, map[index]);
}
public int length() {
return map.length;
}
private void growBackward(int i, T value) {
int nlow = i - EXTRA;
Object[] nmap = new Object[low - nlow + map.length];
System.arraycopy(map, 0, nmap, low - nlow, map.length);
map = nmap;
low = nlow;
map[i - low] = value;
}
private void growForward(int i, T value) {
int nlen = i - low + 1 + EXTRA;
Object[] nmap = new Object[nlen];
System.arraycopy(map, 0, nmap, 0, map.length);
map = nmap;
map[i - low] = value;
}
}

View File

@ -23,8 +23,9 @@
package org.graalvm.compiler.core.common.util;
import org.graalvm.compiler.options.Option;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.options.OptionValue;
import org.graalvm.compiler.options.OptionValues;
/**
* Utility class that allows the compiler to monitor compilations that take a very long time.
@ -34,80 +35,74 @@ public final class CompilationAlarm implements AutoCloseable {
public static class Options {
// @formatter:off
@Option(help = "Time limit in seconds before a compilation expires (0 to disable the limit).", type = OptionType.Debug)
public static final OptionValue<Integer> CompilationExpirationPeriod = new OptionValue<>(300);
public static final OptionKey<Integer> CompilationExpirationPeriod = new OptionKey<>(300);
// @formatter:on
}
private CompilationAlarm() {
}
private static boolean enabled() {
return Options.CompilationExpirationPeriod.getValue() > 0;
private CompilationAlarm(long expiration) {
this.expiration = expiration;
}
/**
* Thread local storage for compilation start timestamps. Everytime a compiler thread calls
* {@link #trackCompilationPeriod()} it will save the start timestamp of the compilation.
* Thread local storage for the active compilation alarm.
*/
private static final ThreadLocal<Long> compilationStartedTimeStamps = new ThreadLocal<>();
private static final ThreadLocal<CompilationAlarm> currentAlarm = new ThreadLocal<>();
private static boolean compilationStarted() {
if (enabled()) {
Long start = compilationStartedTimeStamps.get();
if (start == null) {
compilationStartedTimeStamps.set(System.currentTimeMillis());
return true;
}
}
return false;
}
private static final CompilationAlarm NEVER_EXPIRES = new CompilationAlarm(0);
private static void compilationFinished() {
if (enabled()) {
assert compilationStartedTimeStamps.get() != null;
compilationStartedTimeStamps.set(null);
}
/**
* Gets the current compilation alarm. If there is no current alarm, a non-null value is
* returned that will always return {@code false} for {@link #hasExpired()}.
*/
public static CompilationAlarm current() {
CompilationAlarm alarm = currentAlarm.get();
return alarm == null ? NEVER_EXPIRES : alarm;
}
/**
* Determines if the current compilation is expired. A compilation expires if it takes longer
* than {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}.
* Determines if this alarm has expired. A compilation expires if it takes longer than
* {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}.
*
* @return {@code true} if the current compilation already takes longer than
* {@linkplain CompilationAlarm.Options#CompilationExpirationPeriod}, {@code false}
* otherwise
*/
public static boolean hasExpired() {
if (enabled()) {
Long start = compilationStartedTimeStamps.get();
if (start != null) {
long time = System.currentTimeMillis();
assert time >= start;
return time - start > Options.CompilationExpirationPeriod.getValue() * 1000;
}
}
return false;
public boolean hasExpired() {
return this != NEVER_EXPIRES && System.currentTimeMillis() > expiration;
}
@Override
public void close() {
compilationFinished();
if (this != NEVER_EXPIRES) {
currentAlarm.set(null);
}
}
private static final CompilationAlarm INSTANCE = enabled() ? new CompilationAlarm() : null;
/**
* The time at which this alarm expires.
*/
private final long expiration;
/**
* Gets an object that can be used in a try-with-resource statement to set an time limit based
* alarm for a compilation.
* Starts an alarm for setting a time limit on a compilation if there isn't already an active
* alarm and {@link CompilationAlarm.Options#CompilationExpirationPeriod}{@code > 0}. The
* returned value can be used in a try-with-resource statement to disable the alarm once the
* compilation is finished.
*
* @return a {@link CompilationAlarm} instance if there is no current alarm for the calling
* thread otherwise {@code null}
* @return a {@link CompilationAlarm} if there was no current alarm for the calling thread
* before this call otherwise {@code null}
*/
public static CompilationAlarm trackCompilationPeriod() {
if (compilationStarted()) {
return INSTANCE;
public static CompilationAlarm trackCompilationPeriod(OptionValues options) {
int period = Options.CompilationExpirationPeriod.getValue(options);
if (period > 0) {
CompilationAlarm current = currentAlarm.get();
if (current == null) {
long expiration = System.currentTimeMillis() + period * 1000;
current = new CompilationAlarm(expiration);
currentAlarm.set(current);
return current;
}
}
return null;
}
}

View File

@ -31,6 +31,8 @@ import java.util.Arrays;
*/
public final class IntList {
private static final int[] EMPTY_INT_ARRAY = new int[0];
private int[] array;
private int size;
@ -80,9 +82,13 @@ public final class IntList {
*/
public static IntList copy(IntList other, int startIndex, int length, int initialCapacity) {
assert initialCapacity >= length : "initialCapacity < length";
int[] array = new int[initialCapacity];
System.arraycopy(other.array, startIndex, array, 0, length);
return new IntList(array, length);
if (initialCapacity == 0) {
return new IntList(EMPTY_INT_ARRAY, 0);
} else {
int[] array = new int[initialCapacity];
System.arraycopy(other.array, startIndex, array, 0, length);
return new IntList(array, length);
}
}
public int size() {

View File

@ -24,6 +24,7 @@ package org.graalvm.compiler.core.common.util;
import static org.graalvm.compiler.core.common.util.Util.JAVA_SPECIFICATION_VERSION;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@ -57,11 +58,21 @@ public final class ModuleAPI {
*/
public static final ModuleAPI addExports;
/**
* {@code jdk.internal.module.Modules.addOpens(Module, String, Module)}.
*/
public static final ModuleAPI addOpens;
/**
* {@code java.lang.reflect.Module.getResourceAsStream(String)}.
*/
public static final ModuleAPI getResourceAsStream;
/**
* {@code java.lang.reflect.Module.getPackages()}.
*/
public static final ModuleAPI getPackages;
/**
* {@code java.lang.reflect.Module.canRead(Module)}.
*/
@ -105,6 +116,47 @@ public final class ModuleAPI {
}
}
/**
* Opens all packages in {@code moduleMember}'s module for deep reflection (i.e., allow
* {@link AccessibleObject#setAccessible(boolean)} to be called for any class/method/field) by
* {@code requestor}'s module.
*/
public static void openAllPackagesForReflectionTo(Class<?> moduleMember, Class<?> requestor) {
Object moduleToOpen = getModule.invoke(moduleMember);
Object requestorModule = getModule.invoke(requestor);
if (moduleToOpen != requestorModule) {
String[] packages = getPackages.invoke(moduleToOpen);
for (String pkg : packages) {
addOpens.invokeStatic(moduleToOpen, pkg, requestorModule);
}
}
}
/**
* Opens {@code declaringClass}'s package to allow a method declared in {@code accessor} to call
* {@link AccessibleObject#setAccessible(boolean)} on an {@link AccessibleObject} representing a
* field or method declared by {@code declaringClass}.
*/
public static void openForReflectionTo(Class<?> declaringClass, Class<?> accessor) {
Object moduleToOpen = getModule.invoke(declaringClass);
Object accessorModule = getModule.invoke(accessor);
if (moduleToOpen != accessorModule) {
addOpens.invokeStatic(moduleToOpen, declaringClass.getPackage().getName(), accessorModule);
}
}
/**
* Exports the package named {@code packageName} declared in {@code moduleMember}'s module to
* {@code requestor}'s module.
*/
public static void exportPackageTo(Class<?> moduleMember, String packageName, Class<?> requestor) {
Object moduleToExport = getModule.invoke(moduleMember);
Object requestorModule = getModule.invoke(requestor);
if (moduleToExport != requestorModule) {
addExports.invokeStatic(moduleToExport, packageName, requestorModule);
}
}
private void checkAvailability() throws InternalError {
if (method == null) {
throw new InternalError("Cannot use Module API on JDK " + JAVA_SPECIFICATION_VERSION);
@ -118,10 +170,12 @@ public final class ModuleAPI {
Class<?> moduleClass = getModule.method.getReturnType();
Class<?> modulesClass = Class.forName("jdk.internal.module.Modules");
getResourceAsStream = new ModuleAPI(moduleClass.getMethod("getResourceAsStream", String.class));
getPackages = new ModuleAPI(moduleClass.getMethod("getPackages"));
canRead = new ModuleAPI(moduleClass.getMethod("canRead", moduleClass));
isExported = new ModuleAPI(moduleClass.getMethod("isExported", String.class));
isExportedTo = new ModuleAPI(moduleClass.getMethod("isExported", String.class, moduleClass));
addExports = new ModuleAPI(modulesClass.getDeclaredMethod("addExports", moduleClass, String.class, moduleClass));
addOpens = new ModuleAPI(modulesClass.getDeclaredMethod("addOpens", moduleClass, String.class, moduleClass));
} catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) {
throw new InternalError(e);
}
@ -129,10 +183,12 @@ public final class ModuleAPI {
ModuleAPI unavailable = new ModuleAPI(null);
getModule = unavailable;
getResourceAsStream = unavailable;
getPackages = unavailable;
canRead = unavailable;
isExported = unavailable;
isExportedTo = unavailable;
addExports = unavailable;
addOpens = unavailable;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -20,36 +20,39 @@
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.api.collections;
package org.graalvm.compiler.core.common.util;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.AbstractList;
import java.util.List;
import java.util.RandomAccess;
/**
* A default implementation of {@link CollectionsProvider} that creates standard JDK collection
* class objects.
* A {@code ReversedList} is a view on an other list with the elements in reverse order.
*
* This implementation is made for {@link RandomAccess} lists.
*/
public class DefaultCollectionsProvider implements CollectionsProvider {
public class ReversedList<T> extends AbstractList<T> implements RandomAccess {
private final List<T> original;
@Override
public <E> Set<E> newIdentitySet() {
return Collections.newSetFromMap(newIdentityMap());
public ReversedList(List<T> original) {
assert original instanceof RandomAccess;
this.original = original;
}
@Override
public <K, V> Map<K, V> newIdentityMap() {
return new IdentityHashMap<>();
public T get(int index) {
return original.get(original.size() - index - 1);
}
@Override
public <K, V> Map<K, V> newIdentityMap(int expectedMaxSize) {
return new IdentityHashMap<>(expectedMaxSize);
public int size() {
return original.size();
}
@Override
public <K, V> Map<K, V> newIdentityMap(Map<K, V> initFrom) {
return new IdentityHashMap<>(initFrom);
/**
* Creates a list that is a view on {@code list} in reverse order.
*/
public static <T> ReversedList<T> reversed(List<T> list) {
return new ReversedList<>(list);
}
}

View File

@ -22,9 +22,9 @@
*/
package org.graalvm.compiler.core.common.util;
import static org.graalvm.compiler.core.common.GraalOptions.HotSpotPrintInlining;
import java.util.Collection;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Executable;
import java.lang.reflect.Field;
import java.util.List;
import org.graalvm.compiler.debug.TTY;
@ -74,29 +74,6 @@ public class Util {
return (T) object;
}
public interface Stringify {
String apply(Object o);
}
public static String join(Collection<?> c, String sep) {
return join(c, sep, "", "", null);
}
public static String join(Collection<?> c, String sep, String prefix, String suffix, Stringify stringify) {
StringBuilder buf = new StringBuilder(prefix);
boolean first = true;
for (Object e : c) {
if (!first) {
buf.append(sep);
} else {
first = false;
}
buf.append(stringify != null ? stringify.apply(e) : String.valueOf(e));
}
buf.append(suffix);
return buf.toString();
}
/**
* Sets the element at a given position of a list and ensures that this position exists. If the
* list is current shorter than the position, intermediate positions are filled with a given
@ -191,25 +168,45 @@ public class Util {
* Print a HotSpot-style inlining message to the console.
*/
public static void printInlining(final ResolvedJavaMethod method, final int bci, final int inliningDepth, final boolean success, final String msg, final Object... args) {
if (HotSpotPrintInlining.getValue()) {
StringBuilder sb = new StringBuilder();
// 1234567
sb.append(" "); // print timestamp
// 1234
sb.append(" "); // print compilation number
// % s ! b n
sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
sb.append(" "); // more indent
sb.append(" "); // initial inlining indent
for (int i = 0; i < inliningDepth; i++) {
sb.append(" ");
}
sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
TTY.println(sb.toString());
StringBuilder sb = new StringBuilder();
// 1234567
sb.append(" "); // print timestamp
// 1234
sb.append(" "); // print compilation number
// % s ! b n
sb.append(String.format("%c%c%c%c%c ", ' ', method.isSynchronized() ? 's' : ' ', ' ', ' ', method.isNative() ? 'n' : ' '));
sb.append(" "); // more indent
sb.append(" "); // initial inlining indent
for (int i = 0; i < inliningDepth; i++) {
sb.append(" ");
}
sb.append(String.format("@ %d %s %s%s", bci, methodName(method), success ? "" : "not inlining ", String.format(msg, args)));
TTY.println(sb.toString());
}
private static String methodName(ResolvedJavaMethod method) {
return method.format("%H.%n(%p):%r") + " (" + method.getCodeSize() + " bytes)";
}
/**
* Calls {@link AccessibleObject#setAccessible(boolean)} on {@code field} with the value
* {@code flag}.
*/
public static void setAccessible(Field field, boolean flag) {
if (!Java8OrEarlier) {
ModuleAPI.openForReflectionTo(field.getDeclaringClass(), Util.class);
}
field.setAccessible(flag);
}
/**
* Calls {@link AccessibleObject#setAccessible(boolean)} on {@code executable} with the value
* {@code flag}.
*/
public static void setAccessible(Executable executable, boolean flag) {
if (!Java8OrEarlier) {
ModuleAPI.openForReflectionTo(executable.getDeclaringClass(), Util.class);
}
executable.setAccessible(flag);
}
}

View File

@ -27,12 +27,8 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -74,6 +70,9 @@ import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Position;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.serviceprovider.ServiceProvider;
import org.graalvm.util.Equivalence;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet;
/**
* Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
@ -206,13 +205,13 @@ public class MatchProcessor extends AbstractProcessor {
name = next();
}
originatingElements.addAll(type.originatingElements);
requiredPackages.add(type.nodePackage);
} else if (Character.isLowerCase(peek("name").charAt(0))) {
name = next();
type = valueType;
} else {
throw new RuleParseError("Unexpected token \"%s\" when looking for name or node type", peek(null));
}
requiredPackages.add(type.nodePackage);
if (name != null) {
if (!capturedNames.contains(name)) {
capturedNames.add(name);
@ -234,7 +233,7 @@ public class MatchProcessor extends AbstractProcessor {
/**
* Recursively accumulate any required Position declarations.
*/
void generatePositionDeclarations(Set<String> declarations) {
void generatePositionDeclarations(EconomicSet<String> declarations) {
matchDescriptor.generatePositionDeclarations(declarations);
}
@ -366,7 +365,7 @@ public class MatchProcessor extends AbstractProcessor {
/**
* The types which are know for purpose of parsing MatchRule expressions.
*/
Map<String, TypeDescriptor> knownTypes = new HashMap<>();
EconomicMap<String, TypeDescriptor> knownTypes = EconomicMap.create(Equivalence.DEFAULT);
private TypeDescriptor valueType;
@ -407,7 +406,7 @@ public class MatchProcessor extends AbstractProcessor {
}
}
public void generatePositionDeclarations(Set<String> declarations) {
public void generatePositionDeclarations(EconomicSet<String> declarations) {
if (inputs.length == 0) {
return;
}
@ -532,7 +531,7 @@ public class MatchProcessor extends AbstractProcessor {
out.println();
// Generate declarations for the wrapper class to invoke the code generation methods.
for (MethodInvokerItem invoker : info.invokers.values()) {
for (MethodInvokerItem invoker : info.invokers.getValues()) {
StringBuilder args = new StringBuilder();
StringBuilder types = new StringBuilder();
int count = invoker.fields.size();
@ -663,14 +662,14 @@ public class MatchProcessor extends AbstractProcessor {
final TypeElement topDeclaringType;
final List<MatchRuleItem> matchRules = new ArrayList<>();
private final Set<Element> originatingElements = new HashSet<>();
public Set<String> positionDeclarations = new LinkedHashSet<>();
private final EconomicSet<Element> originatingElements = EconomicSet.create(Equivalence.DEFAULT);
public EconomicSet<String> positionDeclarations = EconomicSet.create(Equivalence.DEFAULT);
/**
* The mapping between elements with MatchRules and the wrapper class used invoke the code
* generation after the match.
*/
Map<String, MethodInvokerItem> invokers = new LinkedHashMap<>();
EconomicMap<String, MethodInvokerItem> invokers = EconomicMap.create(Equivalence.DEFAULT);
/**
* The set of packages which must be imported to refer the classes mention in matchRules.
@ -728,7 +727,7 @@ public class MatchProcessor extends AbstractProcessor {
TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
Map<TypeElement, MatchRuleDescriptor> map = new LinkedHashMap<>();
EconomicMap<TypeElement, MatchRuleDescriptor> map = EconomicMap.create(Equivalence.DEFAULT);
for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
currentElement = element;
@ -740,7 +739,7 @@ public class MatchProcessor extends AbstractProcessor {
}
currentElement = null;
for (MatchRuleDescriptor info : map.values()) {
for (MatchRuleDescriptor info : map.getValues()) {
createFiles(info);
}
@ -834,7 +833,7 @@ public class MatchProcessor extends AbstractProcessor {
declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
}
private void processMatchRule(Map<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
private void processMatchRule(EconomicMap<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
if (!processedMatchRule.contains(element)) {
try {
processedMatchRule.add(element);
@ -961,7 +960,7 @@ public class MatchProcessor extends AbstractProcessor {
Element enclosing = method.getEnclosingElement();
String declaringClass = "";
String separator = "";
Set<Element> originatingElementsList = info.originatingElements;
EconomicSet<Element> originatingElementsList = info.originatingElements;
originatingElementsList.add(method);
while (enclosing != null) {
if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {

View File

@ -22,23 +22,24 @@
*/
package org.graalvm.compiler.core.sparc.test;
import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
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 jdk.vm.ci.sparc.SPARC;
import org.junit.Before;
import org.junit.Test;
import org.graalvm.compiler.core.test.backend.AllocatorTest;
import jdk.vm.ci.sparc.SPARC;
public class SPARCAllocatorTest extends AllocatorTest {
@Before
public void checkSPARC() {
assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC);
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue() == null);
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue());
assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
}
@Test
@ -47,7 +48,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
}
public static long test1snippet(long x) {
return x + 5;
return x + 41;
}
@Test
@ -56,7 +57,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
}
public static long test2snippet(long x) {
return x * 5;
return x * 41;
}
@Test
@ -65,7 +66,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
}
public static long test3snippet(long x) {
return x / 3 + x % 3;
return x / 41 + x % 41;
}
}

View File

@ -113,12 +113,13 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
@Override
public Variable emitBitCount(Value operand) {
Variable result = getLIRGen().newVariable(LIRKind.combine(operand).changeType(SPARCKind.WORD));
Value usedOperand = operand;
AllocatableValue usedOperand = getLIRGen().asAllocatable(operand);
if (operand.getPlatformKind() == SPARCKind.WORD) { // Zero extend
usedOperand = getLIRGen().newVariable(operand.getValueKind());
getLIRGen().append(new SPARCOP3Op(Op3s.Srl, operand, SPARC.g0.asValue(), usedOperand));
AllocatableValue intermediateOperand = getLIRGen().newVariable(operand.getValueKind());
getLIRGen().append(new SPARCOP3Op(Op3s.Srl, usedOperand, g0.asValue(), intermediateOperand));
usedOperand = intermediateOperand;
}
getLIRGen().append(new SPARCOP3Op(Op3s.Popc, SPARC.g0.asValue(), usedOperand, result));
getLIRGen().append(new SPARCOP3Op(Op3s.Popc, g0.asValue(), usedOperand, result));
return result;
}
@ -141,9 +142,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
}
@Override
public Value emitMathAbs(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
SPARCKind kind = (SPARCKind) input.getPlatformKind();
public Value emitMathAbs(Value inputValue) {
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
Opfs opf;
switch (kind) {
case SINGLE:
@ -155,14 +156,14 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
default:
throw GraalError.shouldNotReachHere("Input kind: " + kind);
}
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
return result;
}
@Override
public Value emitMathSqrt(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
SPARCKind kind = (SPARCKind) input.getPlatformKind();
public Value emitMathSqrt(Value inputValue) {
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
SPARCKind kind = (SPARCKind) inputValue.getPlatformKind();
Opfs opf;
switch (kind) {
case SINGLE:
@ -174,7 +175,7 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
default:
throw GraalError.shouldNotReachHere("Input kind: " + kind);
}
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
return result;
}
@ -193,9 +194,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
return emitUnary(Xnor, input);
}
private Variable emitUnary(Opfs opf, Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), input, result));
private Variable emitUnary(Opfs opf, Value inputValue) {
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue));
getLIRGen().append(new SPARCOPFOp(opf, g0.asValue(), getLIRGen().asAllocatable(inputValue), result));
return result;
}
@ -211,11 +212,7 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
private Variable emitBinary(ValueKind<?> resultKind, Opfs opf, Value a, Value b, LIRFrameState state) {
Variable result = getLIRGen().newVariable(resultKind);
if (opf.isCommutative() && isJavaConstant(a) && getLIRGen().getMoveFactory().canInlineConstant(asJavaConstant(a))) {
getLIRGen().append(new SPARCOPFOp(opf, b, a, result, state));
} else {
getLIRGen().append(new SPARCOPFOp(opf, a, b, result, state));
}
getLIRGen().append(new SPARCOPFOp(opf, getLIRGen().asAllocatable(a), getLIRGen().asAllocatable(b), result, state));
return result;
}
@ -495,78 +492,78 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
}
@Override
public Value emitFloatConvert(FloatConvert op, Value inputVal) {
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
Value result;
public Value emitFloatConvert(FloatConvert op, Value inputValue) {
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
AllocatableValue result;
switch (op) {
case D2F:
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(SINGLE));
getLIRGen().append(new SPARCOPFOp(Fdtos, inputVal, result));
result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(SINGLE));
getLIRGen().append(new SPARCOPFOp(Fdtos, inputAllocatable, result));
break;
case F2D:
result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(DOUBLE));
getLIRGen().append(new SPARCOPFOp(Fstod, inputVal, result));
result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(DOUBLE));
getLIRGen().append(new SPARCOPFOp(Fstod, inputAllocatable, result));
break;
case I2F: {
AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
AllocatableValue intEncodedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
result = getLIRGen().newVariable(intEncodedFloatReg.getValueKind());
moveBetweenFpGp(intEncodedFloatReg, input);
moveBetweenFpGp(intEncodedFloatReg, inputAllocatable);
getLIRGen().append(new SPARCOPFOp(Fitos, intEncodedFloatReg, result));
break;
}
case I2D: {
// Unfortunately we must do int -> float -> double because fitod has float
// and double encoding in one instruction
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
moveBetweenFpGp(convertedFloatReg, input);
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
moveBetweenFpGp(convertedFloatReg, inputAllocatable);
getLIRGen().append(new SPARCOPFOp(Fitod, convertedFloatReg, result));
break;
}
case L2D: {
AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
moveBetweenFpGp(longEncodedDoubleReg, input);
AllocatableValue longEncodedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
moveBetweenFpGp(longEncodedDoubleReg, inputAllocatable);
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(longEncodedDoubleReg.getValueKind());
getLIRGen().append(new SPARCOPFOp(Fxtod, longEncodedDoubleReg, convertedDoubleReg));
result = convertedDoubleReg;
break;
}
case D2I: {
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, input, convertedFloatReg));
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2I, inputAllocatable, convertedFloatReg));
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
result = convertedIntReg;
break;
}
case F2L: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, input, convertedDoubleReg));
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2L, inputAllocatable, convertedDoubleReg));
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
result = convertedLongReg;
break;
}
case F2I: {
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, input, convertedFloatReg));
AllocatableValue convertedFloatReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.F2I, inputAllocatable, convertedFloatReg));
AllocatableValue convertedIntReg = getLIRGen().newVariable(LIRKind.combine(convertedFloatReg).changeType(WORD));
moveBetweenFpGp(convertedIntReg, convertedFloatReg);
result = convertedIntReg;
break;
}
case D2L: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, input, convertedDoubleReg));
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
getLIRGen().append(new SPARCArithmetic.FloatConvertOp(FloatConvertOp.FloatConvert.D2L, inputAllocatable, convertedDoubleReg));
AllocatableValue convertedLongReg = getLIRGen().newVariable(LIRKind.combine(convertedDoubleReg).changeType(XWORD));
moveBetweenFpGp(convertedLongReg, convertedDoubleReg);
result = convertedLongReg;
break;
}
case L2F: {
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(input).changeType(DOUBLE));
result = getLIRGen().newVariable(LIRKind.combine(input).changeType(SINGLE));
moveBetweenFpGp(convertedDoubleReg, input);
AllocatableValue convertedDoubleReg = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(DOUBLE));
result = getLIRGen().newVariable(LIRKind.combine(inputAllocatable).changeType(SINGLE));
moveBetweenFpGp(convertedDoubleReg, inputAllocatable);
getLIRGen().append(new SPARCOPFOp(Opfs.Fxtos, convertedDoubleReg, result));
break;
}
@ -609,10 +606,9 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
assert fromBits <= toBits && toBits <= XWORD.getSizeInBits();
LIRKind shiftKind = LIRKind.value(WORD);
LIRKind resultKind = LIRKind.combine(inputVal).changeType(toBits > 32 ? XWORD : WORD);
Value result;
int shiftCount = XWORD.getSizeInBits() - fromBits;
if (fromBits == toBits) {
result = inputVal;
return inputVal;
} else if (isJavaConstant(inputVal)) {
JavaConstant javaConstant = asJavaConstant(inputVal);
long constant;
@ -622,30 +618,33 @@ public class SPARCArithmeticLIRGenerator extends ArithmeticLIRGenerator {
constant = javaConstant.asLong();
}
return new ConstantValue(resultKind, JavaConstant.forLong((constant << shiftCount) >> shiftCount));
} else if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new SPARCOP3Op(Sra, inputVal, SPARC.g0.asValue(LIRKind.value(WORD)), result));
} else {
Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
result = getLIRGen().newVariable(resultKind);
getLIRGen().append(new SPARCOP3Op(Sllx, inputVal, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputVal);
Variable result = getLIRGen().newVariable(resultKind);
if (fromBits == WORD.getSizeInBits() && toBits == XWORD.getSizeInBits()) {
getLIRGen().append(new SPARCOP3Op(Sra, inputAllocatable, g0.asValue(LIRKind.value(WORD)), result));
} else {
Variable tmp = getLIRGen().newVariable(resultKind.changeType(XWORD));
getLIRGen().append(new SPARCOP3Op(Sllx, inputAllocatable, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), tmp));
getLIRGen().append(new SPARCOP3Op(Srax, tmp, new ConstantValue(shiftKind, JavaConstant.forInt(shiftCount)), result));
}
return result;
}
return result;
}
@Override
public Value emitZeroExtend(Value inputVal, int fromBits, int toBits) {
public Value emitZeroExtend(Value inputValue, int fromBits, int toBits) {
assert fromBits <= toBits && toBits <= 64;
if (fromBits == toBits) {
return inputVal;
return inputValue;
}
Variable result = getLIRGen().newVariable(LIRKind.combine(inputVal).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
Variable result = getLIRGen().newVariable(LIRKind.combine(inputValue).changeType(toBits > WORD.getSizeInBits() ? XWORD : WORD));
AllocatableValue inputAllocatable = getLIRGen().asAllocatable(inputValue);
if (fromBits == 32) {
getLIRGen().append(new SPARCOP3Op(Srl, inputVal, g0.asValue(), result));
getLIRGen().append(new SPARCOP3Op(Srl, inputAllocatable, g0.asValue(), result));
} else {
Value mask = getLIRGen().emitConstant(LIRKind.value(XWORD), forLong(mask(fromBits)));
getLIRGen().append(new SPARCOP3Op(And, inputVal, mask, result));
getLIRGen().append(new SPARCOP3Op(And, inputAllocatable, mask, result));
}
return result;
}

View File

@ -67,4 +67,19 @@ public class SPARCImmediateAddressNode extends AddressNode implements LIRLowerab
gen.setResult(this, new SPARCImmediateAddressValue(kind, baseValue, displacement));
}
@Override
public ValueNode getBase() {
return base;
}
@Override
public long getMaxConstantDisplacement() {
return displacement;
}
@Override
public ValueNode getIndex() {
return null;
}
}

View File

@ -65,6 +65,7 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
gen.setResult(this, new SPARCIndexedAddressValue(kind, baseValue, indexValue));
}
@Override
public ValueNode getBase() {
return base;
}
@ -74,6 +75,7 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
this.base = base;
}
@Override
public ValueNode getIndex() {
return index;
}
@ -82,4 +84,9 @@ public class SPARCIndexedAddressNode extends AddressNode implements LIRLowerable
updateUsages(this.index, index);
this.index = index;
}
@Override
public long getMaxConstantDisplacement() {
return Long.MAX_VALUE;
}
}

View File

@ -194,7 +194,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
@Override
public void emitCompareBranch(PlatformKind cmpKind, Value x, Value y, Condition cond, boolean unorderedIsTrue, LabelRef trueDestination, LabelRef falseDestination,
double trueDestinationProbability) {
Value left;
AllocatableValue left;
Value right;
Condition actualCondition;
if (isJavaConstant(x)) {
@ -234,9 +234,9 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
private void emitIntegerTest(Value a, Value b) {
assert ((SPARCKind) a.getPlatformKind()).isInteger();
if (LIRValueUtil.isVariable(b)) {
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadNonConst(a)));
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(b), loadSimm13(a)));
} else {
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadNonConst(b)));
append(SPARCOP3Op.newBinaryVoid(Op3s.Andcc, load(a), loadSimm13(b)));
}
}
@ -250,6 +250,16 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
return load(value);
}
private Value loadSimm13(Value value) {
if (isJavaConstant(value)) {
JavaConstant c = asJavaConstant(value);
if (c.isNull() || SPARCAssembler.isSimm13(c)) {
return value;
}
}
return load(value);
}
@Override
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
// Emit compare
@ -304,24 +314,24 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
private boolean emitIntegerCompare(SPARCKind cmpKind, Value a, Value b) {
boolean mirrored;
assert cmpKind.isInteger();
Value left;
AllocatableValue left;
Value right;
if (LIRValueUtil.isVariable(b)) {
left = load(b);
right = loadNonConst(a);
right = loadSimm13(a);
mirrored = true;
} else {
left = load(a);
right = loadNonConst(b);
right = loadSimm13(b);
mirrored = false;
}
int compareBytes = cmpKind.getSizeInBytes();
// SPARC compares 32 or 64 bits
if (compareBytes < left.getPlatformKind().getSizeInBytes()) {
left = arithmeticLIRGen.emitSignExtend(left, compareBytes * 8, XWORD.getSizeInBytes() * 8);
left = asAllocatable(arithmeticLIRGen.emitSignExtend(left, cmpKind.getSizeInBits(), XWORD.getSizeInBits()));
}
if (compareBytes < right.getPlatformKind().getSizeInBytes()) {
right = arithmeticLIRGen.emitSignExtend(right, compareBytes * 8, XWORD.getSizeInBytes() * 8);
right = arithmeticLIRGen.emitSignExtend(right, cmpKind.getSizeInBits(), XWORD.getSizeInBits());
}
append(SPARCOP3Op.newBinaryVoid(Subcc, left, right));
return mirrored;
@ -365,10 +375,10 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
@Override
public void emitStrategySwitch(SwitchStrategy strategy, Variable key, LabelRef[] keyTargets, LabelRef defaultTarget) {
AllocatableValue scratchValue = newVariable(key.getValueKind());
Variable scratchValue = newVariable(key.getValueKind());
AllocatableValue base = AllocatableValue.ILLEGAL;
for (Constant c : strategy.getKeyConstants()) {
if (!(c instanceof JavaConstant) || !getMoveFactory().canInlineConstant((JavaConstant) c)) {
if (!getMoveFactory().canInlineConstant(c)) {
base = constantTableBaseProvider.getConstantTableBase();
break;
}
@ -376,7 +386,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
append(createStrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue));
}
protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, AllocatableValue scratchValue) {
protected StrategySwitchOp createStrategySwitchOp(AllocatableValue base, SwitchStrategy strategy, LabelRef[] keyTargets, LabelRef defaultTarget, Variable key, Variable scratchValue) {
return new StrategySwitchOp(base, strategy, keyTargets, defaultTarget, key, scratchValue);
}
@ -396,7 +406,7 @@ public abstract class SPARCLIRGenerator extends LIRGenerator {
@Override
public Variable emitByteSwap(Value input) {
Variable result = newVariable(LIRKind.combine(input));
append(new SPARCByteSwapOp(this, result, input));
append(new SPARCByteSwapOp(this, result, asAllocatable(input)));
return result;
}

View File

@ -91,21 +91,25 @@ public class SPARCMoveFactory implements MoveFactory {
}
@Override
public boolean canInlineConstant(JavaConstant c) {
switch (c.getJavaKind()) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
return SPARCAssembler.isSimm13(c.asInt());
case Long:
return SPARCAssembler.isSimm13(c.asLong());
case Object:
return c.isNull();
default:
return false;
public boolean canInlineConstant(Constant con) {
if (con instanceof JavaConstant) {
JavaConstant c = (JavaConstant) con;
switch (c.getJavaKind()) {
case Boolean:
case Byte:
case Char:
case Short:
case Int:
return SPARCAssembler.isSimm13(c.asInt());
case Long:
return SPARCAssembler.isSimm13(c.asLong());
case Object:
return c.isNull();
default:
return false;
}
}
return false;
}
@Override

View File

@ -29,17 +29,27 @@ import static jdk.vm.ci.sparc.SPARCKind.WORD;
import static jdk.vm.ci.sparc.SPARCKind.XWORD;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
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.debug.GraalError;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LabelRef;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
import org.graalvm.compiler.lir.sparc.SPARCAddressValue;
import org.graalvm.compiler.nodes.DeoptimizingNode;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.CompareNode;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
import org.graalvm.compiler.nodes.memory.Access;
import org.graalvm.compiler.nodes.memory.LIRLowerableAccess;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.sparc.SPARCKind;
/**
@ -58,6 +68,10 @@ public class SPARCNodeMatchRules extends NodeMatchRules {
return null;
}
protected LIRKind getLirKind(LIRLowerableAccess access) {
return gen.getLIRKind(access.getAccessStamp());
}
private ComplexMatchResult emitSignExtendMemory(Access access, int fromBits, int toBits) {
assert fromBits <= toBits && toBits <= 64;
SPARCKind toKind = null;
@ -127,6 +141,41 @@ public class SPARCNodeMatchRules extends NodeMatchRules {
return emitZeroExtendMemory(access, root.getInputBits(), root.getResultBits());
}
@MatchRule("(If (ObjectEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (PointerEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (FloatEquals=compare value LogicCompareAndSwap=cas))")
@MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
JavaConstant constant = value.asJavaConstant();
assert compare.condition() == Condition.EQ;
if (constant != null && cas.usages().count() == 1) {
long constantValue = constant.asLong();
boolean successIsTrue;
if (constantValue == 0) {
successIsTrue = false;
} else if (constantValue == 1) {
successIsTrue = true;
} else {
return null;
}
return builder -> {
LIRKind kind = getLirKind(cas);
LabelRef trueLabel = getLIRBlock(root.trueSuccessor());
LabelRef falseLabel = getLIRBlock(root.falseSuccessor());
double trueLabelProbability = root.probability(root.trueSuccessor());
Value expectedValue = operand(cas.getExpectedValue());
Value newValue = operand(cas.getNewValue());
SPARCAddressValue address = (SPARCAddressValue) operand(cas.getAddress());
Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
Value result = getLIRGeneratorTool().emitValueCompareAndSwap(address, expectedValue, newValue);
getLIRGeneratorTool().emitCompareBranch(kind.getPlatformKind(), result, expectedValue, condition, false, trueLabel, falseLabel, trueLabelProbability);
return null;
};
}
return null;
}
@Override
public SPARCLIRGenerator getLIRGeneratorTool() {
return (SPARCLIRGenerator) super.getLIRGeneratorTool();

View File

@ -26,6 +26,7 @@ import java.util.ListIterator;
import org.graalvm.compiler.java.DefaultSuitesProvider;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.BasePhase;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
@ -39,8 +40,8 @@ public class SPARCSuitesProvider extends DefaultSuitesProvider {
}
@Override
public Suites createSuites() {
Suites s = super.createSuites();
public Suites createSuites(OptionValues options) {
Suites s = super.createSuites(options);
ListIterator<BasePhase<? super LowTierContext>> l = s.getLowTier().findPhase(ExpandLogicPhase.class);
while (PhaseSuite.findNextPhase(l, ExpandLogicPhase.class)) {
// Search for last occurrence of ExpandLogicPhase

View File

@ -313,7 +313,7 @@ public class BoxingEliminationTest extends GraalCompilerTest {
graph = parseEager(snippet, AllowAssumptions.NO);
HighTierContext context = getDefaultHighTierContext();
new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
new PartialEscapePhase(false, new CanonicalizerPhase()).apply(graph, context);
new PartialEscapePhase(false, new CanonicalizerPhase(), graph.getOptions()).apply(graph, context);
}
private void compareGraphs(final String snippet, final String referenceSnippet) {
@ -331,7 +331,7 @@ public class BoxingEliminationTest extends GraalCompilerTest {
}
new DeadCodeEliminationPhase().apply(graph);
canonicalizer.apply(graph, context);
new PartialEscapePhase(false, canonicalizer).apply(graph, context);
new PartialEscapePhase(false, canonicalizer, graph.getOptions()).apply(graph, context);
new DeadCodeEliminationPhase().apply(graph);
canonicalizer.apply(graph, context);

View File

@ -22,13 +22,13 @@
*/
package org.graalvm.compiler.core.test;
import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
import static org.graalvm.compiler.debug.DelegatingDebugConfig.Feature.INTERCEPT;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
@ -41,10 +41,10 @@ import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.bytecode.BridgeMethodUtils;
import org.graalvm.compiler.core.CompilerThreadFactory;
@ -67,6 +67,7 @@ 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.InvocationPlugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.VerifyPhase;
@ -80,7 +81,9 @@ import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
import org.graalvm.compiler.phases.verify.VerifyVirtualizableUsage;
import org.graalvm.compiler.runtime.RuntimeProvider;
import org.graalvm.compiler.test.GraalTest;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import jdk.vm.ci.code.BailoutException;
import jdk.vm.ci.code.Register;
@ -98,7 +101,7 @@ import jdk.vm.ci.meta.Value;
* global invariants such as using {@link Object#equals(Object)} to compare certain types instead of
* identity comparisons.
*/
public class CheckGraalInvariants extends GraalTest {
public class CheckGraalInvariants extends GraalCompilerTest {
private static boolean shouldVerifyEquals(ResolvedJavaMethod m) {
if (m.getName().equals("identityEquals")) {
@ -114,7 +117,7 @@ public class CheckGraalInvariants extends GraalTest {
private static boolean shouldProcess(String classpathEntry) {
if (classpathEntry.endsWith(".jar")) {
String name = new File(classpathEntry).getName();
return name.contains("jvmci") || name.contains("graal");
return name.contains("jvmci") || name.contains("graal") || name.contains("jdk.internal.vm.compiler");
}
return false;
}
@ -134,9 +137,13 @@ public class CheckGraalInvariants extends GraalTest {
Assume.assumeTrue(VerifyPhase.class.desiredAssertionStatus());
String propertyName = Java8OrEarlier ? "sun.boot.class.path" : "jdk.module.path";
String bootclasspath = System.getProperty(propertyName);
Assert.assertNotNull("Cannot find value of " + propertyName, bootclasspath);
String bootclasspath;
if (Java8OrEarlier) {
bootclasspath = System.getProperty("sun.boot.class.path");
} else {
bootclasspath = System.getProperty("jdk.module.path") + File.pathSeparatorChar + System.getProperty("jdk.module.upgrade.path");
}
Assert.assertNotNull("Cannot find boot class path", bootclasspath);
final List<String> classNames = new ArrayList<>();
for (String path : bootclasspath.split(File.pathSeparator)) {
@ -162,66 +169,85 @@ public class CheckGraalInvariants extends GraalTest {
String property = System.getProperty(CheckGraalInvariants.class.getName() + ".filters");
String[] filters = property == null ? null : property.split(",");
OptionValues options = getInitialOptions();
CompilerThreadFactory factory = new CompilerThreadFactory("CheckInvariantsThread", new DebugConfigAccess() {
@Override
public GraalDebugConfig getDebugConfig() {
return DebugEnvironment.initialize(System.out);
return DebugEnvironment.ensureInitialized(options);
}
});
int availableProcessors = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor executor = new ThreadPoolExecutor(availableProcessors, availableProcessors, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(), factory);
List<String> errors = Collections.synchronizedList(new ArrayList<>());
// Order outer classes before the inner classes
classNames.sort((String a, String b) -> a.compareTo(b));
// Initialize classes in single thread to avoid deadlocking issues during initialization
List<Class<?>> classes = initializeClasses(classNames);
for (Class<?> c : classes) {
String className = c.getName();
executor.execute(() -> {
try {
checkClass(c, metaAccess);
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
}
});
for (Method m : c.getDeclaredMethods()) {
if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
// ignore
} else {
String methodName = className + "." + m.getName();
if (matches(filters, methodName)) {
executor.execute(() -> {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
StructuredGraph graph = new StructuredGraph(method, AllowAssumptions.NO, INVALID_COMPILATION_ID);
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
graphBuilderSuite.apply(graph, context);
// update phi stamps
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
checkGraph(context, graph);
} catch (VerificationError e) {
errors.add(e.getMessage());
} catch (LinkageError e) {
// suppress linkages errors resulting from eager resolution
} catch (BailoutException e) {
// Graal bail outs on certain patterns in Java bytecode (e.g.,
// unbalanced monitors introduced by jacoco).
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
}
});
for (Method m : BadUsageWithEquals.class.getDeclaredMethods()) {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
StructuredGraph graph = new StructuredGraph.Builder(options, AllowAssumptions.YES).method(method).build();
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
graphBuilderSuite.apply(graph, context);
// update phi stamps
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
checkGraph(context, graph);
errors.add(String.format("Expected error while checking %s", m));
} catch (VerificationError e) {
// expected!
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", m, printStackTraceToString(e)));
}
}
if (errors.isEmpty()) {
// Order outer classes before the inner classes
classNames.sort((String a, String b) -> a.compareTo(b));
// Initialize classes in single thread to avoid deadlocking issues during initialization
List<Class<?>> classes = initializeClasses(classNames);
for (Class<?> c : classes) {
String className = c.getName();
executor.execute(() -> {
try {
checkClass(c, metaAccess);
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", className, printStackTraceToString(e)));
}
});
for (Method m : c.getDeclaredMethods()) {
if (Modifier.isNative(m.getModifiers()) || Modifier.isAbstract(m.getModifiers())) {
// ignore
} else {
String methodName = className + "." + m.getName();
if (matches(filters, methodName)) {
executor.execute(() -> {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
StructuredGraph graph = new StructuredGraph.Builder(options).method(method).build();
try (DebugConfigScope s = Debug.setConfig(new DelegatingDebugConfig().disable(INTERCEPT)); Debug.Scope ds = Debug.scope("CheckingGraph", graph, method)) {
checkMethod(method);
graphBuilderSuite.apply(graph, context);
// update phi stamps
graph.getNodes().filter(PhiNode.class).forEach(PhiNode::inferStamp);
checkGraph(context, graph);
} catch (VerificationError e) {
errors.add(e.getMessage());
} catch (LinkageError e) {
// suppress linkages errors resulting from eager resolution
} catch (BailoutException e) {
// Graal bail outs on certain patterns in Java bytecode (e.g.,
// unbalanced monitors introduced by jacoco).
} catch (Throwable e) {
errors.add(String.format("Error while checking %s:%n%s", methodName, printStackTraceToString(e)));
}
});
}
}
}
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
}
executor.shutdown();
try {
executor.awaitTermination(1, TimeUnit.HOURS);
} catch (InterruptedException e1) {
throw new RuntimeException(e1);
}
if (!errors.isEmpty()) {
StringBuilder msg = new StringBuilder();
String nl = String.format("%n");
@ -262,11 +288,30 @@ public class CheckGraalInvariants extends GraalTest {
}
}
private static void checkMethod(ResolvedJavaMethod method) {
if (method.getAnnotation(Snippet.class) == null) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
for (int i = 0; i < parameterAnnotations.length; i++) {
for (Annotation a : parameterAnnotations[i]) {
Class<? extends Annotation> annotationType = a.annotationType();
if (annotationType == ConstantParameter.class || annotationType == VarargsParameter.class || annotationType == NonNullParameter.class) {
VerificationError verificationError = new VerificationError("Parameter %d of %s is annotated with %s but the method is not annotated with %s", i, method,
annotationType.getSimpleName(),
Snippet.class.getSimpleName());
throw verificationError;
}
}
}
}
}
/**
* Checks the invariants for a single graph.
*/
private static void checkGraph(HighTierContext context, StructuredGraph graph) {
if (shouldVerifyEquals(graph.method())) {
// If you add a new type to test here, be sure to add appropriate
// methods to the BadUsageWithEquals class below
new VerifyUsageWithEquals(Value.class).apply(graph, context);
new VerifyUsageWithEquals(Register.class).apply(graph, context);
new VerifyUsageWithEquals(RegisterCategory.class).apply(graph, context);
@ -305,4 +350,108 @@ public class CheckGraalInvariants extends GraalTest {
t.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
static class BadUsageWithEquals {
Value aValue;
Register aRegister;
RegisterCategory aRegisterCategory;
JavaType aJavaType;
JavaField aJavaField;
JavaMethod aJavaMethod;
LocationIdentity aLocationIdentity;
LIRKind aLIRKind;
ArithmeticOpTable anArithmeticOpTable;
ArithmeticOpTable.Op anArithmeticOpTableOp;
static Value aStaticValue;
static Register aStaticRegister;
static RegisterCategory aStaticRegisterCategory;
static JavaType aStaticJavaType;
static JavaField aStaticJavaField;
static JavaMethod aStaticJavaMethod;
static LocationIdentity aStaticLocationIdentity;
static LIRKind aStaticLIRKind;
static ArithmeticOpTable aStaticArithmeticOpTable;
static ArithmeticOpTable.Op aStaticArithmeticOpTableOp;
boolean test01(Value f) {
return aValue == f;
}
boolean test02(Register f) {
return aRegister == f;
}
boolean test03(RegisterCategory f) {
return aRegisterCategory == f;
}
boolean test04(JavaType f) {
return aJavaType == f;
}
boolean test05(JavaField f) {
return aJavaField == f;
}
boolean test06(JavaMethod f) {
return aJavaMethod == f;
}
boolean test07(LocationIdentity f) {
return aLocationIdentity == f;
}
boolean test08(LIRKind f) {
return aLIRKind == f;
}
boolean test09(ArithmeticOpTable f) {
return anArithmeticOpTable == f;
}
boolean test10(ArithmeticOpTable.Op f) {
return anArithmeticOpTableOp == f;
}
boolean test12(Value f) {
return aStaticValue == f;
}
boolean test13(Register f) {
return aStaticRegister == f;
}
boolean test14(RegisterCategory f) {
return aStaticRegisterCategory == f;
}
boolean test15(JavaType f) {
return aStaticJavaType == f;
}
boolean test16(JavaField f) {
return aStaticJavaField == f;
}
boolean test17(JavaMethod f) {
return aStaticJavaMethod == f;
}
boolean test18(LocationIdentity f) {
return aStaticLocationIdentity == f;
}
boolean test19(LIRKind f) {
return aStaticLIRKind == f;
}
boolean test20(ArithmeticOpTable f) {
return aStaticArithmeticOpTable == f;
}
boolean test21(ArithmeticOpTable.Op f) {
return aStaticArithmeticOpTableOp == f;
}
}
}

View File

@ -90,7 +90,7 @@ public class CommonedConstantsTest extends GraalCompilerTest {
@Test
public void test1() {
getSuites().getHighTier().findPhase(AbstractInliningPhase.class).remove();
createSuites(getInitialOptions()).getHighTier().findPhase(AbstractInliningPhase.class).remove();
test1Snippet(new String(alphabet));
test("test1Snippet", (Object) null);
@ -114,7 +114,7 @@ public class CommonedConstantsTest extends GraalCompilerTest {
@Test
public void test2() {
assert getSuites().getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
assert createSuites(getInitialOptions()).getHighTier().findPhase(AbstractInliningPhase.class).hasNext();
test2Snippet(new String(alphabet));
test("test2Snippet", (Object) null);

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import 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;
private StructuredGraph getCanonicalizedGraph(String name) {
StructuredGraph graph = parseEager(name, AllowAssumptions.YES);
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());
}
@Test
public void test0() {
testIntegerTestCanonicalization("integerTestCanonicalization0");
}
@Test
public void test1() {
testIntegerTestCanonicalization("integerTestCanonicalization1");
}
public static void integerTestCanonicalization0(int a) {
if (1 < a + 1) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void integerTestCanonicalization1(int a) {
if (a - 1 < -1) {
sink1 = 0;
} else {
sink0 = -1;
}
}
}

View File

@ -33,7 +33,9 @@ import jdk.vm.ci.meta.JavaConstant;
import org.junit.Test;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.test.AddExports;
@AddExports("jdk.internal.vm.ci/jdk.vm.ci.meta")
public class ConditionTest {
@Test

View File

@ -1,289 +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.core.test;
import java.lang.reflect.Field;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.nodes.IfNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
import sun.misc.Unsafe;
public class ConditionalEliminationLoadFieldConstantFoldTest extends GraalCompilerTest {
public static int intSideEffect;
public static final B FinalField = new B(10);
private abstract static class A {
}
private static class B extends A {
final int a;
B(int a) {
this.a = a;
}
}
private static class C extends A {
final B b;
C(B b) {
this.b = b;
}
}
private static class D extends A {
final C c;
D(C c) {
this.c = c;
}
}
private static class E extends D {
final Object o;
E(C c, Object o) {
super(c);
this.o = o;
}
}
public static final B CONST_B = new B(10);
public static final C CONST_C = new C(CONST_B);
public static final D CONST_D = new D(CONST_C);
public int testReadConstInBranch(B b) {
if (b == CONST_B) {
if (b.a == 5) {
intSideEffect = b.a;
} else {
intSideEffect = 10;
}
}
return 0;
}
public int testMultipleReadsConstInBranch(D d) {
if (d == CONST_D) {
C c = d.c;
B b = c.b;
int res = b.a + 12;
if (res == 125) {
intSideEffect = 12;
}
}
return 0;
}
public int testLoadFinalInstanceOf(E e) {
Object o = e.o;
if (o == CONST_C) {
if (o instanceof A) {
// eliminate, implied by a.x == Const(Subclass)
intSideEffect = 1;
} else {
intSideEffect = 10;
}
}
return 0;
}
public int testLoadFinalTwiceInstanceOf(E e) {
if (e.o == CONST_C) {
if (e.o instanceof A) {
intSideEffect = 1;
} else {
intSideEffect = 10;
}
}
return 0;
}
static class C1 {
final int a;
C1(int a) {
this.a = a;
}
}
static class C2 {
final C1 c1;
C2(C1 c1) {
this.c1 = c1;
}
}
public static int foldThatIsNotAllowed(C2 c2) {
// read before, this will be used to load through when folding
C1 c1Unknown = c2.c1;
// be naughty (will be a store field after canonicalization as it has a constant offset, so
// we would be able to eliminate the inner if after an early read elimination but we would
// fold before and ce the inner if already)
//
// note: if the offset would not be constant but a parameter we would not even be able to
// remove in inner most if as we cannot rewrite the unsafe store to a store field node as
// the store might kill ANY_LOCATION
UNSAFE.putObject(c2, C2_C1_OFFSET, C1_AFTER_READ_CONST);
if (c2 == C2_CONST) {
if (c1Unknown == C1_CONST) {
/*
* This if can be eliminated (as we rewrite the unsafe store with a constant offset
* to a store field node) but the remaining branch must be the false branch. If we
* do not fold through both field loads we will canonicalize the unsafe store to a
* store field, see the new value and can thus eliminate the true branch
*
* if we fold through the load fields we would load from the object read before the
* store so we miss the unsafe update
*/
if (c2.c1.a == 10) {
intSideEffect = 1;
return 1;
} else {
intSideEffect = 2;
return 2;
}
} else {
intSideEffect = -2;
return -2;
}
} else {
intSideEffect = -1;
return -1;
}
}
public int testLoadFinalTwiceNoReadEliminationInstanceOf(E e) {
if (e.o == CONST_C) {
/*
* we cannot eliminate the second read of e.o although it is a final field. the call to
* System.gc (or any other memory checkpoint killing ANY_LOCATION) will prohibit the
* elimination of the second load, thus we have two different load nodes, we know that
* that first load field is a constant but we do not know for the second one, assuming
* e.o is final, as it might have been written in between
*
* this prohibits us to remove the if (fold through all loads to final fields) and the
* instance of e.o
*/
System.gc();
C c = (C) e.o;
if (c.b.a == 10) {
intSideEffect = 1;
} else {
intSideEffect = 10;
}
}
return 0;
}
private static final C1 C1_CONST = new C1(0);
private static final C2 C2_CONST = new C2(C1_CONST);
private static final C1 C1_AFTER_READ_CONST = new C1(10);
private static Unsafe getUnsafe() {
try {
return Unsafe.getUnsafe();
} catch (SecurityException e) {
}
try {
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
return (Unsafe) theUnsafeInstance.get(Unsafe.class);
} catch (Exception e) {
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
}
}
private static final sun.misc.Unsafe UNSAFE = getUnsafe();
private static final long C2_C1_OFFSET;
static {
try {
Field f = C2.class.getDeclaredField("c1");
C2_C1_OFFSET = UNSAFE.objectFieldOffset(f);
} catch (NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e);
}
}
@Test
public void test01() {
checkGraph("testReadConstInBranch", 1);
test("testReadConstInBranch", new B(1));
}
@Test
public void test02() {
checkGraph("testMultipleReadsConstInBranch", 1);
}
@Test
public void test03() {
checkGraph("testLoadFinalInstanceOf", 1);
}
@Test
public void test04() {
checkGraph("testLoadFinalTwiceInstanceOf", 1);
}
@Test
public void test05() {
checkGraph("testLoadFinalTwiceNoReadEliminationInstanceOf", 2);
}
@Test(expected = AssertionError.class)
@SuppressWarnings("try")
public void test06() {
Result actual = executeActual(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
UNSAFE.putObject(C2_CONST, C2_C1_OFFSET, C1_CONST);
Result expected = executeExpected(getResolvedJavaMethod("foldThatIsNotAllowed"), null, C2_CONST);
Assert.assertEquals(expected.returnValue, actual.returnValue);
}
@SuppressWarnings("try")
private StructuredGraph checkGraph(String name, int nrOfIfsAfter) {
StructuredGraph g = parseForCompile(getResolvedJavaMethod(name));
CanonicalizerPhase c = new CanonicalizerPhase();
c.apply(g, getDefaultHighTierContext());
new EarlyReadEliminationPhase(c).apply(g, getDefaultHighTierContext());
new IterativeConditionalEliminationPhase(c, false).apply(g, getDefaultHighTierContext());
Assert.assertEquals("Nr of Ifs left does not match", nrOfIfsAfter, g.getNodes().filter(IfNode.class).count());
c.apply(g, getDefaultHighTierContext());
return g;
}
}

View File

@ -22,13 +22,12 @@
*/
package org.graalvm.compiler.core.test;
import org.junit.Test;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.junit.Test;
public class ConditionalEliminationMulTest extends GraalCompilerTest {
@ -76,11 +75,9 @@ public class ConditionalEliminationMulTest extends GraalCompilerTest {
private StructuredGraph prepareGraph(String snippet) {
StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
HighTierContext context = getDefaultHighTierContext();
DominatorConditionalEliminationPhase.create(false).apply(graph, context);
CanonicalizerPhase c = new CanonicalizerPhase();
c.apply(graph, context);
new DominatorConditionalEliminationPhase(false).apply(graph, context);
c.apply(graph, context);
return graph;
}
}

View File

@ -44,14 +44,17 @@ import org.graalvm.compiler.phases.tiers.PhaseContext;
*/
public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase {
private static boolean condition1;
private static boolean condition2;
private static class TestClass {
int x;
}
@SuppressWarnings("all")
public static int testSnippet(int a, TestClass t) {
public static int testSnippet1(TestClass t) {
int result = 0;
if (a == 0) {
if (condition1) {
GraalDirectives.controlFlowAnchor();
result = t.x;
}
@ -61,11 +64,38 @@ public class ConditionalEliminationTest10 extends ConditionalEliminationTestBase
@Test
public void test1() {
StructuredGraph graph = parseEager("testSnippet", AllowAssumptions.YES);
test("testSnippet1", 1);
}
@SuppressWarnings("all")
public static int testSnippet2(TestClass t) {
int result = 0;
if (condition1) {
GraalDirectives.controlFlowAnchor();
result = t.x;
} else {
GraalDirectives.controlFlowAnchor();
result = t.x;
}
if (condition2) {
result = t.x;
GraalDirectives.controlFlowAnchor();
}
return result;
}
@Test
public void test2() {
test("testSnippet2", 1);
}
private void test(String snippet, int guardCount) {
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
PhaseContext context = new PhaseContext(getProviders());
new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
Assert.assertEquals(2, graph.getNodes().filter(GuardNode.class).count());
new DominatorConditionalEliminationPhase(true).apply(graph, context);
Assert.assertEquals(1, graph.getNodes().filter(GuardNode.class).count());
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
Assert.assertEquals(guardCount, graph.getNodes().filter(GuardNode.class).count());
}
}

View File

@ -41,7 +41,7 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
@SuppressWarnings("all")
public static int referenceSnippet(int a) {
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
@ -54,10 +54,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
@SuppressWarnings("all")
public static int test1Snippet(int a) {
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
@ -65,10 +65,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
@SuppressWarnings("all")
public static int test2Snippet(int a) {
if ((a & 8) == 0) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
@ -81,10 +81,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
@SuppressWarnings("all")
public static int test3Snippet(int a) {
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
@ -98,10 +98,10 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
@SuppressWarnings("all")
public static int test4Snippet(int a) {
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) == 0) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
@ -114,7 +114,7 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int test5Snippet(int a) {
if ((a & 5) == 5) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 7) != 0) {
return 0;
@ -130,19 +130,19 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int test6Snippet(int a) {
if ((a & 8) != 0) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 15) != 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 0;
}
public static int reference6Snippet(int a) {
if ((a & 8) != 0) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
return 0;
}
@ -153,17 +153,17 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int test7Snippet(int a) {
if ((a & 15) == 15) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) == 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
public static int reference7Snippet(int a) {
if ((a & 8) == 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
@ -175,20 +175,20 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int test8Snippet(int a) {
if ((a & 16) == 16) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 44) != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
public static int reference8Snippet(int a) {
if ((a & 60) != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
@ -201,23 +201,23 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int test9Snippet(int a) {
if ((a & 16) == 16) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 44) != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if (a != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
public static int reference9Snippet(int a) {
if (a != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return a;
}
@ -239,16 +239,16 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
int v = b.byteValue();
long a = v & 0xffffffff;
if (v != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 16) == 16) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 44) != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return v;
@ -257,12 +257,13 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int reference10Snippet(ByteHolder b) {
byte v = b.byteValue();
if (v != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return v;
}
@Test
@Ignore
public void test10() {
testConditionalElimination("test10Snippet", "reference10Snippet");
}
@ -272,16 +273,16 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
long a = v & 0xffffffff;
if ((a & 16) == 16) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 8) != 8) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if ((a & 44) != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if (v != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return v;
}
@ -289,12 +290,13 @@ public class ConditionalEliminationTest11 extends ConditionalEliminationTestBase
public static int reference11Snippet(ByteHolder b) {
byte v = b.byteValue();
if (v != 44) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return v;
}
@Test
@Ignore
public void test11() {
testConditionalElimination("test11Snippet", "reference11Snippet");
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.junit.Test;
public class ConditionalEliminationTest12 extends ConditionalEliminationTestBase {
static class A {
}
static class B extends A {
}
static class C extends B {
}
static class D extends C {
}
@SuppressWarnings({"static-method", "unused"})
private int referenceMethod(Object a) {
if (a instanceof A) {
if (a instanceof C) {
return 1;
} else {
GraalDirectives.deoptimizeAndInvalidate();
}
}
return 0;
}
@SuppressWarnings({"static-method", "unused"})
private int testMethod(Object a) {
if (a instanceof A) {
if (a instanceof C) {
if (a instanceof B) {
B b = (B) a;
if (b instanceof C) {
return 1;
} else {
GraalDirectives.deoptimizeAndInvalidate();
}
}
} else {
GraalDirectives.deoptimizeAndInvalidate();
}
}
return 0;
}
@SuppressWarnings("unused")
@Test
public void testFloatingGuards() {
// Make sure class D is loaded.
D d = new D();
testConditionalElimination("testMethod", "referenceMethod");
}
}

View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Test;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class ConditionalEliminationTest13 extends ConditionalEliminationTestBase {
public ConditionalEliminationTest13() {
super(false);
}
private static int sink0;
private static int sink1;
private static int sink2;
@Override
protected InlineInvokePlugin.InlineInfo bytecodeParserShouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
return InlineInvokePlugin.InlineInfo.createStandardInlineInfo(method);
}
public static void referenceSnippet1(int a) {
if (Integer.compareUnsigned(a, a + 1) < 0) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet1(int a) {
if (Integer.compareUnsigned(a, a + 1) < 0 || a == 0) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void referenceSnippet2(int a) {
if (0 < a) {
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet2(int a) {
if (0 < a) {
if (a == -1) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet3(int a) {
if (0 < a) {
if (a == 1) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
@SuppressWarnings("unused")
public static void referenceSnippet4(int a) {
sink1 = 0;
}
public static void testSnippet4(int a) {
if (Integer.compareUnsigned(a - 1, a) < 0 || a == 0) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet5(int a) {
if (a < 0) {
if (a == -1) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
public static void referenceSnippet6(int a) {
if (a < 0) {
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet6(int a) {
if (a < 0) {
if (a == 0) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet7(int a) {
if (0 < a) {
if (a == 0) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet8(int a) {
if (Integer.compareUnsigned(a, a + 1) < 0 || a == 0xffff_ffff) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void referenceSnippet9(int a) {
if (Integer.compareUnsigned(a - 1, a) < 0) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet9(int a) {
if (Integer.compareUnsigned(a - 1, a) < 0 || a == 0xffff_ffff) {
sink1 = 0;
} else {
sink0 = -1;
}
}
private static int either(int a, int b) {
return (sink0 + sink1 + sink2) == 0 ? a : b;
}
public static void testSnippet10(int a) {
if (Integer.compareUnsigned(a, a + either(1, 2)) < 0 || a == 0xffff_ffff || a == 0xffff_fffe) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void referenceSnippet11(int a) {
if (Integer.compareUnsigned(a, Integer.MAX_VALUE + 1) > 0) {
sink1 = 0;
}
sink0 = -1;
}
public static void testSnippet11(int a) {
if (Integer.compareUnsigned(a, Integer.MAX_VALUE + 1) > 0) {
if (Integer.compareUnsigned(a, 42) <= 0) {
sink2 = -2;
}
sink1 = 0;
}
sink0 = -1;
}
public static void referenceSnippet12(int a) {
if (Integer.compareUnsigned(a, 0xffff_ffff) >= 0) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet12(int a) {
if (Integer.compareUnsigned(a, 0xffff_ffff) >= 0 && a == 0xffff_ffff) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet13(int a) {
int x = either(0, 1);
if (a <= a + x) {
if (a == Integer.MAX_VALUE) {
sink2 = -2;
}
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void referenceSnippet14(int a) {
int x = either(0, 1);
if (a < a + x) {
sink1 = 0;
} else {
sink0 = -1;
}
}
public static void testSnippet14(int a) {
int x = either(0, 1);
if (a < a + x) {
if (a == Integer.MAX_VALUE) {
sink2 = -2;
}
sink1 = 0;
} else {
sink0 = -1;
}
}
@Test
public void test1() {
testConditionalElimination("testSnippet1", "referenceSnippet1");
}
@Test
public void test2() {
testConditionalElimination("testSnippet2", "referenceSnippet2");
}
@Test
public void test3() {
testConditionalElimination("testSnippet3", "testSnippet3");
}
@Test
public void test4() {
testConditionalElimination("testSnippet4", "referenceSnippet4");
}
@Test
public void test5() {
testConditionalElimination("testSnippet5", "testSnippet5");
}
@Test
public void test6() {
testConditionalElimination("testSnippet6", "referenceSnippet6");
}
@Test
public void test7() {
testConditionalElimination("testSnippet7", "referenceSnippet2");
}
@Test
public void test8() {
testConditionalElimination("testSnippet8", "referenceSnippet4");
}
@Test
public void test9() {
testConditionalElimination("testSnippet9", "referenceSnippet9");
}
@Test
public void test10() {
testConditionalElimination("testSnippet10", "referenceSnippet4");
}
@Test
public void test11() {
testConditionalElimination("testSnippet11", "referenceSnippet11");
}
@Test
public void test12() {
testConditionalElimination("testSnippet12", "referenceSnippet12");
}
@Test
public void test13() {
testConditionalElimination("testSnippet13", "testSnippet13");
}
@Test
public void test14() {
testConditionalElimination("testSnippet14", "referenceSnippet14");
}
@Override
protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
super.prepareGraph(graph, canonicalizer, context, applyLowering);
graph.clearAllStateAfter();
graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "After preparation");
canonicalizer.apply(graph, context);
}
}

View File

@ -103,7 +103,7 @@ public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
canonicalizer.apply(graph, context);
new FloatingReadPhase().apply(graph);
new DominatorConditionalEliminationPhase(true).apply(graph, context);
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
canonicalizer.apply(graph, context);
assertDeepEquals(1, graph.getNodes().filter(GuardNode.class).count());
@ -125,7 +125,7 @@ public class ConditionalEliminationTest2 extends ConditionalEliminationTestBase
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
canonicalizer.apply(graph, context);
new DominatorConditionalEliminationPhase(true).apply(graph, context);
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
canonicalizer.apply(graph, context);
assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());

View File

@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.core.test;
import org.junit.Ignore;
import org.junit.Test;
/**
@ -29,6 +30,7 @@ import org.junit.Test;
* {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
* that triggered bugs in this phase.
*/
@Ignore
public class ConditionalEliminationTest3 extends ConditionalEliminationTestBase {
private static final String REFERENCE_SNIPPET = "referenceSnippet";

View File

@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.core.test;
import org.junit.Ignore;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
@ -39,6 +40,10 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
interface B extends A {
}
interface C extends B {
}
static final class DistinctA {
}
@ -115,32 +120,63 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
@Test
public void test3() {
testConditionalElimination("test3Snippet", "reference3Snippet", true);
testConditionalElimination("test3Snippet", "reference3Snippet", true, false);
}
public static int reference4Snippet(Object a) {
if (!(a instanceof B)) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
public static int test4Snippet1(Object a) {
if (!(a instanceof B)) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if (!(a instanceof A)) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
public static int test4Snippet2(Object a) {
if (!(a instanceof A)) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
if (!(a instanceof B)) {
GraalDirectives.deoptimize();
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
@SuppressWarnings({"cast", "unused"})
public static int test4Snippet3(Object a) {
Object pi = (A) a;
if (!(a instanceof B)) {
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
public static int test4Snippet4(Object a) {
if (!(a instanceof A)) {
GraalDirectives.deoptimizeAndInvalidate();
}
if (!(((A) a) instanceof B)) {
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
@SuppressWarnings({"cast"})
public static int test4Snippet5(Object a) {
Object pi = (A) a;
if (pi == null) {
GraalDirectives.deoptimizeAndInvalidate();
}
if (!(a instanceof B)) {
GraalDirectives.deoptimizeAndInvalidate();
}
return 1;
}
@ -149,5 +185,13 @@ public class ConditionalEliminationTest5 extends ConditionalEliminationTestBase
public void test4() {
testConditionalElimination("test4Snippet1", "reference4Snippet");
testConditionalElimination("test4Snippet2", "reference4Snippet");
testConditionalElimination("test4Snippet3", "reference4Snippet");
testConditionalElimination("test4Snippet5", "reference4Snippet");
}
@Ignore
@Test
public void test5() {
testConditionalElimination("test4Snippet4", "reference4Snippet", false, true);
}
}

View File

@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.core.test;
import org.junit.Ignore;
import org.junit.Test;
/**
@ -29,6 +30,7 @@ import org.junit.Test;
* {@link org.graalvm.compiler.phases.common.DominatorConditionalEliminationPhase} including those
* that triggered bugs in this phase.
*/
@Ignore
public class ConditionalEliminationTest7 extends ConditionalEliminationTestBase {
@SuppressWarnings("all")

View File

@ -22,8 +22,6 @@
*/
package org.graalvm.compiler.core.test;
import org.junit.Assert;
import org.graalvm.compiler.debug.Debug;
import org.graalvm.compiler.nodes.ProxyNode;
import org.graalvm.compiler.nodes.StructuredGraph;
@ -36,6 +34,7 @@ import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Assert;
/**
* Collection of tests for
@ -43,11 +42,10 @@ import org.graalvm.compiler.phases.tiers.PhaseContext;
* that triggered bugs in this phase.
*/
public class ConditionalEliminationTestBase extends GraalCompilerTest {
private final boolean disableSimplification;
protected ConditionalEliminationTestBase() {
disableSimplification = true;
this(true);
}
protected ConditionalEliminationTestBase(boolean disableSimplification) {
@ -55,11 +53,11 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
}
protected void testConditionalElimination(String snippet, String referenceSnippet) {
testConditionalElimination(snippet, referenceSnippet, false);
testConditionalElimination(snippet, referenceSnippet, false, false);
}
@SuppressWarnings("try")
protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference) {
protected void testConditionalElimination(String snippet, String referenceSnippet, boolean applyConditionalEliminationOnReference, boolean applyLowering) {
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
Debug.dump(Debug.BASIC_LOG_LEVEL, graph, "Graph");
PhaseContext context = new PhaseContext(getProviders());
@ -72,9 +70,7 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
}
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest", graph)) {
canonicalizer1.apply(graph, context);
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
// new DominatorConditionalEliminationPhase(true).apply(graph, context);
prepareGraph(graph, canonicalizer1, context, applyLowering);
new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
canonicalizer.apply(graph, context);
canonicalizer.apply(graph, context);
@ -84,21 +80,29 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
}
StructuredGraph referenceGraph = parseEager(referenceSnippet, AllowAssumptions.YES);
try (Debug.Scope scope = Debug.scope("ConditionalEliminationTest.ReferenceGraph", referenceGraph)) {
new ConvertDeoptimizeToGuardPhase().apply(referenceGraph, context);
prepareGraph(referenceGraph, canonicalizer, context, applyLowering);
if (applyConditionalEliminationOnReference) {
new DominatorConditionalEliminationPhase(true).apply(referenceGraph, context);
canonicalizer.apply(referenceGraph, context);
canonicalizer.apply(referenceGraph, context);
} else {
canonicalizer.apply(referenceGraph, context);
DominatorConditionalEliminationPhase.create(true).apply(referenceGraph, context);
}
canonicalizer.apply(referenceGraph, context);
canonicalizer.apply(referenceGraph, context);
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
} catch (Throwable t) {
Debug.handle(t);
}
assertEquals(referenceGraph, graph);
}
protected void prepareGraph(StructuredGraph graph, CanonicalizerPhase canonicalizer, PhaseContext context, boolean applyLowering) {
if (applyLowering) {
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
canonicalizer.apply(graph, context);
}
canonicalizer.apply(graph, context);
new ConvertDeoptimizeToGuardPhase().apply(graph, context);
}
public void testProxies(String snippet, int expectedProxiesCreated) {
StructuredGraph graph = parseEager(snippet, AllowAssumptions.YES);
PhaseContext context = new PhaseContext(getProviders());
@ -110,9 +114,9 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
canonicalizer.apply(graph, context);
int baseProxyCount = graph.getNodes().filter(ProxyNode.class).count();
new DominatorConditionalEliminationPhase(true).apply(graph, context);
DominatorConditionalEliminationPhase.create(true).apply(graph, context);
canonicalizer.apply(graph, context);
new SchedulePhase().apply(graph, context);
new SchedulePhase(graph.getOptions()).apply(graph, context);
int actualProxiesCreated = graph.getNodes().filter(ProxyNode.class).count() - baseProxyCount;
Assert.assertEquals(expectedProxiesCreated, actualProxiesCreated);
}

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