8243380: Update Graal

Reviewed-by: kvn
This commit is contained in:
Dean Long 2020-06-05 02:00:02 -07:00
parent 0963050548
commit 6c3bc71079
513 changed files with 14093 additions and 6365 deletions
src
jdk.aot/share/classes
jdk.internal.vm.compiler/share/classes
jdk.internal.vm.compiler.collections/src/jdk/internal/vm/compiler/collections
jdk.internal.vm.compiler.libgraal/src/jdk/internal/vm/compiler/libgraal
org.graalvm.compiler.asm.aarch64.test/src/org/graalvm/compiler/asm/aarch64/test
org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64
org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64
org.graalvm.compiler.asm/src/org/graalvm/compiler/asm
org.graalvm.compiler.code/src/org/graalvm/compiler/code
org.graalvm.compiler.core.aarch64.test/src/org/graalvm/compiler/core/aarch64/test
org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64
org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64
org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common
org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor
org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test
org.graalvm.compiler.core/src/org/graalvm/compiler/core
org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test
org.graalvm.compiler.debug/src/org/graalvm/compiler/debug
org.graalvm.compiler.graph.test/src/org/graalvm/compiler/graph/test
org.graalvm.compiler.graph/src/org/graalvm/compiler/graph
org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64

@ -52,8 +52,8 @@ import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
*
* <p>
* This class holds information necessary to create platform-specific binary containers such as
* ELFContainer for Linux or MachOContainer for Mac OS or PEContainer
* for MS Windows operating systems.
* ELFContainer for Linux 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
@ -300,7 +300,7 @@ public final class BinaryContainer implements SymbolTable {
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
this.threadLocalHandshakes = graalHotSpotVMConfig.threadLocalHandshakes;
this.threadLocalHandshakes = graalHotSpotVMConfig.useThreadLocalPolling;
// Section unique name is limited to 8 characters due to limitation on Windows.
// Name could be longer but only first 8 characters are stored on Windows.
@ -354,7 +354,7 @@ public final class BinaryContainer implements SymbolTable {
graphBuilderConfig.omitAssertions()));
if (JavaVersionUtil.JAVA_SPEC < 14) {
// See JDK-8220049. Thread local handshakes are on by default since JDK14, the command line option has been removed.
booleanFlagsList.add(graalHotSpotVMConfig.threadLocalHandshakes);
booleanFlagsList.add(graalHotSpotVMConfig.useThreadLocalPolling);
}
ArrayList<Integer> intFlagsList = new ArrayList<>();
@ -432,6 +432,10 @@ public final class BinaryContainer implements SymbolTable {
return "_aot_stub_routines_crc_table_adr";
}
public static String getPollingPageSymbolName() {
return "_aot_polling_page";
}
public static String getResolveStaticEntrySymbolName() {
return "_resolve_static_entry";
}
@ -508,6 +512,7 @@ public final class BinaryContainer implements SymbolTable {
createGotSymbol(getHeapEndAddressSymbolName());
createGotSymbol(getNarrowKlassBaseAddressSymbolName());
createGotSymbol(getNarrowOopBaseAddressSymbolName());
createGotSymbol(getPollingPageSymbolName());
createGotSymbol(getLogOfHeapRegionGrainBytesSymbolName());
createGotSymbol(getInlineContiguousAllocationSupportedSymbolName());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,7 @@ import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.GraalCompilerOptions;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Activation;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
@ -118,7 +119,7 @@ final class AOTCompilationTask implements Runnable, Comparable<Object> {
CompilationResult compResult = null;
final long startTime = System.currentTimeMillis();
SnippetReflectionProvider snippetReflection = aotBackend.getProviders().getSnippetReflection();
try (DebugContext debug = DebugContext.create(graalOptions, new GraalDebugHandlersFactory(snippetReflection)); Activation a = debug.activate()) {
try (DebugContext debug = new Builder(graalOptions, new GraalDebugHandlersFactory(snippetReflection)).build(); Activation a = debug.activate()) {
compResult = aotBackend.compileMethod(method, debug);
}
final long endTime = System.currentTimeMillis();

@ -26,6 +26,7 @@
package jdk.tools.jaotc;
import org.graalvm.compiler.bytecode.Bytecodes;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.code.site.Call;
@ -67,11 +68,11 @@ final class CallInfo {
}
static boolean isVirtualCall(CompiledMethodInfo methodInfo, Call call) {
return isInvokeVirtual(call) && !methodInfo.hasMark(call, MarkId.INVOKESPECIAL) && !isStaticTarget(call);
return isInvokeVirtual(call) && !methodInfo.hasMark(call, HotSpotMarkId.INVOKESPECIAL) && !isStaticTarget(call);
}
static boolean isOptVirtualCall(CompiledMethodInfo methodInfo, Call call) {
return isInvokeVirtual(call) && methodInfo.hasMark(call, MarkId.INVOKESPECIAL);
return isInvokeVirtual(call) && methodInfo.hasMark(call, HotSpotMarkId.INVOKESPECIAL);
}
private static boolean isJavaCall(Call call) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,8 @@ package jdk.tools.jaotc;
import java.util.List;
import jdk.vm.ci.code.site.Mark;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
final class CodeOffsets {
private final int entry;
@ -42,34 +43,32 @@ final class CodeOffsets {
this.deoptHandler = deoptHandler;
}
static CodeOffsets buildFrom(List<Mark> marks) {
static CodeOffsets buildFrom(List<CompilationResult.CodeMark> marks) {
int entry = 0;
int verifiedEntry = 0;
int exceptionHandler = -1;
int deoptHandler = -1;
for (Mark mark : marks) {
if (mark.id instanceof Integer) {
MarkId markId = MarkId.getEnum((int) mark.id);
switch (markId) {
case UNVERIFIED_ENTRY:
entry = mark.pcOffset;
break;
case VERIFIED_ENTRY:
verifiedEntry = mark.pcOffset;
break;
case OSR_ENTRY:
// Unhandled
break;
case EXCEPTION_HANDLER_ENTRY:
exceptionHandler = mark.pcOffset;
break;
case DEOPT_HANDLER_ENTRY:
deoptHandler = mark.pcOffset;
break;
default:
break; // Ignore others
}
for (CompilationResult.CodeMark mark : marks) {
HotSpotMarkId markId = (HotSpotMarkId) mark.id;
switch (markId) {
case UNVERIFIED_ENTRY:
entry = mark.pcOffset;
break;
case VERIFIED_ENTRY:
verifiedEntry = mark.pcOffset;
break;
case OSR_ENTRY:
// Unhandled
break;
case EXCEPTION_HANDLER_ENTRY:
exceptionHandler = mark.pcOffset;
break;
case DEOPT_HANDLER_ENTRY:
deoptHandler = mark.pcOffset;
break;
default:
break; // Ignore others
}
}
return new CodeOffsets(entry, verifiedEntry, exceptionHandler, deoptHandler);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,17 +25,17 @@
package jdk.tools.jaotc;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.ReadOnlyDataContainer;
import jdk.tools.jaotc.AOTCompiledClass.AOTKlassData;
import org.graalvm.compiler.code.CompilationResult;
import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.code.site.Site;
import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
@ -306,23 +306,11 @@ final class CompiledMethodInfo {
return null;
}
boolean hasMark(Site call, MarkId id) {
for (Mark m : compilationResult.getMarks()) {
int adjOffset = m.pcOffset;
if (archStr.equals("aarch64")) {
// The mark is at the end of a group of three instructions:
// adrp; add; ldr
adjOffset += 12;
} else {
// X64-specific code.
// Call instructions are aligned to 8
// bytes - 1 on x86 to patch address atomically,
adjOffset = (adjOffset & (-8)) + 7;
}
// Mark points before aligning nops.
if ((call.pcOffset == adjOffset) && MarkId.getEnum((int) m.id) == id) {
return true;
}
boolean hasMark(Call call, HotSpotMarkId id) {
assert id == HotSpotMarkId.INVOKESTATIC || id == HotSpotMarkId.INVOKESPECIAL;
CompilationResult.CodeMark mark = compilationResult.getAssociatedMark(call);
if (mark != null) {
return mark.id == id;
}
return false;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,8 @@
package jdk.tools.jaotc;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.Symbol;
import jdk.vm.ci.code.site.Call;
@ -136,7 +138,7 @@ final class JavaCallSiteRelocationSymbol extends CallSiteRelocationSymbol {
private static String getResolveSymbolName(CompiledMethodInfo mi, Call call) {
String resolveSymbolName;
if (CallInfo.isStaticCall(call)) {
assert mi.hasMark(call, MarkId.INVOKESTATIC);
assert mi.hasMark(call, HotSpotMarkId.INVOKESTATIC);
resolveSymbolName = BinaryContainer.getResolveStaticEntrySymbolName();
} else if (CallInfo.isSpecialCall(call)) {
resolveSymbolName = BinaryContainer.getResolveOptVirtualEntrySymbolName();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -31,6 +31,8 @@ import static org.graalvm.compiler.hotspot.meta.HotSpotAOTProfilingPlugin.Option
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
@ -39,13 +41,12 @@ import java.util.ListIterator;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.stream.Stream;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.api.runtime.GraalJVMCICompiler;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Activation;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.hotspot.CompilerConfigurationFactory;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory;
@ -232,12 +233,12 @@ public final class Main {
// The GC names are spelled the same in both enums, so no clever remapping is needed
// here.
String name = "CollectedHeap::" + graalGC.name();
int gc = graalHotSpotVMConfig.getConstant(name, Integer.class, def);
int gc = graalHotSpotVMConfig.getConstant(name, Integer.class, def, true);
BinaryContainer binaryContainer = new BinaryContainer(graalOptions, graalHotSpotVMConfig, graphBuilderConfig, gc, JVM_VERSION);
DataBuilder dataBuilder = new DataBuilder(this, backend, classes, binaryContainer);
try (DebugContext debug = DebugContext.create(graalOptions, new GraalDebugHandlersFactory(snippetReflection)); Activation a = debug.activate()) {
try (DebugContext debug = new Builder(graalOptions, new GraalDebugHandlersFactory(snippetReflection)).build(); Activation a = debug.activate()) {
dataBuilder.prepareData(debug);
}

@ -1,79 +0,0 @@
/*
* Copyright (c) 2016, 2020, 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 jdk.tools.jaotc;
import java.util.HashMap;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
/**
* Constants used to mark special positions in code being installed into the code cache by Graal C++
* code.
*/
enum MarkId {
VERIFIED_ENTRY("CodeInstaller::VERIFIED_ENTRY"),
UNVERIFIED_ENTRY("CodeInstaller::UNVERIFIED_ENTRY"),
OSR_ENTRY("CodeInstaller::OSR_ENTRY"),
EXCEPTION_HANDLER_ENTRY("CodeInstaller::EXCEPTION_HANDLER_ENTRY"),
DEOPT_HANDLER_ENTRY("CodeInstaller::DEOPT_HANDLER_ENTRY"),
INVOKEINTERFACE("CodeInstaller::INVOKEINTERFACE"),
INVOKEVIRTUAL("CodeInstaller::INVOKEVIRTUAL"),
INVOKESTATIC("CodeInstaller::INVOKESTATIC"),
INVOKESPECIAL("CodeInstaller::INVOKESPECIAL"),
INLINE_INVOKE("CodeInstaller::INLINE_INVOKE"),
POLL_NEAR("CodeInstaller::POLL_NEAR"),
POLL_RETURN_NEAR("CodeInstaller::POLL_RETURN_NEAR"),
POLL_FAR("CodeInstaller::POLL_FAR"),
POLL_RETURN_FAR("CodeInstaller::POLL_RETURN_FAR"),
CARD_TABLE_ADDRESS("CodeInstaller::CARD_TABLE_ADDRESS"),
HEAP_TOP_ADDRESS("CodeInstaller::HEAP_TOP_ADDRESS"),
HEAP_END_ADDRESS("CodeInstaller::HEAP_END_ADDRESS"),
NARROW_KLASS_BASE_ADDRESS("CodeInstaller::NARROW_KLASS_BASE_ADDRESS"),
NARROW_OOP_BASE_ADDRESS("CodeInstaller::NARROW_OOP_BASE_ADDRESS"),
CRC_TABLE_ADDRESS("CodeInstaller::CRC_TABLE_ADDRESS"),
LOG_OF_HEAP_REGION_GRAIN_BYTES("CodeInstaller::LOG_OF_HEAP_REGION_GRAIN_BYTES"),
INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED("CodeInstaller::INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED");
private final int value;
private static HashMap<Integer, MarkId> lookup = new HashMap<>();
static {
for (MarkId e : values()) {
lookup.put(e.value, e);
}
}
MarkId(String name) {
this.value = (int) (long) HotSpotJVMCIRuntime.runtime().getConfigStore().getConstants().get(name);
}
static MarkId getEnum(int value) {
MarkId e = lookup.get(value);
if (e == null) {
throw new InternalError("Unknown enum value: " + value);
}
return e;
}
}

@ -25,11 +25,13 @@
package jdk.tools.jaotc;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import jdk.tools.jaotc.binformat.BinaryContainer;
import jdk.tools.jaotc.binformat.Relocation;
import jdk.tools.jaotc.binformat.Relocation.RelocType;
import jdk.tools.jaotc.binformat.Symbol;
import jdk.vm.ci.code.site.Mark;
final class MarkProcessor {
@ -48,8 +50,8 @@ final class MarkProcessor {
* @param mark mark being processed
*/
@SuppressWarnings("fallthrough")
void process(CompiledMethodInfo methodInfo, Mark mark) {
MarkId markId = MarkId.getEnum((int) mark.id);
void process(CompiledMethodInfo methodInfo, CompilationResult.CodeMark mark) {
HotSpotMarkId markId = (HotSpotMarkId) mark.id;
switch (markId) {
case EXCEPTION_HANDLER_ENTRY:
case DEOPT_HANDLER_ENTRY:
@ -62,24 +64,19 @@ final class MarkProcessor {
}
// fallthrough
case CARD_TABLE_ADDRESS:
case HEAP_TOP_ADDRESS:
case HEAP_END_ADDRESS:
case NARROW_KLASS_BASE_ADDRESS:
case NARROW_OOP_BASE_ADDRESS:
case CRC_TABLE_ADDRESS:
case LOG_OF_HEAP_REGION_GRAIN_BYTES:
case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
String vmSymbolName;
switch (markId) {
case POLL_FAR:
case POLL_RETURN_FAR:
vmSymbolName = BinaryContainer.getPollingPageSymbolName();
break;
case CARD_TABLE_ADDRESS:
vmSymbolName = BinaryContainer.getCardTableAddressSymbolName();
break;
case HEAP_TOP_ADDRESS:
vmSymbolName = BinaryContainer.getHeapTopAddressSymbolName();
break;
case HEAP_END_ADDRESS:
vmSymbolName = BinaryContainer.getHeapEndAddressSymbolName();
break;
case NARROW_KLASS_BASE_ADDRESS:
vmSymbolName = BinaryContainer.getNarrowKlassBaseAddressSymbolName();
break;
@ -92,9 +89,6 @@ final class MarkProcessor {
case LOG_OF_HEAP_REGION_GRAIN_BYTES:
vmSymbolName = BinaryContainer.getLogOfHeapRegionGrainBytesSymbolName();
break;
case INLINE_CONTIGUOUS_ALLOCATION_SUPPORTED:
vmSymbolName = BinaryContainer.getInlineContiguousAllocationSupportedSymbolName();
break;
default:
throw new InternalError("Unhandled mark: " + mark);
}
@ -109,6 +103,7 @@ final class MarkProcessor {
case VERIFIED_ENTRY:
case UNVERIFIED_ENTRY:
case OSR_ENTRY:
case FRAME_COMPLETE:
case INVOKEINTERFACE:
case INVOKEVIRTUAL:
case INVOKESTATIC:

@ -236,7 +236,7 @@ final class MetadataBuilder {
infopointProcessor.process(methodInfo, infoPoint);
}
for (Mark mark : compilationResult.getMarks()) {
for (CompilationResult.CodeMark mark : compilationResult.getMarks()) {
markProcessor.process(methodInfo, mark);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -45,7 +45,26 @@ import java.util.Map;
import java.util.function.BiFunction;
/**
* Memory efficient map data structure.
* Memory efficient map data structure that dynamically changes its representation depending on the
* number of entries and is specially optimized for small number of entries. It keeps elements in a
* linear list without any hashing when the number of entries is small. Should an actual hash data
* structure be necessary, it tries to fit the hash value into as few bytes as possible. In contrast
* to {@link java.util.HashMap}, it avoids allocating an extra node object per entry and rather
* keeps values always in a plain array. See {@link EconomicMapImpl} for implementation details and
* exact thresholds when its representation changes.
*
* It supports a {@code null} value, but it does not support adding or looking up a {@code null}
* key. Operations {@code get} and {@code put} provide constant-time performance on average if
* repeatedly performed. They can however trigger an operation growing or compressing the data
* structure, which is linear in the number of elements. Iteration is also linear in the number of
* elements.
*
* The implementation is not synchronized. If multiple threads want to access the data structure, it
* requires manual synchronization, for example using {@link java.util.Collections#synchronizedMap}.
* There is also no extra precaution to detect concurrent modification while iterating.
*
* Different strategies for the equality comparison can be configured by providing a
* {@link Equivalence} configuration object.
*
* @since 19.0
*/
@ -53,7 +72,8 @@ public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
/**
* Associates {@code value} with {@code key} in this map. If the map previously contained a
* mapping for {@code key}, the old value is replaced by {@code value}.
* mapping for {@code key}, the old value is replaced by {@code value}. While the {@code value}
* may be {@code null}, the {@code key} must not be {code null}.
*
* @return the previous value associated with {@code key}, or {@code null} if there was no
* mapping for {@code key}.
@ -94,7 +114,7 @@ public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
/**
* Removes the mapping for {@code key} from this map if it is present. The map will not contain
* a mapping for {@code key} once the call returns.
* a mapping for {@code key} once the call returns. The {@code key} must not be {@code null}.
*
* @return the previous value associated with {@code key}, or {@code null} if there was no
* mapping for {@code key}.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,7 +41,6 @@
package jdk.internal.vm.compiler.collections;
import java.util.Iterator;
import java.util.Objects;
import java.util.function.BiFunction;
/**
@ -240,7 +239,7 @@ final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
@SuppressWarnings("unchecked")
@Override
public V get(K key) {
Objects.requireNonNull(key);
checkKeyNonNull(key);
int index = find(key);
if (index != -1) {
@ -420,9 +419,7 @@ final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
@SuppressWarnings("unchecked")
@Override
public V put(K key, V value) {
if (key == null) {
throw new UnsupportedOperationException("null not supported as key!");
}
checkKeyNonNull(key);
int index = find(key);
if (index != -1) {
Object oldValue = getValue(index);
@ -622,9 +619,7 @@ final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
@SuppressWarnings("unchecked")
@Override
public V removeKey(K key) {
if (key == null) {
throw new UnsupportedOperationException("null not supported as key!");
}
checkKeyNonNull(key);
int index;
if (hasHashArray()) {
index = this.findAndRemoveHash(key);
@ -640,6 +635,12 @@ final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
return null;
}
private void checkKeyNonNull(K key) {
if (key == null) {
throw new UnsupportedOperationException("null not supported as key!");
}
}
/**
* Removes the element at the specific index and returns the index of the next element. This can
* be a different value if graph compression was triggered.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,7 +41,8 @@
package jdk.internal.vm.compiler.collections;
/**
* Unmodifiable memory efficient map data structure.
* Unmodifiable memory efficient map. See {@link EconomicMap} for the underlying data structure and
* its properties.
*
* @since 19.0
*/
@ -49,7 +50,7 @@ public interface UnmodifiableEconomicMap<K, V> {
/**
* Returns the value to which {@code key} is mapped, or {@code null} if this map contains no
* mapping for {@code key}.
* mapping for {@code key}. The {@code key} must not be {@code null}.
*
* @since 19.0
*/
@ -57,7 +58,7 @@ public interface UnmodifiableEconomicMap<K, V> {
/**
* Returns the value to which {@code key} is mapped, or {@code defaultValue} if this map
* contains no mapping for {@code key}.
* contains no mapping for {@code key}. The {@code key} must not be {@code null}.
*
* @since 19.0
*/
@ -70,7 +71,8 @@ public interface UnmodifiableEconomicMap<K, V> {
}
/**
* Returns {@code true} if this map contains a mapping for {@code key}.
* Returns {@code true} if this map contains a mapping for {@code key}. Returns always
* {@code false} if the {@code key} is {@code null}.
*
* @since 19.0
*/

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,8 @@
package jdk.internal.vm.compiler.libgraal;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import jdk.vm.ci.hotspot.HotSpotSpeculationLog;
import jdk.vm.ci.services.Services;
@ -33,8 +34,13 @@ import jdk.vm.ci.services.Services;
*/
public class LibGraal {
static {
// Initialize JVMCI to ensure JVMCI opens its packages to Graal.
Services.initializeJVMCI();
}
public static boolean isAvailable() {
return inLibGraal() || isolate != 0L;
return inLibGraal() || theIsolate != 0L;
}
public static boolean isSupported() {
@ -45,67 +51,63 @@ public class LibGraal {
return Services.IS_IN_NATIVE_IMAGE;
}
public static void registerNativeMethods(HotSpotJVMCIRuntime runtime, Class<?> clazz) {
public static void registerNativeMethods(Class<?> clazz) {
if (clazz.isPrimitive()) {
throw new IllegalArgumentException();
}
if (inLibGraal() || !isAvailable()) {
throw new IllegalStateException();
}
runtime.registerNativeMethods(clazz);
runtime().registerNativeMethods(clazz);
}
public static long translate(HotSpotJVMCIRuntime runtime, Object obj) {
public static long translate(Object obj) {
if (!isAvailable()) {
throw new IllegalStateException();
}
if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
}
return runtime.translate(obj);
return runtime().translate(obj);
}
public static <T> T unhand(HotSpotJVMCIRuntime runtime, Class<T> type, long handle) {
public static <T> T unhand(Class<T> type, long handle) {
if (!isAvailable()) {
throw new IllegalStateException();
}
if (!inLibGraal() && LibGraalScope.currentScope.get() == null) {
throw new IllegalStateException("Not within a " + LibGraalScope.class.getName());
}
return runtime.unhand(type, handle);
return runtime().unhand(type, handle);
}
private static long initializeLibgraal() {
try {
// Initialize JVMCI to ensure JVMCI opens its packages to
// Graal otherwise the call to HotSpotJVMCIRuntime.runtime()
// below will fail on JDK13+.
Services.initializeJVMCI();
HotSpotJVMCIRuntime runtime = HotSpotJVMCIRuntime.runtime();
long[] nativeInterface = runtime.registerNativeMethods(LibGraal.class);
return nativeInterface[1];
long[] javaVMInfo = runtime().registerNativeMethods(LibGraalScope.class);
return javaVMInfo[1];
} catch (UnsupportedOperationException e) {
return 0L;
}
}
static final long isolate = Services.IS_BUILDING_NATIVE_IMAGE ? 0L : initializeLibgraal();
static final long theIsolate = Services.IS_BUILDING_NATIVE_IMAGE ? 0L : initializeLibgraal();
static boolean isCurrentThreadAttached(HotSpotJVMCIRuntime runtime) {
return runtime.isCurrentThreadAttached();
static boolean isCurrentThreadAttached() {
return runtime().isCurrentThreadAttached();
}
public static boolean attachCurrentThread(HotSpotJVMCIRuntime runtime, boolean isDaemon) {
return runtime.attachCurrentThread(isDaemon);
public static boolean attachCurrentThread(boolean isDaemon, long[] isolate) {
if (isolate != null) {
isolate[0] = LibGraal.theIsolate;
}
return runtime().attachCurrentThread(isDaemon);
}
public static void detachCurrentThread(HotSpotJVMCIRuntime runtime) {
runtime.detachCurrentThread();
public static boolean detachCurrentThread(boolean release) {
runtime().detachCurrentThread();
return false;
}
static native long getCurrentIsolateThread(long iso);
public static long getFailedSpeculationsAddress(HotSpotSpeculationLog log) {
return log.getFailedSpeculationsAddress();
}

@ -0,0 +1,149 @@
/*
* Copyright (c) 2020, 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 jdk.internal.vm.compiler.libgraal;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
/**
* Represents a single libgraal isolate. All {@link LibGraalObject}s have a {@link LibGraalIsolate}
* context.
*/
public final class LibGraalIsolate {
final long address;
private static final Map<Long, LibGraalIsolate> isolates = new HashMap<>();
static synchronized LibGraalIsolate forAddress(long isolateAddress) {
return isolates.computeIfAbsent(isolateAddress, a -> new LibGraalIsolate(a));
}
private LibGraalIsolate(long address) {
this.address = address;
}
/**
* Gets the isolate associated with the current thread. The current thread must be in an
* {@linkplain LibGraalScope opened} scope.
*
* @throws IllegalStateException if the current thread is not attached to libgraal
*/
public static LibGraalIsolate current() {
return LibGraalScope.current().getIsolate();
}
/**
* Gets the value corresponding to {@code key} from a key-value store of singleton objects. If
* no value corresponding to {@code key} currently exists, then it is computed with
* {@code supplier} and inserted in the store.
*
* This is used to obtain objects whose lifetime is bound to the isolate represented by this
* object.
*/
@SuppressWarnings("unchecked")
public synchronized <T> T getSingleton(Class<T> key, Supplier<T> supplier) {
// Cannot use HahsMap.computeIfAbsent as it will throw a ConcurrentModificationException
// if supplier recurses here to compute another singleton.
if (!singletons.containsKey(key)) {
singletons.put(key, supplier.get());
}
return (T) singletons.get(key);
}
private final Map<Class<?>, Object> singletons = new HashMap<>();
/**
* Strong references to the {@link WeakReference} objects.
*/
private final Set<LibGraalIsolate.Cleaner> cleaners = Collections.newSetFromMap(new ConcurrentHashMap<>());
void register(LibGraalObject obj, long handle) {
cleanHandles();
Cleaner cref = new Cleaner(cleanersQueue, obj, handle);
cleaners.add(cref);
}
/**
* Processes {@link #cleanersQueue} to release any handles whose {@link LibGraalObject} objects
* are now unreachable.
*/
private void cleanHandles() {
Cleaner cleaner;
while ((cleaner = (Cleaner) cleanersQueue.poll()) != null) {
cleaners.remove(cleaner);
if (!cleaner.clean()) {
new Exception(String.format("Error releasing handle %d in isolate 0x%x", cleaner.handle, address)).printStackTrace(System.out);
}
}
}
/**
* Queue into which a {@link Cleaner} is enqueued when its {@link LibGraalObject} referent
* becomes unreachable.
*/
private final ReferenceQueue<LibGraalObject> cleanersQueue = new ReferenceQueue<>();
private static final class Cleaner extends WeakReference<LibGraalObject> {
private final long handle;
Cleaner(ReferenceQueue<LibGraalObject> cleanersQueue, LibGraalObject referent, long handle) {
super(referent, cleanersQueue);
this.handle = handle;
}
boolean clean() {
return LibGraalObject.releaseHandle(LibGraalScope.getIsolateThread(), handle);
}
}
/**
* Notifies that the {@code JavaVM} associated with {@code isolate} has been destroyed. All
* subsequent accesses to objects in the isolate will throw an {@link IllegalArgumentException}.
*/
static synchronized void remove(LibGraalIsolate isolate) {
isolate.destroyed = true;
LibGraalIsolate removed = isolates.remove(isolate.address);
assert removed == isolate : "isolate already removed or overwritten: " + isolate;
}
@Override
public String toString() {
return String.format("%s[0x%x]", getClass().getSimpleName(), address);
}
private boolean destroyed;
public boolean isValid() {
return !destroyed;
}
}

@ -0,0 +1,93 @@
/*
* Copyright (c) 2020, 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 jdk.internal.vm.compiler.libgraal;
/**
* Encapsulates a handle to an object in a libgraal isolate where the object's lifetime is bound to
* the lifetime of the {@link LibGraalObject} instance. At some point after a {@link LibGraalObject}
* is garbage collected, a call is made to release the handle, allowing the libgraal object to be
* collected.
*/
public class LibGraalObject {
static {
if (LibGraal.isAvailable()) {
LibGraal.registerNativeMethods(LibGraalObject.class);
}
}
/**
* Handle to an object in {@link #isolate}.
*/
private final long handle;
/**
* The libgraal isolate containing {@link #handle}.
*/
private final LibGraalIsolate isolate;
/**
* Creates a new {@link LibGraalObject}.
*
* @param handle handle to an object in a libgraal isolate
*/
protected LibGraalObject(long handle) {
this.handle = handle;
isolate = LibGraalScope.current().getIsolate();
isolate.register(this, handle);
}
/**
* Gets the raw JNI handle wrapped by this object.
*
* @throw {@link IllegalArgumentException} if the isolate context for the handle has destroyed.
*/
public long getHandle() {
if (!isolate.isValid()) {
throw new IllegalArgumentException(toString());
}
return handle;
}
/**
* Releases {@code handle} in the isolate denoted by {@code isolateThreadId}.
*
* @return {@code false} if {@code} is not a valid handle in the isolate
*/
// Implementation:
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.releaseHandle
static native boolean releaseHandle(long isolateThreadId, long handle);
@Override
public String toString() {
String name = getClass().getSimpleName();
Class<?> outer = getClass().getDeclaringClass();
while (outer != null) {
name = outer.getSimpleName() + '.' + name;
outer = outer.getDeclaringClass();
}
return String.format("%s[%d]", name, handle);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,37 +24,92 @@
package jdk.internal.vm.compiler.libgraal;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope(HotSpotJVMCIRuntime)
* Opening} a scope attaches the current thread to libgraal and {@linkplain #close() closing} it
* Scope for calling CEntryPoints in libgraal. {@linkplain #LibGraalScope() Opening} a scope ensures
* the current thread is attached to libgraal and {@linkplain #close() closing} the outer most scope
* detaches the current thread.
*/
public final class LibGraalScope implements AutoCloseable {
static final ThreadLocal<LibGraalScope> currentScope = new ThreadLocal<>();
/**
* Shared state between a thread's nested scopes.
*/
static class Shared {
final DetachAction detachAction;
final LibGraalIsolate isolate;
final long isolateThread;
Shared(DetachAction detachAction, LibGraalIsolate isolate, long isolateThread) {
this.detachAction = detachAction;
this.isolate = isolate;
this.isolateThread = isolateThread;
}
}
private final LibGraalScope parent;
private final boolean topLevel;
private final HotSpotJVMCIRuntime runtime;
private final long isolateThread;
private final Shared shared;
/**
* Gets the current scope.
*
* @throws IllegalStateException if the current thread is not in an {@linkplain #LibGraalScope()
* opened} scope
*/
public static LibGraalScope current() {
LibGraalScope scope = currentScope.get();
if (scope == null) {
throw new IllegalStateException("Not in an " + LibGraalScope.class.getSimpleName());
}
return scope;
}
/**
* Gets the isolate thread associated with the current thread. The current thread must be in an
* {@linkplain #LibGraalScope(HotSpotJVMCIRuntime) opened} scope.
* {@linkplain #LibGraalScope() opened} scope.
*
* @returns a value that can be used for the IsolateThreadContext argument of a {@code native}
* method {@link LibGraal#registerNativeMethods linked} to a CEntryPoint function in
* libgraal
* @throws IllegalStateException if not the current thread is not attached to libgraal
* @throws IllegalStateException if the current thread is not attached to libgraal
*/
public static long getIsolateThread() {
LibGraalScope scope = currentScope.get();
if (scope == null) {
throw new IllegalStateException("Cannot get isolate thread outside of a " + LibGraalScope.class.getSimpleName());
}
return scope.isolateThread;
return current().shared.isolateThread;
}
/**
* Denotes the detach action to perform when closing a {@link LibGraalScope}.
*/
public enum DetachAction {
/**
* Detach the thread from its libgraal isolate.
*/
DETACH,
/**
* Detach the thread from its libgraal isolate and the associated {@code JVMCIRuntime}.
*/
DETACH_RUNTIME,
/**
* Detach the thread from its libgraal isolate and the associated {@code JVMCIRuntime}. If
* the VM supports releasing the {@code JavaVM} associated with {@code JVMCIRuntime}s and
* this is the last thread attached to its {@code JVMCIRuntime}, then the
* {@code JVMCIRuntime} destroys its {@code JavaVM} instance.
*/
DETACH_RUNTIME_AND_RELEASE
}
/**
* Shortcut for calling {@link #LibGraalScope(DetachAction)} with an argument of
* {@link DetachAction#DETACH_RUNTIME}.
*/
public LibGraalScope() {
this(DetachAction.DETACH_RUNTIME);
}
/**
@ -69,28 +124,183 @@ public final class LibGraalScope implements AutoCloseable {
* @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
* or {@link LibGraal#inLibGraal()} returns true
*/
public LibGraalScope(HotSpotJVMCIRuntime runtime) {
public LibGraalScope(DetachAction detachAction) {
if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
throw new IllegalStateException();
}
this.runtime = runtime;
parent = currentScope.get();
boolean top = false;
if (parent == null) {
top = LibGraal.attachCurrentThread(runtime, false);
isolateThread = LibGraal.getCurrentIsolateThread(LibGraal.isolate);
long[] isolateBox = {0};
boolean firstAttach = LibGraal.attachCurrentThread(false, isolateBox);
long isolateAddress = isolateBox[0];
LibGraalIsolate isolate = LibGraalIsolate.forAddress(isolateAddress);
long isolateThread = getIsolateThreadIn(isolateAddress);
shared = new Shared(firstAttach ? detachAction : null, isolate, isolateThread);
} else {
isolateThread = parent.isolateThread;
shared = parent.shared;
}
topLevel = top;
currentScope.set(this);
}
/**
* Enters a scope for making calls into an existing libgraal isolate. If there is no existing
* libgraal scope for the current thread, the current thread is attached to libgraal. When the
* outer most scope is closed, the current thread is detached from libgraal.
*
* This must be used in a try-with-resources statement.
*
* This cannot be called from {@linkplain LibGraal#inLibGraal() within} libgraal.
*
* @throws IllegalStateException if libgraal is {@linkplain LibGraal#isAvailable() unavailable}
* or {@link LibGraal#inLibGraal()} returns true
*/
public LibGraalScope(long isolateAddress) {
if (LibGraal.inLibGraal() || !LibGraal.isAvailable()) {
throw new IllegalStateException();
}
parent = currentScope.get();
if (parent == null) {
long isolateThread = getIsolateThreadIn(isolateAddress);
boolean alreadyAttached;
if (isolateThread == 0L) {
alreadyAttached = false;
isolateThread = attachThreadTo(isolateAddress);
} else {
alreadyAttached = true;
}
LibGraalIsolate isolate = LibGraalIsolate.forAddress(isolateAddress);
shared = new Shared(alreadyAttached ? null : DetachAction.DETACH, isolate, isolateThread);
} else {
shared = parent.shared;
}
currentScope.set(this);
}
/**
* Attaches the current thread to the isolate at {@code isolateAddress}.
*
* @return the address of the attached IsolateThread
*/
// Implementation:
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.attachThreadTo
static native long attachThreadTo(long isolateAddress);
/**
* Detaches the current thread from the isolate at {@code isolateAddress}.
*/
// Implementation:
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.detachThreadFrom
static native void detachThreadFrom(long isolateThreadAddress);
/**
* Gets the isolate thread for the current thread in the isolate at {@code isolateAddress}.
*
* @return 0L if the current thread is not attached to the isolate at {@code isolateAddress}
*/
// Implementation:
// com.oracle.svm.graal.hotspot.libgraal.LibGraalEntryPoints.getIsolateThreadIn
@SuppressWarnings("unused")
static native long getIsolateThreadIn(long isolateAddress);
/**
* Gets the isolate associated with this scope.
*/
public LibGraalIsolate getIsolate() {
return shared.isolate;
}
/**
* Gets the address of the isolate thread associated with this scope.
*/
public long getIsolateThreadAddress() {
return shared.isolateThread;
}
@Override
public void close() {
if (topLevel) {
LibGraal.detachCurrentThread(runtime);
if (parent == null && shared.detachAction != null) {
if (shared.detachAction == DetachAction.DETACH) {
detachThreadFrom(shared.isolateThread);
} else {
boolean isolateDestroyed = LibGraal.detachCurrentThread(shared.detachAction == DetachAction.DETACH_RUNTIME_AND_RELEASE);
if (isolateDestroyed) {
LibGraalIsolate.remove(shared.isolate);
}
}
}
currentScope.set(parent);
}
// Shared support for the LibGraal overlays
/**
* Convenience function for wrapping varargs into an array for use in calls to
* {@link #method(Class, String, Class[][])}.
*/
static Class<?>[] sig(Class<?>... types) {
return types;
}
/**
* Gets the method in {@code declaringClass} with the unique name {@code name}.
*
* @param sigs the signatures the method may have
*/
static Method method(Class<?> declaringClass, String name, Class<?>[]... sigs) {
if (sigs.length == 1 || sigs.length == 0) {
try {
Class<?>[] sig = sigs.length == 1 ? sigs[0] : new Class<?>[0];
return declaringClass.getDeclaredMethod(name, sig);
} catch (NoSuchMethodException | SecurityException e) {
throw (NoSuchMethodError) new NoSuchMethodError(name).initCause(e);
}
}
Method match = null;
for (Method m : declaringClass.getDeclaredMethods()) {
if (m.getName().equals(name)) {
if (match != null) {
throw new InternalError(String.format("Expected single method named %s, found %s and %s",
name, match, m));
}
match = m;
}
}
if (match == null) {
throw new NoSuchMethodError("Cannot find method " + name + " in " + declaringClass.getName());
}
Class<?>[] parameterTypes = match.getParameterTypes();
for (Class<?>[] sig : sigs) {
if (Arrays.equals(parameterTypes, sig)) {
return match;
}
}
throw new NoSuchMethodError(String.format("Unexpected signature for %s: %s", name, Arrays.toString(parameterTypes)));
}
/**
* Gets the method in {@code declaringClass} with the unique name {@code name} or {@code null}
* if not found.
*
* @param sigs the signatures the method may have
*/
static Method methodOrNull(Class<?> declaringClass, String name, Class<?>[]... sigs) {
try {
return method(declaringClass, name, sigs);
} catch (NoSuchMethodError e) {
return null;
}
}
/**
* Gets the method in {@code declaringClass} with the unique name {@code name} or {@code null}
* if {@code guard == null}.
*
* @param sigs the signatures the method may have
*/
static Method methodIf(Object guard, Class<?> declaringClass, String name, Class<?>[]... sigs) {
if (guard == null) {
return null;
}
return method(declaringClass, name, sigs);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -132,16 +132,6 @@ class TestProtectedAssembler extends AArch64Assembler {
super.stxr(size, rs, rt, rn);
}
@Override
protected void ldar(int size, Register rt, Register rn) {
super.ldar(size, rt, rn);
}
@Override
protected void stlr(int size, Register rt, Register rn) {
super.stlr(size, rt, rn);
}
@Override
public void ldaxr(int size, Register rt, Register rn) {
super.ldaxr(size, rt, rn);
@ -258,7 +248,7 @@ class TestProtectedAssembler extends AArch64Assembler {
}
@Override
protected void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
public void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
super.sub(size, dst, src1, src2, extendType, shiftAmt);
}

@ -56,6 +56,7 @@ import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSIN
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.CSNEG;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DC;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DMB;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.DSB;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EON;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EOR;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.EXTR;
@ -673,6 +674,7 @@ public abstract class AArch64Assembler extends Assembler {
CLREX(0xd5033f5f),
HINT(0xD503201F),
DMB(0x000000A0),
DSB(0x00000080),
MRS(0xD5300000),
MSR(0xD5100000),
@ -1402,7 +1404,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param rt general purpose register. May not be null or stackpointer.
* @param rn general purpose register.
*/
protected void ldar(int size, Register rt, Register rn) {
public void ldar(int size, Register rt, Register rn) {
assert size == 8 || size == 16 || size == 32 || size == 64;
int transferSize = NumUtil.log2Ceil(size / 8);
exclusiveLoadInstruction(LDAR, rt, rn, transferSize);
@ -1415,7 +1417,7 @@ public abstract class AArch64Assembler extends Assembler {
* @param rt general purpose register. May not be null or stackpointer.
* @param rn general purpose register.
*/
protected void stlr(int size, Register rt, Register rn) {
public void stlr(int size, Register rt, Register rn) {
assert size == 8 || size == 16 || size == 32 || size == 64;
int transferSize = NumUtil.log2Ceil(size / 8);
// Hack: Passing the zero-register means it is ignored when building the encoding.
@ -1471,7 +1473,7 @@ public abstract class AArch64Assembler extends Assembler {
*/
private void exclusiveStoreInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize) {
assert log2TransferSize >= 0 && log2TransferSize < 4;
assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && (instr == STLR || !rs.equals(rt));
int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt));
}
@ -1992,7 +1994,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 sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
public void sub(int size, Register dst, Register src1, Register src2, ExtendType extendType, int shiftAmt) {
assert !dst.equals(zr);
assert !src1.equals(zr);
assert !src2.equals(sp);
@ -3012,6 +3014,15 @@ public abstract class AArch64Assembler extends Assembler {
emitInt(DMB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset);
}
/**
* Data Synchronization Barrier.
*
* @param barrierKind barrier that is issued. May not be null.
*/
public void dsb(BarrierKind barrierKind) {
emitInt(DSB.encoding | BarrierOp | barrierKind.encoding << BarrierKindOffset);
}
/**
* Instruction Synchronization Barrier.
*/

@ -2138,6 +2138,14 @@ public class AArch64MacroAssembler extends AArch64Assembler {
super.hint(SystemHint.CSDB);
}
/**
* Ensures current execution state is committed before continuing.
*/
public void fullSystemBarrier() {
super.dsb(BarrierKind.SYSTEM);
super.isb();
}
/**
* Same as {@link #nop()}.
*/

@ -107,7 +107,8 @@ public class AMD64Assembler extends AMD64BaseAssembler {
public static class Options {
// @formatter:off
@Option(help = "Force branch instructions to align with 32-bytes boundary, to mitigate the jcc erratum. " +
"See https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf for more details.", type = OptionType.User)
"See https://www.intel.com/content/dam/support/us/en/documents/processors/mitigations-jump-conditional-code-erratum.pdf for more details. " +
"If not set explicitly, the default value will be determined according to the CPU model.", type = OptionType.User)
public static final OptionKey<Boolean> UseBranchesWithin32ByteBoundary = new OptionKey<>(false);
// @formatter:on
}
@ -120,19 +121,28 @@ public class AMD64Assembler extends AMD64BaseAssembler {
protected CodePatchShifter codePatchShifter = null;
/**
* Constructs an assembler for the AMD64 architecture.
*/
public AMD64Assembler(TargetDescription target) {
super(target);
useBranchesWithin32ByteBoundary = false;
}
/**
* Constructs an assembler for the AMD64 architecture.
*/
public AMD64Assembler(TargetDescription target, OptionValues optionValues) {
super(target);
useBranchesWithin32ByteBoundary = Options.UseBranchesWithin32ByteBoundary.getValue(optionValues);
}
public AMD64Assembler(TargetDescription target, OptionValues optionValues, boolean hasIntelJccErratum) {
super(target);
if (Options.UseBranchesWithin32ByteBoundary.hasBeenSet(optionValues)) {
useBranchesWithin32ByteBoundary = Options.UseBranchesWithin32ByteBoundary.getValue(optionValues);
} else {
useBranchesWithin32ByteBoundary = hasIntelJccErratum;
}
}
public void setCodePatchShifter(CodePatchShifter codePatchShifter) {
assert this.codePatchShifter == null : "overwriting existing value";
this.codePatchShifter = codePatchShifter;
@ -2269,6 +2279,12 @@ public class AMD64Assembler extends AMD64BaseAssembler {
emitModRM(dst, src);
}
public final void movb(Register dst, AMD64Address src) {
prefixb(src, dst);
emitByte(0x8A);
emitOperandHelper(dst, src, 0);
}
public final void movb(AMD64Address dst, int imm8) {
prefix(dst);
emitByte(0xC6);

@ -63,6 +63,14 @@ public class AMD64MacroAssembler extends AMD64Assembler {
super(target, optionValues);
}
public AMD64MacroAssembler(TargetDescription target, OptionValues optionValues, boolean hasIntelJccErratum) {
super(target, optionValues, hasIntelJccErratum);
}
public final void decrementq(Register reg) {
decrementq(reg, 1);
}
public final void decrementq(Register reg, int value) {
if (value == Integer.MIN_VALUE) {
subq(reg, value);
@ -101,6 +109,10 @@ public class AMD64MacroAssembler extends AMD64Assembler {
}
}
public final void incrementq(Register reg) {
incrementq(reg, 1);
}
public void incrementq(Register reg, int value) {
if (value == Integer.MIN_VALUE) {
addq(reg, value);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
@ -26,5 +26,5 @@ package org.graalvm.compiler.asm;
public class AsmOptions {
public static int InitialCodeBufferSize = 232;
public static final int InitialCodeBufferSize = 232;
}

@ -36,7 +36,9 @@ import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.EconomicSet;
import jdk.internal.vm.compiler.collections.Equivalence;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.graph.NodeSourcePosition;
@ -194,7 +196,7 @@ public class CompilationResult {
private final List<SourceMapping> sourceMapping = new ArrayList<>();
private final List<DataPatch> dataPatches = new ArrayList<>();
private final List<ExceptionHandler> exceptionHandlers = new ArrayList<>();
private final List<Mark> marks = new ArrayList<>();
private final List<CodeMark> marks = new ArrayList<>();
private int totalFrameSize = -1;
private int maxInterpreterFrameSize = -1;
@ -523,11 +525,13 @@ public class CompilationResult {
* @param target the being called
* @param debugInfo the debug info for the call
* @param direct specifies if this is a {@linkplain Call#direct direct} call
* @return created call object
*/
public void recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
public Call recordCall(int codePos, int size, InvokeTarget target, DebugInfo debugInfo, boolean direct) {
checkOpen();
final Call call = new Call(target, codePos, size, direct, debugInfo);
addInfopoint(call);
return call;
}
/**
@ -603,9 +607,9 @@ public class CompilationResult {
* @param codePos the position in the code that is covered by the handler
* @param markId the identifier for this mark
*/
public Mark recordMark(int codePos, Object markId) {
public CodeMark recordMark(int codePos, MarkId markId) {
checkOpen();
Mark mark = new Mark(codePos, markId);
CodeMark mark = new CodeMark(codePos, markId);
marks.add(mark);
return mark;
}
@ -692,9 +696,78 @@ public class CompilationResult {
}
/**
* @return the list of marks
* An identified mark in the generated code.
*/
public List<Mark> getMarks() {
public interface MarkId {
/**
* A human readable name for this mark.
*/
String getName();
/**
* Return the object which should be used in the {@link Mark}. On some platforms that may be
* different than this object.
*/
default Object getId() {
return this;
}
/**
* Indicates whether the mark is intended to identify the end of the last instruction or the
* beginning of the next instruction. This information is necessary if the backend needs to
* insert instructions after the normal assembly step.
*/
boolean isMarkAfter();
}
/**
* An alternative to the existing {@link Mark} which isn't very flexible since it's final. This
* enforces some API for the mark object and can be converted into the standard mark for code
* installation if necessary.
*/
public static class CodeMark extends Site {
/**
* An object denoting extra semantic information about the machine code position of this
* mark.
*/
public final MarkId id;
/**
* Creates a mark that associates {@code id} with the machine code position
* {@code pcOffset}.
*/
public CodeMark(int pcOffset, MarkId id) {
super(pcOffset);
this.id = id;
assert id != null : this;
}
@Override
public String toString() {
return id + "@" + pcOffset;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CodeMark) {
CodeMark that = (CodeMark) obj;
if (this.pcOffset == that.pcOffset && Objects.equals(this.id, that.id)) {
return true;
}
}
return false;
}
}
/**
* @return the list of {@link CodeMark code marks}.
*/
public List<CodeMark> getMarks() {
if (marks.isEmpty()) {
return emptyList();
}
@ -750,6 +823,7 @@ public class CompilationResult {
if (annotations != null) {
annotations.clear();
}
callToMark.clear();
}
public void clearInfopoints() {
@ -788,7 +862,7 @@ public class CompilationResult {
});
iterateAndReplace(dataPatches, pos, site -> new DataPatch(site.pcOffset + bytesToShift, site.reference, site.note));
iterateAndReplace(exceptionHandlers, pos, site -> new ExceptionHandler(site.pcOffset + bytesToShift, site.handlerPos));
iterateAndReplace(marks, pos, site -> new Mark(site.pcOffset + bytesToShift, site.id));
iterateAndReplace(marks, pos, site -> new CodeMark(site.pcOffset + bytesToShift, site.id));
if (annotations != null) {
for (CodeAnnotation annotation : annotations) {
int annotationPos = annotation.position;
@ -802,9 +876,29 @@ public class CompilationResult {
private static <T extends Site> void iterateAndReplace(List<T> sites, int pos, Function<T, T> replacement) {
for (int i = 0; i < sites.size(); i++) {
T site = sites.get(i);
if (pos == site.pcOffset && site instanceof CodeMark) {
CodeMark mark = (CodeMark) site;
if (mark.id.isMarkAfter()) {
// The insert point is exactly on the mark but the mark is annotating the end of
// the last instruction, so leave it alone.
continue;
}
}
if (pos <= site.pcOffset) {
sites.set(i, replacement.apply(site));
}
}
}
private final EconomicMap<Call, CodeMark> callToMark = EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE);
public void recordCallContext(CodeMark mark, Call call) {
if (call != null) {
callToMark.put(call, mark);
}
}
public CodeMark getAssociatedMark(Call call) {
return callToMark.get(call);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,8 @@ import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import org.graalvm.compiler.serviceprovider.ServiceProvider;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.CodeUtil.DefaultRefMapFormatter;
@ -40,9 +42,6 @@ import jdk.vm.ci.code.site.Call;
import jdk.vm.ci.code.site.DataPatch;
import jdk.vm.ci.code.site.ExceptionHandler;
import jdk.vm.ci.code.site.Infopoint;
import jdk.vm.ci.code.site.Mark;
import org.graalvm.compiler.serviceprovider.ServiceProvider;
/**
* {@link HexCodeFile} based implementation of {@link DisassemblerProvider}.
@ -99,8 +98,8 @@ public class HexCodeFileDisassemblerProvider implements DisassemblerProvider {
for (DataPatch site : compResult.getDataPatches()) {
hcf.addOperandComment(site.pcOffset, "{" + site.reference.toString() + "}");
}
for (Mark mark : compResult.getMarks()) {
hcf.addComment(mark.pcOffset, codeCache.getMarkName(mark));
for (CompilationResult.CodeMark mark : compResult.getMarks()) {
hcf.addComment(mark.pcOffset, mark.id.getName());
}
}
String hcfEmbeddedString = hcf.toEmbeddedString();

@ -1,6 +1,6 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, Arm Limited. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@ package org.graalvm.compiler.core.aarch64.test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ExtendedAddShiftOp;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp.ExtendedAddSubShiftOp;
import org.junit.Test;
import java.util.ArrayDeque;
@ -36,7 +36,7 @@ import java.util.Set;
import java.util.function.Predicate;
public class AArch64ArrayAddressTest extends AArch64MatchRuleTest {
private static final Predicate<LIRInstruction> predicate = op -> (op instanceof ExtendedAddShiftOp);
private static final Predicate<LIRInstruction> predicate = op -> (op instanceof ExtendedAddSubShiftOp);
public static byte loadByte(byte[] arr, int n) {
return arr[n];

@ -0,0 +1,238 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.aarch64.test;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
import org.junit.Test;
import java.util.function.Predicate;
public class AArch64MergeExtendWithAddSubTest extends AArch64MatchRuleTest {
private static final Predicate<LIRInstruction> PRED_EXTEND_ADD_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("ADD"));
private static final Predicate<LIRInstruction> PRED_EXTEND_SUB_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("SUB"));
private static final Long[] LONG_VALUES = {-1L, 0L, 0x1234567812345678L, 0xFFFFFFFFL, 0x12L, 0x1234L, Long.MIN_VALUE, Long.MAX_VALUE};
private static final Integer[] INT_VALUES = {-1, 0, 0x1234, 0x12345678, Integer.MIN_VALUE, Integer.MAX_VALUE};
private <T> void predicateExist(String[] testCases, T[] values, Predicate<LIRInstruction> predicate) {
for (String t : testCases) {
for (T value : values) {
test(t, value, value);
checkLIR(t, predicate, 1);
}
}
}
public long addI2LShift(long x, long y) {
int z = (int) y;
return x + (((long) z) << 3);
}
public long addB2LShift(long x, long y) {
byte z = (byte) y;
return x + (((long) z) << 2);
}
public long addC2LShift(long x, long y) {
char z = (char) y;
return x + (((long) z) << 1);
}
public long addS2LShift(long x, long y) {
short z = (short) y;
return x + (((long) z) << 4);
}
public long subI2LShift(long x, long y) {
int z = (int) y;
return x - (((long) z) << 1);
}
public long subB2LShift(long x, long y) {
byte z = (byte) y;
return x - (((long) z) << 2);
}
public long subC2LShift(long x, long y) {
char z = (char) y;
return x - (((long) z) << 3);
}
public long subS2LShift(long x, long y) {
short z = (short) y;
return x - (((long) z) << 4);
}
public long addI2L(long x, long y) {
int z = (int) y;
return x + z;
}
public long addB2L(long x, long y) {
byte z = (byte) y;
return x + z;
}
public long addC2L(long x, long y) {
char z = (char) y;
return x + z;
}
public long addS2L(long x, long y) {
short z = (short) y;
return x + z;
}
public int addB2S(int x, int y) {
short a = (short) x;
byte b = (byte) y;
return a + b;
}
public int addB2SShift(int x, int y) {
short a = (short) x;
byte b = (byte) y;
return a + (b << 2);
}
public int addB2I(int x, int y) {
byte z = (byte) y;
return x + z;
}
public int addB2IShift(int x, int y) {
byte z = (byte) y;
return x + (z << 3);
}
public int addS2I(int x, int y) {
short z = (short) y;
return x + z;
}
public int addS2IShift(int x, int y) {
short z = (short) y;
return x + (z << 2);
}
public int addC2I(int x, int y) {
char z = (char) y;
return x + z;
}
public int addC2IShift(int x, int y) {
char z = (char) y;
return x + (z << 1);
}
@Test
public void mergeSignExtendIntoAdd() {
predicateExist(new String[]{"addB2S", "addB2I", "addS2I", "addC2I"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addB2L", "addC2L", "addI2L", "addS2L"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
@Test
public void mergeSignExtendShiftIntoAdd() {
predicateExist(new String[]{"addB2SShift", "addB2IShift", "addS2IShift", "addC2IShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addB2LShift", "addC2LShift", "addI2LShift", "addS2LShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public long subI2L(long x, long y) {
int z = (int) y;
return x - z;
}
public long subB2L(long x, long y) {
byte z = (byte) y;
return x - z;
}
public long subC2L(long x, long y) {
char z = (char) y;
return x - z;
}
public long subS2L(long x, long y) {
short z = (short) y;
return x - z;
}
public int subB2S(int x, int y) {
short a = (short) x;
byte b = (byte) y;
return a - b;
}
public int subB2SShift(int x, int y) {
short a = (short) x;
byte b = (byte) y;
return a - (b << 2);
}
public int subB2I(int x, int y) {
byte z = (byte) y;
return x - z;
}
public int subB2IShift(int x, int y) {
byte z = (byte) y;
return x - (z << 3);
}
public int subS2I(int x, int y) {
short z = (short) y;
return x - z;
}
public int subS2IShift(int x, int y) {
short z = (short) y;
return x - (z << 2);
}
public int subC2I(int x, int y) {
char z = (char) y;
return x - z;
}
public int subC2IShift(int x, int y) {
char z = (char) y;
return x - (z << 1);
}
@Test
public void mergeSignExtendShiftIntoSub() {
predicateExist(new String[]{"subB2SShift", "subB2IShift", "subS2IShift", "subC2IShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subB2LShift", "subC2LShift", "subI2LShift", "subS2LShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
@Test
public void mergeSignExtendIntoSub() {
predicateExist(new String[]{"subB2S", "subB2I", "subS2I", "subC2I"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subB2L", "subC2L", "subI2L", "subS2L"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
}

@ -0,0 +1,314 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.aarch64.test;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticOp;
import org.junit.Test;
import java.util.function.Predicate;
public class AArch64MergeNarrowWithAddSubTest extends AArch64MatchRuleTest {
private static final Predicate<LIRInstruction> PRED_EXTEND_ADD_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("ADD"));
private static final Predicate<LIRInstruction> PRED_EXTEND_SUB_SHIFT = op -> (op instanceof AArch64ArithmeticOp.ExtendedAddSubShiftOp && op.name().equals("SUB"));
private static final Long[] LONG_VALUES = {-1L, 0L, 0x1234567812345678L, 0xFFFFFFFFL, 0x12L, 0x1234L, Long.MIN_VALUE, Long.MAX_VALUE};
private static final Integer[] INT_VALUES = {-1, 0, 0x1234, 0x12345678, Integer.MIN_VALUE, Integer.MAX_VALUE};
private <T> void predicateExist(String[] testCases, T[] values, Predicate<LIRInstruction> predicate) {
for (String t : testCases) {
for (T value : values) {
test(t, value, value);
checkLIR(t, predicate, 1);
}
}
}
public int addIB(int x, int y) {
return x + (y & 0xff);
}
public int addIH(int x, int y) {
return x + (y & 0xffff);
}
public long addLB(long x, long y) {
return x + (y & 0xff);
}
public long addLH(long x, long y) {
return x + (y & 0xffff);
}
public long addLW(long x, long y) {
return x + (y & 0xffffffffL);
}
@Test
public void mergeDowncastIntoAdd() {
predicateExist(new String[]{"addIB", "addIH"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLB", "addLH", "addLW"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int subIB(int x, int y) {
return x - (y & 0xff);
}
public int subIH(int x, int y) {
return x - (y & 0xffff);
}
public long subLB(long x, long y) {
return x - (y & 0xff);
}
public long subLH(long x, long y) {
return x - (y & 0xffff);
}
public long subLW(long x, long y) {
return x - (y & 0xffffffffL);
}
@Test
public void mergeDowncastIntoSub() {
predicateExist(new String[]{"subIB", "subIH"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLB", "subLH", "subLW"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
public int addIBShift(int x, int y) {
return x + ((y & 0xff) << 3);
}
public int addIHShift(int x, int y) {
return x + ((y & 0xffff) << 3);
}
public long addLBShift(long x, long y) {
return x + ((y & 0xffL) << 3);
}
public long addLHShift(long x, long y) {
return x + ((y & 0xffffL) << 3);
}
public long addLWShift(long x, long y) {
return x + ((y & 0xffffffffL) << 3);
}
@Test
public void mergeShiftDowncastIntoAdd() {
predicateExist(new String[]{"addIBShift", "addIHShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLBShift", "addLHShift", "addLWShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int subIBShift(int x, int y) {
return x - ((y & 0xff) << 3);
}
public int subIHShift(int x, int y) {
return x - ((y & 0xffff) << 3);
}
public long subLBShift(long x, long y) {
return x - ((y & 0xffL) << 3);
}
public long subLHShift(long x, long y) {
return x - ((y & 0xffffL) << 3);
}
public long subLWShift(long x, long y) {
return x - ((y & 0xffffffffL) << 3);
}
@Test
public void mergeShiftDowncastIntoSub() {
predicateExist(new String[]{"subIBShift", "subIHShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLBShift", "subLHShift", "subLWShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
public int addIntExtractShort(int x, int y) {
return x + ((y << 16) >> 16);
}
public int addIntExtractByte(int x, int y) {
return x + ((y << 24) >> 24);
}
public long addLongExtractInt(long x, long y) {
return x + ((y << 32) >> 32);
}
public long addLongExtractShort(long x, long y) {
return x + ((y << 48) >> 48);
}
public long addLongExtractByte(long x, long y) {
return x + ((y << 56) >> 56);
}
@Test
public void addSignExtractTest() {
predicateExist(new String[]{"addIntExtractShort", "addIntExtractByte"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLongExtractInt", "addLongExtractShort", "addLongExtractByte"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int addIntExtractShortByShift(int x, int y) {
return x + (((y << 16) >> 16) << 3);
}
public int addIntExtractByteByShift(int x, int y) {
return x + (((y << 24) >> 24) << 3);
}
public long addLongExtractIntByShift(long x, long y) {
return x + (((y << 32) >> 32) << 3);
}
public long addLongExtractShortByShift(long x, long y) {
return x + (((y << 48) >> 48) << 3);
}
public long addLongExtractByteByShift(long x, long y) {
return x + (((y << 56) >> 56) << 3);
}
@Test
public void addExtractByShiftTest() {
predicateExist(new String[]{"addIntExtractShortByShift", "addIntExtractByteByShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLongExtractIntByShift", "addLongExtractShortByShift", "addLongExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int addIntUnsignedExtractByte(int x, int y) {
return x + ((y << 24) >>> 24);
}
public long addLongUnsignedExtractByte(long x, long y) {
return x + ((y << 56) >>> 56);
}
@Test
public void addUnsignedExtractTest() {
predicateExist(new String[]{"addIntUnsignedExtractByte"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLongUnsignedExtractByte"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int addIntUnsignedExtractByteByShift(int x, int y) {
return x + (((y << 24) >>> 24) << 2);
}
public long addLongUnsignedExtractByteByShift(long x, long y) {
return x + (((y << 56) >>> 56) << 1);
}
@Test
public void addUnsignedExtractByShiftTest() {
predicateExist(new String[]{"addIntUnsignedExtractByteByShift"}, INT_VALUES, PRED_EXTEND_ADD_SHIFT);
predicateExist(new String[]{"addLongUnsignedExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_ADD_SHIFT);
}
public int subIntExtractShort(int x, int y) {
return x - ((y << 16) >> 16);
}
public int subIntExtractByte(int x, int y) {
return x - ((y << 24) >> 24);
}
public long subLongExtractInt(long x, long y) {
return x - ((y << 32) >> 32);
}
public long subLongExtractShort(long x, long y) {
return x - ((y << 48) >> 48);
}
public long subLongExtractByte(long x, long y) {
return x - ((y << 56) >> 56);
}
@Test
public void subExtractTest() {
predicateExist(new String[]{"subIntExtractShort", "subIntExtractByte"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLongExtractInt", "subLongExtractShort", "subLongExtractByte"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
public int subIntExtractShortByShift(int x, int y) {
return x - (((y << 16) >> 16) << 3);
}
public int subIntExtractByteByShift(int x, int y) {
return x - (((y << 24) >> 24) << 3);
}
public long subLongExtractIntByShift(long x, long y) {
return x - (((y << 32) >> 32) << 3);
}
public long subLongExtractShortByShift(long x, long y) {
return x - (((y << 48) >> 48) << 3);
}
public long subLongExtractByteByShift(long x, long y) {
return x - (((y << 56) >> 56) << 3);
}
@Test
public void subExtractByShiftTest() {
predicateExist(new String[]{"subIntExtractShortByShift", "subIntExtractByteByShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLongExtractIntByShift", "subLongExtractShortByShift", "subLongExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
public int subIntUnsignedExtractByte(int x, int y) {
return x - ((y << 24) >>> 24);
}
public long subLongUnsignedExtractByte(long x, long y) {
return x - ((y << 56) >>> 56);
}
@Test
public void subUnsignedExtractTest() {
predicateExist(new String[]{"subIntUnsignedExtractByte"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLongUnsignedExtractByte"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
public int subIntUnsignedExtractByteByShift(int x, int y) {
return x - (((y << 24) >>> 24) << 1);
}
public long subLongUnsignedExtractByteByShift(long x, long y) {
return x - (((y << 56) >>> 56) << 2);
}
@Test
public void subUnsignedExtractByShiftTest() {
predicateExist(new String[]{"subIntUnsignedExtractByteByShift"}, INT_VALUES, PRED_EXTEND_SUB_SHIFT);
predicateExist(new String[]{"subLongUnsignedExtractByteByShift"}, LONG_VALUES, PRED_EXTEND_SUB_SHIFT);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, 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
@ -62,7 +62,7 @@ public class AArch64TestBitAndBranchTest extends LIRTest {
public static long testBit42Snippet(long a, long b, long c) {
if ((a & (1L << 42)) == 0) {
return b;
return b + c;
} else {
return c;
}

@ -0,0 +1,194 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.aarch64.test;
import jdk.vm.ci.aarch64.AArch64;
import jdk.vm.ci.aarch64.AArch64Kind;
import org.graalvm.compiler.core.test.MatchRuleTest;
import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.aarch64.AArch64Move;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.function.Predicate;
import static org.junit.Assume.assumeTrue;
public class AArch64VolatileAccessesTest extends MatchRuleTest {
private static volatile byte volatileByteField;
private static volatile short volatileShortField;
private static volatile int volatileIntField;
private static volatile long volatileLongField;
private static volatile float volatileFloatField;
private static volatile double volatileDoubleField;
private static Predicate<LIRInstruction> storePredicate(AArch64Kind kind) {
return op -> (op instanceof AArch64Move.VolatileStoreOp && ((AArch64Move.VolatileStoreOp) op).getKind() == kind);
}
private static Predicate<LIRInstruction> loadPredicate(AArch64Kind kind) {
return op -> (op instanceof AArch64Move.VolatileLoadOp && ((AArch64Move.VolatileLoadOp) op).getKind() == kind);
}
@Before
public void checkAArch64() {
assumeTrue("skipping AArch64 specific test", getTarget().arch instanceof AArch64);
}
public static byte volatileByteFieldLoad() {
return volatileByteField;
}
@Test
public void test01() {
checkLIR("volatileByteFieldLoad", loadPredicate(AArch64Kind.BYTE), 1);
volatileByteField = 42;
test("volatileByteFieldLoad");
}
public static short volatileShortFieldLoad() {
return volatileShortField;
}
@Test
public void test02() {
checkLIR("volatileShortFieldLoad", loadPredicate(AArch64Kind.WORD), 1);
volatileShortField = 42;
test("volatileShortFieldLoad");
}
public static int volatileIntFieldLoad() {
return volatileIntField;
}
@Test
public void test03() {
checkLIR("volatileIntFieldLoad", loadPredicate(AArch64Kind.DWORD), 1);
volatileIntField = 42;
test("volatileIntFieldLoad");
}
public static long volatileLongFieldLoad() {
return volatileLongField;
}
@Test
public void test04() {
checkLIR("volatileLongFieldLoad", loadPredicate(AArch64Kind.QWORD), 1);
volatileLongField = 42;
test("volatileLongFieldLoad");
}
public static float volatileFloatFieldLoad() {
return volatileFloatField;
}
@Test
public void test05() {
checkLIR("volatileFloatFieldLoad", loadPredicate(AArch64Kind.SINGLE), 1);
volatileFloatField = 42;
test("volatileFloatFieldLoad");
}
public static double volatileDoubleFieldLoad() {
return volatileDoubleField;
}
@Test
public void test06() {
checkLIR("volatileDoubleFieldLoad", loadPredicate(AArch64Kind.DOUBLE), 1);
volatileDoubleField = 42;
test("volatileDoubleFieldLoad");
}
public static void volatileByteFieldStore(byte v) {
volatileByteField = v;
}
@Test
public void test07() {
checkLIR("volatileByteFieldStore", storePredicate(AArch64Kind.BYTE), 1);
executeActual(getResolvedJavaMethod("volatileByteFieldStore"), (byte) 0x42);
Assert.assertEquals(volatileByteField, 0x42);
}
public static void volatileShortFieldStore(short v) {
volatileShortField = v;
}
@Test
public void test08() {
checkLIR("volatileShortFieldStore", storePredicate(AArch64Kind.WORD), 1);
executeActual(getResolvedJavaMethod("volatileShortFieldStore"), (short) 0x42);
Assert.assertEquals(volatileShortField, 0x42);
}
public static void volatileIntFieldStore(int v) {
volatileIntField = v;
}
@Test
public void test09() {
checkLIR("volatileIntFieldStore", storePredicate(AArch64Kind.DWORD), 1);
executeActual(getResolvedJavaMethod("volatileIntFieldStore"), 0x42);
Assert.assertEquals(volatileIntField, 0x42);
}
public static void volatileLongFieldStore(int v) {
volatileLongField = v;
}
@Test
public void test10() {
checkLIR("volatileLongFieldStore", storePredicate(AArch64Kind.QWORD), 1);
executeActual(getResolvedJavaMethod("volatileLongFieldStore"), 0x42);
Assert.assertEquals(volatileLongField, 0x42);
}
public static void volatileFloatFieldStore(float v) {
volatileFloatField = v;
}
@Test
public void test11() {
checkLIR("volatileFloatFieldStore", storePredicate(AArch64Kind.SINGLE), 1);
executeActual(getResolvedJavaMethod("volatileFloatFieldStore"), (float) 0x42);
Assert.assertEquals(volatileFloatField, 0x42, 0);
}
public static void volatileDoubleFieldStore(double v) {
volatileDoubleField = v;
}
@Test
public void test12() {
checkLIR("volatileDoubleFieldStore", storePredicate(AArch64Kind.DOUBLE), 1);
executeActual(getResolvedJavaMethod("volatileDoubleFieldStore"), (double) 0x42);
Assert.assertEquals(volatileDoubleField, 0x42, 0);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -46,6 +46,7 @@ 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.AArch64Move;
import org.graalvm.compiler.lir.aarch64.AArch64Move.LoadOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreConstantOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
@ -237,7 +238,7 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
result = getLIRGen().newVariable(LIRKind.combine(c));
} else {
assert a.getPlatformKind() == c.getPlatformKind();
if (op == AArch64ArithmeticOp.FADD) {
if (op == AArch64ArithmeticOp.FMADD) {
// For floating-point Math.fma intrinsic.
assert a.getPlatformKind() == AArch64Kind.SINGLE || a.getPlatformKind() == AArch64Kind.DOUBLE;
} else {
@ -506,6 +507,14 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
return result;
}
@Override
public Variable emitVolatileLoad(LIRKind kind, Value address, LIRFrameState state) {
AllocatableValue loadAddress = asAllocatable(address);
Variable result = getLIRGen().newVariable(getLIRGen().toRegisterKind(kind));
getLIRGen().append(new AArch64Move.VolatileLoadOp((AArch64Kind) kind.getPlatformKind(), result, loadAddress, state));
return result;
}
@Override
public void emitStore(ValueKind<?> lirKind, Value address, Value inputVal, LIRFrameState state) {
AArch64AddressValue storeAddress = getLIRGen().asAddressValue(address);
@ -523,6 +532,14 @@ public class AArch64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implem
getLIRGen().append(new StoreOp(kind, storeAddress, input, state));
}
@Override
public void emitVolatileStore(ValueKind<?> lirKind, Value addressVal, Value inputVal, LIRFrameState state) {
AArch64Kind kind = (AArch64Kind) lirKind.getPlatformKind();
AllocatableValue input = asAllocatable(inputVal);
AllocatableValue address = asAllocatable(addressVal);
getLIRGen().append(new AArch64Move.VolatileStoreOp(kind, address, input, state));
}
@Override
public Value emitRound(Value value, RoundingMode mode) {
AArch64ArithmeticOp op;

@ -141,6 +141,22 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
}
}
private static ExtendType getSignExtendType(int fromBits) {
switch (fromBits) {
case Byte.SIZE:
return ExtendType.SXTB;
case Short.SIZE:
return ExtendType.SXTH;
case Integer.SIZE:
return ExtendType.SXTW;
case Long.SIZE:
return ExtendType.SXTX;
default:
GraalError.shouldNotReachHere("extended from " + fromBits + "bits is not supported!");
return null;
}
}
private AllocatableValue moveSp(AllocatableValue value) {
return getLIRGeneratorTool().moveSp(value);
}
@ -190,7 +206,83 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
}
private static boolean isNarrowingLongToInt(NarrowNode narrow) {
return narrow.getInputBits() == 64 && narrow.getResultBits() == 32;
return narrow.getInputBits() == Long.SIZE && narrow.getResultBits() == Integer.SIZE;
}
private ComplexMatchResult emitExtendedAddSubShift(BinaryNode op, ValueNode x, ValueNode y, ExtendType extType, int shiftAmt) {
assert op instanceof AddNode || op instanceof SubNode;
return builder -> {
AllocatableValue src1 = moveSp(gen.asAllocatable(operand(x)));
AllocatableValue src2 = moveSp(gen.asAllocatable(operand(y)));
Variable result = gen.newVariable(LIRKind.combine(operand(x), operand(y)));
AArch64ArithmeticOp arithmeticOp = op instanceof AddNode ? AArch64ArithmeticOp.ADD : AArch64ArithmeticOp.SUB;
gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(arithmeticOp, result, src1, src2, extType, shiftAmt));
return result;
};
}
@MatchRule("(Add=op x (LeftShift (SignExtend=ext y) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (SignExtend=ext y) Constant=lshift))")
@MatchRule("(Add=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (ZeroExtend=ext y) Constant=lshift))")
public ComplexMatchResult mergeSignExtendByShiftIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y, ConstantNode lshift) {
assert lshift.getStackKind().isNumericInteger();
int shiftAmt = lshift.asJavaConstant().asInt();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
ExtendType extType;
if (ext instanceof SignExtendNode) {
extType = getSignExtendType(((SignExtendNode) ext).getInputBits());
} else {
extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits());
}
return emitExtendedAddSubShift(op, x, y, extType, shiftAmt);
}
@MatchRule("(Add=op x (LeftShift (And y Constant=constant) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (And y Constant=constant) Constant=lshift))")
public ComplexMatchResult mergeShiftDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant, ConstantNode lshift) {
assert lshift.getStackKind().isNumericInteger();
assert constant.getStackKind().isNumericInteger();
int shiftAmt = lshift.asJavaConstant().asInt();
long mask = constant.asJavaConstant().asLong();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) {
return null;
}
ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length());
return emitExtendedAddSubShift(op, x, y, extType, shiftAmt);
}
@MatchRule("(Add=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))")
@MatchRule("(Sub=op x (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst))")
public ComplexMatchResult mergePairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst) {
assert shiftConst.getStackKind().isNumericInteger();
int shift = shiftConst.asJavaConstant().asInt();
if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) {
return null;
}
int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift;
return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), 0);
}
@MatchRule("(Add=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))")
@MatchRule("(Sub=op x (LeftShift (RightShift (LeftShift y Constant=shiftConst) Constant=shiftConst) Constant=lshift))")
public ComplexMatchResult mergeShiftedPairShiftIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode shiftConst, ConstantNode lshift) {
assert shiftConst.getStackKind().isNumericInteger();
int shift = shiftConst.asJavaConstant().asInt();
int shiftAmt = lshift.asJavaConstant().asInt();
if (shiftAmt > 4 || shiftAmt < 0) {
return null;
}
if (shift != 16 && shift != 24 && shift != 32 && shift != 48 && shift != 56) {
return null;
}
int extractBits = shift >= 32 ? Long.SIZE - shift : Integer.SIZE - shift;
return emitExtendedAddSubShift(op, x, y, getSignExtendType(extractBits), shiftAmt);
}
@MatchRule("(AArch64PointerAdd=addP base ZeroExtend)")
@ -225,7 +317,7 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
LIRKind kind = LIRKind.combineDerived(gen.getLIRKind(addP.stamp(NodeView.DEFAULT)),
baseReference, null);
Variable result = gen.newVariable(kind);
gen.append(new AArch64ArithmeticOp.ExtendedAddShiftOp(result, x, moveSp(y),
gen.append(new AArch64ArithmeticOp.ExtendedAddSubShiftOp(AArch64ArithmeticOp.ADD, result, x, moveSp(y),
extendType, shiftNum));
return result;
};
@ -469,6 +561,32 @@ public class AArch64NodeMatchRules extends NodeMatchRules {
resultKind, op, commutative, operand(src2), operand(src1));
}
@MatchRule("(Add=op x (And y Constant=constant))")
@MatchRule("(Sub=op x (And y Constant=constant))")
public ComplexMatchResult mergeDowncastIntoAddSub(BinaryNode op, ValueNode x, ValueNode y, ConstantNode constant) {
assert constant.getStackKind().isNumericInteger();
long mask = constant.asJavaConstant().asLong();
if (mask != 0xff && mask != 0xffff && mask != 0xffffffffL) {
return null;
}
ExtendType extType = getZeroExtendType(Long.toBinaryString(mask).length());
return emitExtendedAddSubShift(op, x, y, extType, 0);
}
@MatchRule("(Add=op x (SignExtend=ext y))")
@MatchRule("(Sub=op x (SignExtend=ext y))")
@MatchRule("(Add=op x (ZeroExtend=ext y))")
@MatchRule("(Sub=op x (ZeroExtend=ext y))")
public ComplexMatchResult mergeSignExtendIntoAddSub(BinaryNode op, UnaryNode ext, ValueNode x, ValueNode y) {
ExtendType extType;
if (ext instanceof SignExtendNode) {
extType = getSignExtendType(((SignExtendNode) ext).getInputBits());
} else {
extType = getZeroExtendType(((ZeroExtendNode) ext).getInputBits());
}
return emitExtendedAddSubShift(op, x, y, extType, 0);
}
@MatchRule("(Negate=unary (Narrow=narrow value))")
@MatchRule("(Not=unary (Narrow=narrow value))")
public ComplexMatchResult elideL2IForUnary(UnaryNode unary, NarrowNode narrow) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -31,6 +31,7 @@ import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.VolatileReadNode;
import org.graalvm.compiler.phases.Phase;
/**
@ -46,7 +47,7 @@ public class AArch64ReadReplacementPhase extends Phase {
if (node instanceof AArch64ReadNode) {
continue;
}
if (node instanceof ReadNode) {
if (node instanceof ReadNode && !(node instanceof VolatileReadNode)) {
ReadNode readNode = (ReadNode) node;
if (readNode.hasExactlyOneUsage()) {
Node usage = readNode.usages().first();

@ -1177,6 +1177,16 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
return result;
}
@Override
public Variable emitVolatileLoad(LIRKind kind, Value address, LIRFrameState state) {
throw GraalError.shouldNotReachHere();
}
@Override
public void emitVolatileStore(ValueKind<?> kind, Value address, Value input, LIRFrameState state) {
throw GraalError.shouldNotReachHere();
}
protected void emitStoreConst(AMD64Kind kind, AMD64AddressValue address, ConstantValue value, LIRFrameState state) {
Constant c = value.getConstant();
if (JavaConstant.isNull(c)) {

@ -107,7 +107,7 @@ import org.graalvm.compiler.lir.amd64.AMD64ZeroMemoryOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorCompareOp;
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import org.graalvm.compiler.lir.gen.LIRGenerator;
import org.graalvm.compiler.lir.hashing.Hasher;
import org.graalvm.compiler.lir.hashing.IntHasher;
import org.graalvm.compiler.phases.util.Providers;
import jdk.vm.ci.amd64.AMD64;
@ -317,8 +317,9 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
@Override
public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
boolean isSelfEqualsCheck = cond == Condition.EQ && !unorderedIsTrue && left.equals(right);
Condition finalCondition = emitCompare(cmpKind, left, right, cond);
append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability, isSelfEqualsCheck));
return;
}
@ -459,10 +460,15 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
finalCondition = emitCompare(cmpKind, left, right, cond);
}
return emitCondMoveOp(finalCondition, finalTrueValue, finalFalseValue, isFloatComparison, unorderedIsTrue);
boolean isSelfEqualsCheck = isFloatComparison && finalCondition == Condition.EQ && left.equals(right);
return emitCondMoveOp(finalCondition, finalTrueValue, finalFalseValue, isFloatComparison, unorderedIsTrue, isSelfEqualsCheck);
}
private Variable emitCondMoveOp(Condition condition, Value trueValue, Value falseValue, boolean isFloatComparison, boolean unorderedIsTrue) {
return emitCondMoveOp(condition, trueValue, falseValue, isFloatComparison, unorderedIsTrue, false);
}
private Variable emitCondMoveOp(Condition condition, Value trueValue, Value falseValue, boolean isFloatComparison, boolean unorderedIsTrue, boolean isSelfEqualsCheck) {
boolean isParityCheckNecessary = isFloatComparison && unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(condition);
Variable result = newVariable(trueValue.getValueKind());
if (!isParityCheckNecessary && isIntConstant(trueValue, 1) && isIntConstant(falseValue, 0)) {
@ -485,7 +491,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
append(new CondSetOp(result, condition.negate()));
}
} else if (isFloatComparison) {
append(new FloatCondMoveOp(result, condition, unorderedIsTrue, load(trueValue), load(falseValue)));
append(new FloatCondMoveOp(result, condition, unorderedIsTrue, load(trueValue), load(falseValue), isSelfEqualsCheck));
} else {
append(new CondMoveOp(result, condition, load(trueValue), loadNonConst(falseValue)));
}
@ -686,16 +692,31 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
}
@Override
protected Optional<Hasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
return Hasher.forKeys(keyConstants, minDensity);
protected Optional<IntHasher> hasherFor(JavaConstant[] keyConstants, double minDensity) {
int[] keys = new int[keyConstants.length];
for (int i = 0; i < keyConstants.length; i++) {
keys[i] = keyConstants[i].asInt();
}
return IntHasher.forKeys(keys);
}
@Override
protected void emitHashTableSwitch(Hasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
Value index = hasher.hash(value, arithmeticLIRGen);
protected void emitHashTableSwitch(IntHasher hasher, JavaConstant[] keys, LabelRef defaultTarget, LabelRef[] targets, Value value) {
Value hash = value;
if (hasher.factor > 1) {
Value factor = emitJavaConstant(JavaConstant.forShort(hasher.factor));
hash = arithmeticLIRGen.emitMul(hash, factor, false);
}
if (hasher.shift > 0) {
Value shift = emitJavaConstant(JavaConstant.forByte(hasher.shift));
hash = arithmeticLIRGen.emitShr(hash, shift);
}
Value cardinalityAnd = emitJavaConstant(JavaConstant.forInt(hasher.cardinality - 1));
hash = arithmeticLIRGen.emitAnd(hash, cardinalityAnd);
Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
Variable entryScratch = newVariable(LIRKind.value(target().arch.getWordKind()));
append(new HashTableSwitchOp(keys, defaultTarget, targets, value, index, scratch, entryScratch));
append(new HashTableSwitchOp(keys, defaultTarget, targets, value, hash, scratch, entryScratch));
}
@Override

@ -0,0 +1,64 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common;
import org.graalvm.compiler.debug.CompilationListener;
import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* Connects a {@link CompilationListener} to a {@link CompilerProfiler}.
*/
public class CompilationListenerProfiler implements CompilationListener {
private final int compileId;
private final CompilerProfiler profiler;
/**
* Creates a compilation listener that passes events for a specific compilation identified by
* {@code compileId} onto {@code profiler}.
*/
public CompilationListenerProfiler(CompilerProfiler profiler, int compileId) {
this.profiler = profiler;
this.compileId = compileId;
}
@Override
public void notifyInlining(ResolvedJavaMethod caller, ResolvedJavaMethod callee, boolean succeeded, CharSequence message, int bci) {
profiler.notifyCompilerInlingEvent(compileId, caller, callee, succeeded, message.toString(), bci);
}
@Override
public CompilerPhaseScope enterPhase(CharSequence name, int nesting) {
long start = profiler.getTicks();
return new CompilerPhaseScope() {
@Override
public void close() {
profiler.notifyCompilerPhaseEvent(compileId, start, name.toString(), nesting);
}
};
}
}

@ -0,0 +1,63 @@
/*
* Copyright (c) 2020, 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 jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* A profiling service that consumes compilation related events. The Java Flight Recorder (JFR) is
* an example of such a service that can be exposed via this interface.
*/
public interface CompilerProfiler {
/**
* Get current value of the profiler's time counter.
*
* @return the number of profile-defined time units that have elapsed
*/
long getTicks();
/**
* Notifies JFR when a compiler phase ends.
*
* @param compileId current computation unit id
* @param startTime when the phase started
* @param name name of the phase
* @param nestingLevel how many ancestor phases there are of the phase
*/
void notifyCompilerPhaseEvent(int compileId, long startTime, String name, int nestingLevel);
/**
* Notifies JFR when the compiler considers inlining {@code callee} into {@code caller}.
*
* @param compileId current computation unit id
* @param caller caller method
* @param callee callee method considered for inlining into {@code caller}
* @param succeeded true if {@code callee} was inlined into {@code caller}
* @param message extra information about inlining decision
* @param bci byte code index of call site
*/
void notifyCompilerInlingEvent(int compileId, ResolvedJavaMethod caller, ResolvedJavaMethod callee, boolean succeeded, String message, int bci);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -271,6 +271,6 @@ public final class GraalOptions {
@Option(help = "Alignment in bytes for loop header blocks.", type = OptionType.Expert)
public static final OptionKey<Integer> LoopHeaderAlignment = new OptionKey<>(16);
@Option(help = "Do not include membars for volatile accesses until the end of optimizations.", type = OptionType.Expert)
public static final OptionKey<Boolean> LateMembars = new OptionKey<>(true);
@Option(help = "String.indexOf invocations will be evaluated at compile time if the receiver is a constant and its length is lower than this value.", type = OptionType.Expert)
public static final OptionKey<Integer> StringIndexOfLimit = new OptionKey<>(4096);
}

@ -136,6 +136,14 @@ public class NumUtil {
return number / mod * mod;
}
public static int divideAndRoundUp(int number, int divisor) {
return (number + divisor - 1) / divisor;
}
public static long divideAndRoundUp(long number, long divisor) {
return (number + divisor - 1L) / divisor;
}
public static int log2Ceil(int val) {
int x = 1;
int log2 = 0;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -533,6 +533,130 @@ public enum Condition {
}
}
private static boolean in(Condition needle, Condition... haystack) {
for (Condition c : haystack) {
if (c == needle) {
return true;
}
}
return false;
}
/**
* Returns true if this condition and {@code other} will never both return true for the same
* arguments. This means that tests using these conditions can be safely reordered.
*/
public boolean trueIsDisjoint(Condition other) {
if (other == this) {
return false;
}
switch (this) {
case EQ: {
// 0 EQ 0 is not disjoint from 0 LE 0
// 0 EQ 0 is not disjoint from 0 GE 0
// 0 EQ 0 is not disjoint from 0 AE 0
// 0 EQ 0 is not disjoint from 0 BE 0
return in(other, NE, LT, GT, AT, BT);
}
case NE: {
// 0 NE 1 is not disjoint from 0 LT 1
// 0 NE 1 is not disjoint from 0 LE 1
// 0 NE -1 is not disjoint from 0 GT -1
// 0 NE -1 is not disjoint from 0 GE -1
// 1 NE 0 is not disjoint from 1 AE 0
// 0 NE 1 is not disjoint from 0 BE 1
// 1 NE 0 is not disjoint from 1 AT 0
// 0 NE 1 is not disjoint from 0 BT 1
return other == EQ;
}
case LT: {
// 0 LT 1 is not disjoint from 0 NE 1
// 0 LT 1 is not disjoint from 0 LE 1
// -1 LT 0 is not disjoint from -1 AE 0
// 0 LT 1 is not disjoint from 0 BE 1
// -1 LT 0 is not disjoint from -1 AT 0
// 0 LT 1 is not disjoint from 0 BT 1
return in(other, EQ, GT, GE);
}
case LE: {
// 0 LE 0 is not disjoint from 0 EQ 0
// 0 LE 1 is not disjoint from 0 NE 1
// 0 LE 1 is not disjoint from 0 LT 1
// 0 LE 0 is not disjoint from 0 GE 0
// 0 LE 0 is not disjoint from 0 AE 0
// 0 LE 0 is not disjoint from 0 BE 0
// -1 LE 0 is not disjoint from -1 AT 0
// 0 LE 1 is not disjoint from 0 BT 1
return other == GT;
}
case GT: {
// 0 GT -1 is not disjoint from 0 NE -1
// 0 GT -1 is not disjoint from 0 GE -1
// 1 GT 0 is not disjoint from 1 AE 0
// 0 GT -1 is not disjoint from 0 BE -1
// 1 GT 0 is not disjoint from 1 AT 0
// 0 GT -1 is not disjoint from 0 BT -1
return in(other, EQ, LT, LE);
}
case GE: {
// 0 GE 0 is not disjoint from 0 EQ 0
// 0 GE -1 is not disjoint from 0 NE -1
// 0 GE 0 is not disjoint from 0 LE 0
// 0 GE -1 is not disjoint from 0 GT -1
// 0 GE 0 is not disjoint from 0 AE 0
// 0 GE 0 is not disjoint from 0 BE 0
// 1 GE 0 is not disjoint from 1 AT 0
// 0 GE -1 is not disjoint from 0 BT -1
return other == LT;
}
case AE: {
// 0 AE 0 is not disjoint from 0 EQ 0
// 1 AE 0 is not disjoint from 1 NE 0
// -1 AE 0 is not disjoint from -1 LT 0
// 0 AE 0 is not disjoint from 0 LE 0
// 1 AE 0 is not disjoint from 1 GT 0
// 0 AE 0 is not disjoint from 0 GE 0
// 0 AE 0 is not disjoint from 0 BE 0
// 1 AE 0 is not disjoint from 1 AT 0
return other == BT;
}
case BE: {
// 0 BE 0 is not disjoint from 0 EQ 0
// 0 BE 1 is not disjoint from 0 NE 1
// 0 BE 1 is not disjoint from 0 LT 1
// 0 BE 0 is not disjoint from 0 LE 0
// 0 BE -1 is not disjoint from 0 GT -1
// 0 BE 0 is not disjoint from 0 GE 0
// 0 BE 0 is not disjoint from 0 AE 0
// 0 BE 1 is not disjoint from 0 BT 1
return other == AT;
}
case AT: {
// 1 AT 0 is not disjoint from 1 NE 0
// -1 AT 0 is not disjoint from -1 LT 0
// -1 AT 0 is not disjoint from -1 LE 0
// 1 AT 0 is not disjoint from 1 GT 0
// 1 AT 0 is not disjoint from 1 GE 0
// 1 AT 0 is not disjoint from 1 AE 0
return in(other, EQ, BE, BT);
}
case BT: {
// 0 BT 1 is not disjoint from 0 NE 1
// 0 BT 1 is not disjoint from 0 LT 1
// 0 BT 1 is not disjoint from 0 LE 1
// 0 BT -1 is not disjoint from 0 GT -1
// 0 BT -1 is not disjoint from 0 GE -1
// 0 BT 1 is not disjoint from 0 BE 1
return in(other, EQ, AE, AT);
}
}
throw new IllegalArgumentException(this.toString());
}
/**
* Return the join of this condition and {@code other}. Only non-null return values are
* meaningful.
*/
public Condition join(Condition other) {
if (other == this) {
return this;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,4 +41,6 @@ public interface CodeGenProviders {
ForeignCallsProvider getForeignCalls();
ConstantReflectionProvider getConstantReflection();
MetaAccessExtensionProvider getMetaAccessExtensionProvider();
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -26,9 +26,11 @@ package org.graalvm.compiler.core.common.spi;
import java.util.Arrays;
import jdk.internal.vm.compiler.word.LocationIdentity;
/**
* The name and signature of a foreign call. A foreign call differs from a normal compiled Java call
* in at least one of these aspects:
* The information required for high level code generation of a foreign call. A foreign call differs
* from a normal compiled Java call in at least one of these aspects:
* <ul>
* <li>The call is to C/C++/assembler code.</li>
* <li>The call uses different conventions for passing parameters or returning values.</li>
@ -42,59 +44,86 @@ import java.util.Arrays;
*/
public class ForeignCallDescriptor {
private final String name;
private final Class<?> resultType;
private final Class<?>[] argumentTypes;
protected final ForeignCallSignature signature;
protected final boolean isReexecutable;
protected final boolean canDeoptimize;
protected final boolean isGuaranteedSafepoint;
protected final LocationIdentity[] killedLocations;
public ForeignCallDescriptor(String name, Class<?> resultType, Class<?>[] argumentTypes, boolean isReexecutable, LocationIdentity[] killedLocations, boolean canDeoptimize,
boolean isGuaranteedSafepoint) {
this.isReexecutable = isReexecutable;
this.killedLocations = killedLocations;
this.canDeoptimize = canDeoptimize;
this.isGuaranteedSafepoint = isGuaranteedSafepoint;
this.signature = new ForeignCallSignature(name, resultType, argumentTypes);
public ForeignCallDescriptor(String name, Class<?> resultType, Class<?>... argumentTypes) {
this.name = name;
this.resultType = resultType;
this.argumentTypes = argumentTypes;
}
/**
* Gets the name of this foreign call.
*/
public ForeignCallSignature getSignature() {
return signature;
}
public String getName() {
return name;
return signature.getName();
}
/**
* Gets the return type of this foreign call.
*/
public Class<?> getResultType() {
return resultType;
return signature.getResultType();
}
/**
* Gets the argument types of this foreign call.
*/
public Class<?>[] getArgumentTypes() {
return argumentTypes.clone();
return signature.getArgumentTypes();
}
@Override
public boolean equals(Object o) {
return this == o;
}
@Override
public int hashCode() {
return name.hashCode();
return signature.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ForeignCallDescriptor) {
ForeignCallDescriptor other = (ForeignCallDescriptor) obj;
return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes);
}
return false;
/**
* Determines if a given foreign call is side-effect free. Deoptimization cannot return
* execution to a point before a foreign call that has a side effect.
*/
public boolean isReexecutable() {
return isReexecutable;
}
/**
* Gets the set of memory locations killed by a given foreign call. Returning the special value
* {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning
* any empty array denotes that the call does not kill any memory locations.
*/
public LocationIdentity[] getKilledLocations() {
return killedLocations;
}
/**
* Determines if deoptimization can occur during a given foreign call.
*/
public boolean canDeoptimize() {
return canDeoptimize;
}
/**
* Identifies foreign calls which are guaranteed to include a safepoint check.
*/
public boolean isGuaranteedSafepoint() {
return isGuaranteedSafepoint;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(name).append('(');
String sep = "";
for (Class<?> arg : argumentTypes) {
sb.append(sep).append(arg.getSimpleName());
sep = ",";
}
return sb.append(')').append(resultType.getSimpleName()).toString();
return getClass().getSimpleName() + "{" + signature +
", isReexecutable=" + isReexecutable +
", canDeoptimize=" + canDeoptimize +
", isGuaranteedSafepoint=" + isGuaranteedSafepoint +
", killedLocations=" + Arrays.toString(killedLocations) +
'}';
}
}

@ -0,0 +1,89 @@
/*
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common.spi;
import java.util.Arrays;
/**
* The name and signature of a {@link ForeignCallDescriptor foreign call}.
*/
public final class ForeignCallSignature {
private final String name;
private final Class<?> resultType;
private final Class<?>[] argumentTypes;
public ForeignCallSignature(String name, Class<?> resultType, Class<?>... argumentTypes) {
this.name = name;
this.resultType = resultType;
this.argumentTypes = argumentTypes;
}
/**
* Gets the name of this foreign call.
*/
public String getName() {
return name;
}
/**
* Gets the return type of this foreign call.
*/
public Class<?> getResultType() {
return resultType;
}
/**
* Gets the argument types of this foreign call.
*/
public Class<?>[] getArgumentTypes() {
return argumentTypes.clone();
}
@Override
public int hashCode() {
return name.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ForeignCallSignature) {
ForeignCallSignature other = (ForeignCallSignature) obj;
return other.name.equals(name) && other.resultType.equals(resultType) && Arrays.equals(other.argumentTypes, argumentTypes);
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(name).append('(');
String sep = "";
for (Class<?> arg : argumentTypes) {
sb.append(sep).append(arg.getSimpleName());
sep = ",";
}
return sb.append(')').append(resultType.getSimpleName()).toString();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,7 +25,6 @@
package org.graalvm.compiler.core.common.spi;
import org.graalvm.compiler.core.common.LIRKind;
import jdk.internal.vm.compiler.word.LocationIdentity;
import jdk.vm.ci.code.ValueKindFactory;
@ -34,36 +33,20 @@ import jdk.vm.ci.code.ValueKindFactory;
*/
public interface ForeignCallsProvider extends ValueKindFactory<LIRKind> {
/**
* Determines if a given foreign call is side-effect free. Deoptimization cannot return
* execution to a point before a foreign call that has a side effect.
*/
boolean isReexecutable(ForeignCallDescriptor descriptor);
/**
* Gets the set of memory locations killed by a given foreign call. Returning the special value
* {@link LocationIdentity#any()} denotes that the call kills all memory locations. Returning
* any empty array denotes that the call does not kill any memory locations.
*/
LocationIdentity[] getKilledLocations(ForeignCallDescriptor descriptor);
/**
* Determines if deoptimization can occur during a given foreign call.
*/
boolean canDeoptimize(ForeignCallDescriptor descriptor);
/**
* Identifies foreign calls which are guaranteed to include a safepoint check.
*/
boolean isGuaranteedSafepoint(ForeignCallDescriptor descriptor);
/**
* Gets the linkage for a foreign call.
*/
ForeignCallLinkage lookupForeignCall(ForeignCallDescriptor descriptor);
/**
* Return true if the foreign call has a binding.
* Gets the linkage for a foreign call.
*/
boolean isAvailable(ForeignCallDescriptor descriptor);
default ForeignCallLinkage lookupForeignCall(ForeignCallSignature signature) {
return lookupForeignCall(getDescriptor(signature));
}
/**
* Gets the descriptor for a foreign call.
*/
ForeignCallDescriptor getDescriptor(ForeignCallSignature signature);
}

@ -0,0 +1,50 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.common.spi;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaType;
/**
* Provides additional meta data about JVMCI objects that is not provided by the VM itself, and
* therefore does not need to be in JVMCI itself.
*/
public interface MetaAccessExtensionProvider {
/**
* The {@link JavaKind} used to store the provided type in a field or array element. This can be
* different than the {@link JavaType#getJavaKind} for types that are intercepted and
* transformed by the compiler.
*/
JavaKind getStorageKind(JavaType type);
/**
* Checks if a dynamic allocation of the provided type can be canonicalized to a regular
* allocation node. If the method returns false, then the dynamic allocation would throw an
* exception at run time and therefore canonicalization would miss that exception.
*/
boolean canConstantFoldDynamicAllocation(ResolvedJavaType type);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -339,14 +339,14 @@ public class FloatStamp extends PrimitiveStamp {
if (Float.isNaN(value.asFloat())) {
result = new FloatStamp(32, Double.NaN, Double.NaN, false);
} else {
result = new FloatStamp(32, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
result = new FloatStamp(32, value.asFloat(), value.asFloat(), true);
}
break;
case Double:
if (Double.isNaN(value.asDouble())) {
result = new FloatStamp(64, Double.NaN, Double.NaN, false);
} else {
result = new FloatStamp(64, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
result = new FloatStamp(64, value.asDouble(), value.asDouble(), true);
}
break;
default:

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -44,6 +44,11 @@ public final class BitMap2D {
}
public BitMap2D(int sizeInSlots, int bitsPerSlot) {
long nBits = (long) sizeInSlots * bitsPerSlot;
if (nBits > Integer.MAX_VALUE) {
// Avoids issues where (sizeInSlots * bitsPerSlot) wraps around to a positive integer
throw new OutOfMemoryError("Cannot allocate a BitSet for " + nBits + " bits");
}
map = new BitSet(sizeInSlots * bitsPerSlot);
this.bitsPerSlot = bitsPerSlot;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -548,7 +548,7 @@ public class MatchProcessor extends AbstractProcessor {
}
out.printf(" private static final String[] %s = new String[] {%s};\n", invoker.argumentsListName(), args);
out.printf(" private static final class %s implements MatchGenerator {\n", invoker.wrapperClass());
out.printf(" static MatchGenerator instance = new %s();\n", invoker.wrapperClass());
out.printf(" static final MatchGenerator instance = new %s();\n", invoker.wrapperClass());
out.printf(" @Override\n");
out.printf(" public ComplexMatchResult match(NodeMatchRules nodeMatchRules, Object...args) {\n");
out.printf(" return ((%s) nodeMatchRules).%s(%s);\n", invoker.nodeLIRBuilderClass, invoker.methodName, types);

@ -0,0 +1,160 @@
/*
* Copyright (c) 2020, 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.junit.Test;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.java.NewArrayNode;
public class ArrayCopyVirtualizationTest extends GraalCompilerTest {
@Override
protected void checkMidTierGraph(StructuredGraph graph) {
assertTrue(graph.getNodes().filter(node -> node instanceof NewArrayNode).count() == 0, "shouldn't require allocation in %s", graph);
super.checkMidTierGraph(graph);
}
public byte byteCopyVirtualization() {
byte[] array = new byte[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public short shortCopyVirtualization() {
short[] array = new short[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 2);
return array[0];
}
public char charCopyVirtualization() {
char[] array = new char[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public int intCopyVirtualization() {
int[] array = new int[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public long longCopyVirtualization() {
long[] array = new long[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public float floatCopyVirtualization() {
float[] array = new float[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public double doubleCopyVirtualization() {
double[] array = new double[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
public Object objectCopyVirtualization() {
Object[] array = new Object[]{1, 2, 3, 4};
System.arraycopy(array, 1, array, 0, 3);
return array[0];
}
@Test
public void testCopyVirtualization() {
test("byteCopyVirtualization");
test("shortCopyVirtualization");
test("charCopyVirtualization");
test("intCopyVirtualization");
test("longCopyVirtualization");
test("floatCopyVirtualization");
test("doubleCopyVirtualization");
test("objectCopyVirtualization");
}
public byte byteCopyBackwardsVirtualization() {
byte[] array = new byte[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public short shortCopyBackwardsVirtualization() {
short[] array = new short[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public char charCopyBackwardsVirtualization() {
char[] array = new char[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public int intCopyBackwardsVirtualization() {
int[] array = new int[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public long longCopyBackwardsVirtualization() {
long[] array = new long[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public float floatCopyBackwardsVirtualization() {
float[] array = new float[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public double doubleCopyBackwardsVirtualization() {
double[] array = new double[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
public Object objectCopyBackwardsVirtualization() {
Object[] array = new Object[]{1, 2, 3, 4};
System.arraycopy(array, 0, array, 1, 3);
return array[3];
}
@Test
public void testCopyBackwardsVirtualization() {
test("byteCopyBackwardsVirtualization");
test("shortCopyBackwardsVirtualization");
test("charCopyBackwardsVirtualization");
test("intCopyBackwardsVirtualization");
test("longCopyBackwardsVirtualization");
test("floatCopyBackwardsVirtualization");
test("doubleCopyBackwardsVirtualization");
test("objectCopyBackwardsVirtualization");
}
}

@ -252,6 +252,21 @@ public class BoxingEliminationTest extends GraalCompilerTest {
test("materializeTest1Snippet", 1);
}
public static Float materializeTest2Snippet(float a) {
Float v = a;
if (v == a) {
return v;
} else {
return null;
}
}
@Test
public void materializeTest2() {
test("materializeTest2Snippet", 1f);
}
public static int intTest1Snippet() {
return Integer.valueOf(1);
}

@ -40,6 +40,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
@ -60,7 +61,7 @@ import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
@ -150,13 +151,23 @@ public class CheckGraalInvariants extends GraalCompilerTest {
}
protected String getClassPath() {
String bootclasspath;
String classpath;
if (JavaVersionUtil.JAVA_SPEC <= 8) {
bootclasspath = System.getProperty("sun.boot.class.path");
classpath = System.getProperty("sun.boot.class.path");
} else {
bootclasspath = JRT_CLASS_PATH_ENTRY;
classpath = JRT_CLASS_PATH_ENTRY;
}
return bootclasspath;
// Also process classes that go into the libgraal native image.
String javaClassPath = System.getProperty("java.class.path");
if (javaClassPath != null) {
for (String path : javaClassPath.split(File.pathSeparator)) {
if (path.contains("libgraal") && !path.contains("processor")) {
classpath += File.pathSeparator + path;
}
}
}
return classpath;
}
protected boolean shouldLoadClass(String className) {
@ -345,6 +356,8 @@ public class CheckGraalInvariants extends GraalCompilerTest {
verifiers.add(new VerifyGetOptionsUsage());
verifiers.add(new VerifyUnsafeAccess());
loadVerifiers(verifiers);
VerifyFoldableMethods foldableMethodsVerifier = new VerifyFoldableMethods();
if (tool.shouldVerifyFoldableMethods()) {
verifiers.add(foldableMethodsVerifier);
@ -354,7 +367,7 @@ public class CheckGraalInvariants extends GraalCompilerTest {
for (Method m : BadUsageWithEquals.class.getDeclaredMethods()) {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
try (DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER)) {
try (DebugContext debug = new Builder(options).build()) {
StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES).method(method).build();
try (DebugCloseable s = debug.disableIntercept(); DebugContext.Scope ds = debug.scope("CheckingGraph", graph, method)) {
graphBuilderSuite.apply(graph, context);
@ -408,7 +421,7 @@ public class CheckGraalInvariants extends GraalCompilerTest {
String methodName = className + "." + method.getName();
if (matches(filters, methodName)) {
executor.execute(() -> {
try (DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER)) {
try (DebugContext debug = new Builder(options).build()) {
boolean isSubstitution = method.getAnnotation(Snippet.class) != null || method.getAnnotation(MethodSubstitution.class) != null;
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).setIsSubstitution(isSubstitution).build();
try (DebugCloseable s = debug.disableIntercept(); DebugContext.Scope ds = debug.scope("CheckingGraph", graph, method)) {
@ -471,6 +484,13 @@ public class CheckGraalInvariants extends GraalCompilerTest {
}
}
@SuppressWarnings("unchecked")
private static void loadVerifiers(List<VerifyPhase<CoreProviders>> verifiers) {
for (VerifyPhase<CoreProviders> verifier : ServiceLoader.load(VerifyPhase.class)) {
verifiers.add(verifier);
}
}
/**
* Initializes a map from a field annotated by {@link Option} to a set that will be used to
* collect methods that accesses the option field.

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -108,4 +108,27 @@ public class ConditionTest {
}
}
static int[] intBoundaryValues = new int[]{-1, 0, 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, Integer.MAX_VALUE - 1, Integer.MAX_VALUE};
@Test
public void testTrueIsDisjoint() {
for (Condition c1 : Condition.values()) {
for (Condition c2 : Condition.values()) {
if (c1.trueIsDisjoint(c2)) {
for (int v1 : intBoundaryValues) {
for (int v2 : intBoundaryValues) {
JavaConstant a = JavaConstant.forInt(v1);
JavaConstant b = JavaConstant.forInt(v2);
boolean result1 = c1.foldCondition(a, b, null, false);
boolean result2 = c2.foldCondition(a, b, null, false);
// If these conditions are disjoint then both conditions can't evaluate
// to true for the same inputs.
assertFalse(String.format("%s %s %s (%s) is not disjoint from %s %s %s (%s)", a, c1, b, result1, a, c2, b, result2), result1 && result2);
}
}
}
}
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -93,7 +93,7 @@ public class GuardPrioritiesTest extends GraphScheduleTest {
return graph;
}
public int unknownCondition(Integer c, Object o, int[] a, Integer i) {
public int unknownCondition(int c, Object o, int[] a, int i) {
if (o != null) {
GraalDirectives.deoptimizeAndInvalidate();
}

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020, 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.api.directives.GraalDirectives.injectBranchProbability;
import org.junit.Test;
/**
* Test extracted from reproducer in https://github.com/oracle/graal/issues/2493.
*/
public class IfCanonicalizerSwapTest extends GraalCompilerTest {
public static String testSnippet1(long value) {
if (injectBranchProbability(0.50, value >= 0L) && injectBranchProbability(0.00, value <= 35L)) {
return "JustRight";
} else {
if (injectBranchProbability(0.50, value > 35L)) {
return "TooHot";
} else {
return "TooCold";
}
}
}
@Test
public void test1() {
test("testSnippet1", -1L);
test("testSnippet1", 100L);
test("testSnippet1", 10L);
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -26,17 +26,20 @@
package org.graalvm.compiler.core.test;
import jdk.vm.ci.aarch64.AArch64;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.internal.vm.compiler.collections.EconomicMap;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
import org.graalvm.compiler.nodes.extended.MembarNode;
import org.graalvm.compiler.nodes.memory.FixedAccessNode;
import org.graalvm.compiler.nodes.memory.MemoryAccess;
import org.graalvm.compiler.nodes.memory.ReadNode;
@ -78,7 +81,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test01() {
List<TypePair> accesses = compile("volatileFieldLoadFieldLoad", stressTestEarlyReads());
List<TypePair> accesses = getAccesses("volatileFieldLoadFieldLoad", stressTestEarlyReads());
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
@ -95,7 +98,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test02() {
List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldLoad", stressTestEarlyReads());
List<TypePair> accesses = getAccesses("volatileFieldLoadVolatileFieldLoad", stressTestEarlyReads());
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
@ -112,7 +115,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test03() {
List<TypePair> accesses = compile("volatileFieldLoadVolatileFieldStore");
List<TypePair> accesses = getAccesses("volatileFieldLoadVolatileFieldStore");
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
@ -128,7 +131,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test04() {
List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldLoad", stressTestEarlyReads());
List<TypePair> accesses = getAccesses("volatileFieldStoreVolatileFieldLoad", stressTestEarlyReads());
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
@ -145,7 +148,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test05() {
List<TypePair> accesses = compile("fieldLoadVolatileFieldStore");
List<TypePair> accesses = getAccesses("fieldLoadVolatileFieldStore");
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), regularAccessField);
@ -161,7 +164,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
@Test
public void test06() {
List<TypePair> accesses = compile("volatileFieldStoreVolatileFieldStore");
List<TypePair> accesses = getAccesses("volatileFieldStoreVolatileFieldStore");
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccessType);
@ -170,6 +173,119 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
Assert.assertTrue(accesses.get(1).isWrite());
}
public static int volatileFieldLoad() {
return VolatileAccess.field;
}
@Test
public void test07() {
verifyMembars("volatileFieldLoad", membarsExpected());
}
private boolean membarsExpected() {
return !(getTarget().arch instanceof AArch64);
}
public static void volatileFieldStore(int v) {
VolatileAccess.field = v;
}
@Test
public void test08() {
verifyMembars("volatileFieldStore", membarsExpected());
}
// Unused field load should be optimized out and leave no barrier behind
@SuppressWarnings("unused")
public static void volatileFieldStoreUnusedVolatileFieldLoadVolatileFieldStore(int v2) {
VolatileAccess2.field = v2;
int v1 = VolatileAccess.field;
VolatileAccess2.field = v2;
}
@Test
public void test09() {
StructuredGraph graph = getFinalGraph(getResolvedJavaMethod("volatileFieldStoreUnusedVolatileFieldLoadVolatileFieldStore"));
List<TypePair> accesses = getAccesses(graph);
Assert.assertEquals(accesses.size(), 2);
Assert.assertEquals(accesses.get(0).getType(), volatileAccess2Type);
Assert.assertEquals(accesses.get(1).getType(), volatileAccess2Type);
Assert.assertTrue(accesses.get(0).isWrite());
Assert.assertTrue(accesses.get(1).isWrite());
Assert.assertEquals(membarsExpected() ? 4 : 0, getMembars(graph).size());
}
// Unused field load should be optimized out and leave no barrier behind
@SuppressWarnings("unused")
public static void unusedVolatileFieldLoadVolatileFieldStore(int v2) {
int v1 = VolatileAccess.field;
VolatileAccess2.field = v2;
}
@Test
public void test10() {
StructuredGraph graph = getFinalGraph(getResolvedJavaMethod("unusedVolatileFieldLoadVolatileFieldStore"));
List<TypePair> accesses = getAccesses(graph);
Assert.assertEquals(accesses.size(), 1);
Assert.assertEquals(accesses.get(0).getType(), volatileAccess2Type);
Assert.assertTrue(accesses.get(0).isWrite());
Assert.assertEquals(membarsExpected() ? 2 : 0, getMembars(graph).size());
}
public static int unsafeVolatileFieldLoad(Object o, long offset) {
return UNSAFE.getIntVolatile(o, offset);
}
@Test
public void test11() {
verifyMembars("unsafeVolatileFieldLoad", membarsExpected());
}
public static void unsafeVolatileFieldStore(Object o, long offset, int v) {
UNSAFE.putIntVolatile(o, offset, v);
}
@Test
public void test12() {
verifyMembars("unsafeVolatileFieldStore", membarsExpected());
}
private void verifyMembars(String method, boolean expectsMembar) {
StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(method));
StructuredGraph.ScheduleResult schedule = graph.getLastSchedule();
ControlFlowGraph cfg = schedule.getCFG();
Block[] blocks = cfg.getBlocks();
Assert.assertEquals(blocks.length, 1);
Block block = blocks[0];
List<Node> nodes = schedule.nodesFor(block);
Node preBarrier = null;
Node postBarrier = null;
Node mem = null;
for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i);
if (node instanceof MembarNode) {
if (preBarrier == null) {
Assert.assertNull(mem);
preBarrier = node;
} else {
Assert.assertNull(postBarrier);
Assert.assertNotNull(mem);
postBarrier = node;
}
} else if (node instanceof MemoryAccess) {
Assert.assertEquals(preBarrier != null, expectsMembar);
Assert.assertNull(postBarrier);
Assert.assertNull(mem);
mem = node;
}
}
Assert.assertEquals(preBarrier != null, expectsMembar);
Assert.assertEquals(postBarrier != null, expectsMembar);
Assert.assertNotNull(mem);
}
private static OptionValues stressTestEarlyReads() {
EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
overrides.put(StressTestEarlyReads, true);
@ -198,7 +314,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
}
}
private List<TypePair> compile(String test, OptionValues options) {
private List<TypePair> getAccesses(String test, OptionValues options) {
StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test), options);
return getAccesses(graph);
}
@ -212,7 +328,7 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
n -> new TypePair(n instanceof ReadNode, classForAccess((FixedAccessNode) n))).collect(Collectors.toList());
}
private List<TypePair> compile(String test) {
private List<TypePair> getAccesses(String test) {
StructuredGraph graph = getFinalGraph(getResolvedJavaMethod(test));
return getAccesses(graph);
}
@ -230,4 +346,11 @@ public class LateMembarInsertionTest extends GraalCompilerTest {
return javaType;
}
private static List<Node> getMembars(StructuredGraph graph) {
StructuredGraph.ScheduleResult schedule = graph.getLastSchedule();
ControlFlowGraph cfg = schedule.getCFG();
Block[] blocks = cfg.getBlocks();
return Arrays.stream(blocks).flatMap(b -> schedule.nodesFor(b).stream()).filter(n -> n instanceof MembarNode).collect(Collectors.toList());
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,8 +28,8 @@ import org.graalvm.compiler.loop.DefaultLoopPolicies;
import org.graalvm.compiler.loop.phases.LoopFullUnrollPhase;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.java.MonitorEnterNode;
import org.graalvm.compiler.nodes.java.MonitorExitNode;
import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
@ -71,7 +71,7 @@ public class LockEliminationTest extends GraalCompilerTest {
StructuredGraph graph = getGraph("testSynchronizedSnippet", false);
createCanonicalizerPhase().apply(graph, getProviders());
new LockEliminationPhase().apply(graph);
assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
}
@ -89,7 +89,7 @@ public class LockEliminationTest extends GraalCompilerTest {
StructuredGraph graph = getGraph("testSynchronizedMethodSnippet", false);
createCanonicalizerPhase().apply(graph, getProviders());
new LockEliminationPhase().apply(graph);
assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
}
@ -109,7 +109,7 @@ public class LockEliminationTest extends GraalCompilerTest {
HighTierContext context = getDefaultHighTierContext();
new LoopFullUnrollPhase(canonicalizer, new DefaultLoopPolicies()).apply(graph, context);
new LockEliminationPhase().apply(graph);
assertDeepEquals(1, graph.getNodes().filter(RawMonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorEnterNode.class).count());
assertDeepEquals(1, graph.getNodes().filter(MonitorExitNode.class).count());
}
@ -157,12 +157,12 @@ public class LockEliminationTest extends GraalCompilerTest {
public void testEscapeAnalysis() {
StructuredGraph graph = getGraph("testEscapeAnalysisSnippet", true);
assertDeepEquals(3, graph.getNodes().filter(RawMonitorEnterNode.class).count());
assertDeepEquals(3, graph.getNodes().filter(MonitorEnterNode.class).count());
assertDeepEquals(3, graph.getNodes().filter(MonitorExitNode.class).count());
new LockEliminationPhase().apply(graph);
assertDeepEquals(2, graph.getNodes().filter(RawMonitorEnterNode.class).count());
assertDeepEquals(2, graph.getNodes().filter(MonitorEnterNode.class).count());
assertDeepEquals(2, graph.getNodes().filter(MonitorExitNode.class).count());
}
}

@ -24,12 +24,7 @@
package org.graalvm.compiler.core.test;
import jdk.vm.ci.meta.JavaConstant;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.ReturnNode;
import org.graalvm.compiler.nodes.StructuredGraph;
@ -40,6 +35,10 @@ import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.schedule.SchedulePhase;
import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.meta.JavaConstant;
public class LongNodeChainTest extends GraalCompilerTest {
@ -56,7 +55,7 @@ public class LongNodeChainTest extends GraalCompilerTest {
private void longAddChain(boolean reverse) {
HighTierContext context = getDefaultHighTierContext();
OptionValues options = getInitialOptions();
StructuredGraph graph = new StructuredGraph.Builder(options, DebugContext.create(options, DebugHandlersFactory.LOADER)).build();
StructuredGraph graph = new StructuredGraph.Builder(options, new Builder(options).build()).build();
ValueNode constant = graph.unique(ConstantNode.forPrimitive(JavaConstant.INT_1));
ValueNode value = null;
if (reverse) {

@ -25,13 +25,11 @@
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.memory.WriteNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.phases.common.FloatingReadPhase;
import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.Suites;
import org.graalvm.compiler.runtime.RuntimeProvider;
import org.junit.Test;
public class MemoryGraphCanonicalizeTest extends GraalCompilerTest {
@ -69,15 +67,15 @@ public class MemoryGraphCanonicalizeTest extends GraalCompilerTest {
@Test
public void testComplexElimination() {
testGraph("complexElimination", 6);
testGraph("complexElimination", 5);
}
public void testGraph(String name, int expectedWrites) {
StructuredGraph graph = parseEager(name, StructuredGraph.AllowAssumptions.YES);
HighTierContext context = getDefaultHighTierContext();
new LoweringPhase(createCanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
new IncrementalCanonicalizerPhase<>(createCanonicalizerPhase(), new FloatingReadPhase()).apply(graph, context);
createCanonicalizerPhase().apply(graph, context);
Suites s = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getSuites().getDefaultSuites(getInitialOptions());
s.getHighTier().apply(graph, getDefaultHighTierContext());
s.getMidTier().apply(graph, getDefaultMidTierContext());
int writes = graph.getNodes().filter(WriteNode.class).count();
assertTrue(writes == expectedWrites, "Expected %d writes, found %d", expectedWrites, writes);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -40,6 +40,7 @@ import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodes.ReturnNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.memory.FloatingReadNode;
@ -699,16 +700,20 @@ public class MemoryScheduleTest extends GraphScheduleTest {
createInliningPhase(canonicalizer).apply(graph, context);
}
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
graph.clearAllStateAfter();
}
debug.dump(DebugContext.BASIC_LEVEL, graph, "after removal of framestates");
new FloatingReadPhase().apply(graph);
new RemoveValueProxyPhase().apply(graph);
MidTierContext midContext = new MidTierContext(getProviders(), getTargetProvider(), OptimisticOptimizations.ALL, graph.getProfilingInfo());
new GuardLoweringPhase().apply(graph, midContext);
if (mode == TestMode.WITHOUT_FRAMESTATES || mode == TestMode.INLINED_WITHOUT_FRAMESTATES) {
graph.clearAllStateAfter();
// disable stat split verification
graph.setGuardsStage(GuardsStage.AFTER_FSA);
}
debug.dump(DebugContext.BASIC_LEVEL, graph, "after removal of framestates");
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.MID_TIER).apply(graph, midContext);
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.LOW_TIER).apply(graph, midContext);

@ -0,0 +1,67 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Arm Limited and affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.calc.RightShiftNode;
import org.graalvm.compiler.nodes.calc.UnsignedRightShiftNode;
import org.junit.Test;
public class NegateCanonicalizationTest extends GraalCompilerTest {
public static int negateInt(int x) {
return -(x >> 31);
}
public static long negateLong(long x) {
return -(x >> 63);
}
public static int signExtractInt(int x) {
return (x >> 31) >>> 31;
}
public static long signExtractLong(long x) {
return (x >> 63) >>> 63;
}
private void checkNodes(String methodName) {
StructuredGraph graph = parseForCompile(getResolvedJavaMethod(methodName));
createCanonicalizerPhase().apply(graph, getProviders());
assertTrue(graph.getNodes().filter(NegateNode.class).count() == 0);
assertTrue(graph.getNodes().filter(RightShiftNode.class).count() == 0);
assertTrue(graph.getNodes().filter(UnsignedRightShiftNode.class).count() == 1);
}
@Test
public void testNegate() {
checkNodes("negateInt");
checkNodes("negateLong");
checkNodes("signExtractInt");
checkNodes("signExtractLong");
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, 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
@ -29,9 +29,8 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
import java.util.Iterator;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
@ -39,10 +38,15 @@ import org.graalvm.compiler.graph.NodeSuccessorList;
import org.graalvm.compiler.graph.Position;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.EndNode;
import org.graalvm.compiler.nodes.MergeNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.junit.Assert;
import org.junit.Test;
public class NodePosIteratorTest extends GraalCompilerTest {
@ -63,6 +67,27 @@ public class NodePosIteratorTest extends GraalCompilerTest {
}
@Test
public void testNodeInputIteratorLimit() {
DebugContext debug = getDebugContext();
StructuredGraph graph = new StructuredGraph.Builder(debug.getOptions(), debug,
StructuredGraph.AllowAssumptions.YES).build();
AbstractMergeNode merge = graph.add(new MergeNode());
for (int i = 0; i < 65536; i++) {
EndNode end = graph.add(new EndNode());
merge.addForwardEnd(end);
}
merge.inputs().count();
EndNode end = graph.add(new EndNode());
try {
merge.addForwardEnd(end);
} catch (PermanentBailoutException e) {
return;
}
Assert.fail("Expected a permanent bailout exception due to too high number of inputs");
}
@Test
public void testInputs() {
TestNode n = new TestNode();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -62,6 +62,7 @@ public class SchedulingTest extends GraphScheduleTest {
fs.replaceAtUsages(null);
GraphUtil.killWithUnusedFloatingInputs(fs);
}
graph.clearAllStateAfter();
SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.LATEST);
schedulePhase.apply(graph);
ScheduleResult schedule = graph.getLastSchedule();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.BeginNode;
@ -51,7 +52,7 @@ public class SimpleCFGTest extends GraalCompilerTest {
@Test
public void testImplies() {
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, new GraalDebugHandlersFactory(getSnippetReflection()));
DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(getSnippetReflection())).build();
StructuredGraph graph = new StructuredGraph.Builder(options, debug, AllowAssumptions.YES).build();
EndNode trueEnd = graph.add(new EndNode());

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -30,8 +30,8 @@ import java.lang.reflect.Method;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.java.GraphBuilderPhase;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
@ -93,7 +93,7 @@ public class StaticInterfaceFieldTest extends GraalTest {
final Method m = getMethod(clazz, methodName);
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).build();
try (DebugCloseable s = debug.disableIntercept(); DebugContext.Scope ds = debug.scope("GraphBuilding", graph, method)) {
graphBuilderSuite.apply(graph, context);

@ -282,6 +282,7 @@ public class UnsafeVirtualizationTest extends GraalCompilerTest {
} else {
UNSAFE.putLong(t, getUnsafeByteArrayOffset(0), l2);
}
sideEffect();
if (c) {
GraalDirectives.deoptimize();
}
@ -495,7 +496,7 @@ public class UnsafeVirtualizationTest extends GraalCompilerTest {
VirtualObjectNode virtual = graph.getNodes().filter(VirtualObjectNode.class).first();
if (virtual instanceof VirtualArrayNode) {
VirtualArrayNode array = (VirtualArrayNode) virtual;
if (array.isVirtualByteArray()) {
if (array.isVirtualByteArray(context.getMetaAccessExtensionProvider())) {
canVirtualize = context.getPlatformConfigurationProvider().canVirtualizeLargeByteArrayAccess();
}
}

@ -0,0 +1,117 @@
/*
* Copyright (c) 2020, 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.debug.DebugOptions.DumpOnError;
import java.util.List;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.cfg.BlockMap;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeMap;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.extended.OpaqueNode;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* This test verifies that the backend detects graphs for which the scheduling is broken, i.e. input
* values are scheduled in non-dominating blocks causing illegal flow of values in the control flow
* graph.
*/
public class UnschedulableGraphTest extends GraalCompilerTest {
public static int snippet01(int a, int b, int c) {
if (GraalDirectives.sideEffect(a) == b) {
GraalDirectives.sideEffect(b);
GraalDirectives.controlFlowAnchor();
} else {
GraalDirectives.sideEffect(c);
GraalDirectives.controlFlowAnchor();
}
GraalDirectives.sideEffect();
GraalDirectives.controlFlowAnchor();
return GraalDirectives.opaque(-a) + GraalDirectives.opaque(-b);
}
@Override
protected void checkLowTierGraph(StructuredGraph graph) {
super.checkLowTierGraph(graph);
ScheduleResult res = graph.getLastSchedule();
BlockMap<List<Node>> blockToNode = res.getBlockToNodesMap();
NodeMap<Block> nodeToBlock = res.getNodeToBlockMap();
Assert.assertEquals(4, res.getCFG().getBlocks().length);
Block split = res.getCFG().getStartBlock();
Assert.assertEquals(2, split.getSuccessorCount());
Block trueSucc = split.getSuccessors()[0];
Block falseSucc = split.getSuccessors()[1];
Block merge = trueSucc.getFirstSuccessor();
Assert.assertEquals(merge, falseSucc.getFirstSuccessor());
for (OpaqueNode op : graph.getNodes().filter(OpaqueNode.class)) {
Assert.assertEquals(merge, res.getNodeToBlockMap().get(op));
}
int k = 0;
// destroy dominance relation for NegateNode nodes, they no longer dominate the addition
for (NegateNode op : graph.getNodes().filter(NegateNode.class)) {
final Block nonDominatingBlock = k++ % 2 == 0 ? trueSucc : falseSucc;
blockToNode.get(merge).remove(op);
blockToNode.get(nonDominatingBlock).add(0, op);
nodeToBlock.set(op, nonDominatingBlock);
}
graph.getDebug().dump(DebugContext.VERBOSE_LEVEL, graph, "After changing constant schedule");
}
private DebugContext getDebugContext(ResolvedJavaMethod method) {
OptionValues options = new OptionValues(getInitialOptions(), DumpOnError, false);
return getDebugContext(options, null, method);
}
@Test
@SuppressWarnings("try")
public void test01() {
ResolvedJavaMethod method = getResolvedJavaMethod("snippet01");
try (AutoCloseable c = new TTY.Filter();
DebugContext debug = getDebugContext(method);
DebugCloseable s = debug.disableIntercept()) {
test("snippet01", 0, 1, 2);
Assert.fail("Compilation should not reach this point, must throw an exception before");
} catch (Throwable t) {
if (t.getMessage().contains("liveIn set of first block must be empty")) {
return;
}
throw new AssertionError(t);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,8 +33,8 @@ import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.RetryableBailoutException;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.java.GraphBuilderPhase;
import org.graalvm.compiler.nodes.StructuredGraph;
@ -128,7 +128,7 @@ public class VerifyBailoutUsageTest {
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
for (Method m : c.getDeclaredMethods()) {
if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, 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
@ -144,8 +144,8 @@ public class VerifyDebugUsage extends VerifyPhase<CoreProviders> {
"org.graalvm.compiler.phases.BasePhase.dumpAfter",
"org.graalvm.compiler.phases.BasePhase.dumpBefore",
"org.graalvm.compiler.core.GraalCompiler.emitFrontEnd",
"org.graalvm.compiler.truffle.compiler.PartialEvaluator.fastPartialEvaluation",
"org.graalvm.compiler.truffle.compiler.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings",
"org.graalvm.compiler.truffle.compiler.PartialEvaluator.inliningGraphPE",
"org.graalvm.compiler.truffle.compiler.PerformanceInformationHandler.reportPerformanceWarnings",
"org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph",
"org.graalvm.compiler.core.test.VerifyDebugUsageTest$ValidDumpUsagePhase.run",
"org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidConcatDumpUsagePhase.run",

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -31,8 +31,8 @@ import java.lang.reflect.Modifier;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.Indent;
import org.graalvm.compiler.graph.Node;
@ -349,7 +349,7 @@ public class VerifyDebugUsageTest {
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
for (Method m : c.getDeclaredMethods()) {
if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -34,8 +34,8 @@ import java.lang.reflect.Modifier;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.java.GraphBuilderPhase;
import org.graalvm.compiler.nodeinfo.NodeInfo;
@ -273,7 +273,7 @@ public class VerifyVirtualizableTest {
graphBuilderSuite.appendPhase(new GraphBuilderPhase(config));
HighTierContext context = new HighTierContext(providers, graphBuilderSuite, OptimisticOptimizations.NONE);
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
for (Method m : c.getDeclaredMethods()) {
if (!Modifier.isNative(m.getModifiers()) && !Modifier.isAbstract(m.getModifiers())) {
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);

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

@ -26,14 +26,9 @@ package org.graalvm.compiler.core.test.ea;
import java.lang.ref.SoftReference;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.test.TypeSystemTest;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.ReturnNode;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
import org.graalvm.compiler.nodes.extended.BoxNode;
@ -45,6 +40,9 @@ import org.graalvm.compiler.nodes.java.NewInstanceNode;
import org.graalvm.compiler.nodes.java.StoreFieldNode;
import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
/**
* The PartialEscapeAnalysisPhase is expected to remove all allocations and return the correct
@ -282,9 +280,7 @@ public class PartialEscapeAnalysisTest extends EATestBase {
@SafeVarargs
protected final void testPartialEscapeAnalysis(String snippet, double expectedProbability, int expectedCount, Class<? extends Node>... invalidNodeClasses) {
prepareGraph(snippet, false);
for (AbstractMergeNode merge : graph.getNodes(AbstractMergeNode.TYPE)) {
merge.setStateAfter(null);
}
graph.clearAllStateAfter();
new DeadCodeEliminationPhase().apply(graph);
createCanonicalizerPhase().apply(graph, context);
try {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, 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
@ -34,8 +34,8 @@ import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.GraalCompiler;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.DebugDumpScope;
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
import org.graalvm.compiler.lir.phases.LIRSuites;
@ -88,7 +88,7 @@ public class InvokeGraal {
/* Create a unique compilation identifier, visible in IGV. */
CompilationIdentifier compilationId = backend.getCompilationIdentifier(method);
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
try (DebugContext.Scope s = debug.scope("compileAndInstallMethod", new DebugDumpScope(String.valueOf(compilationId), true))) {
/*

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ import java.util.Map;
import java.util.Set;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeMap;
@ -246,7 +246,7 @@ public class StaticAnalysis {
*/
OptionValues options = getInitialOptions();
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
StructuredGraph graph = new StructuredGraph.Builder(options, debug).method(method).build();
/*
* Support for graph dumping, IGV uses this information to show the method name of a

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -30,7 +30,6 @@ import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureA
import static org.graalvm.compiler.core.GraalCompilerOptions.ExitVMOnException;
import static org.graalvm.compiler.core.GraalCompilerOptions.MaxCompilationProblemsPerAction;
import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition;
import static org.graalvm.compiler.debug.DebugContext.VERBOSE_LEVEL;
import static org.graalvm.compiler.debug.DebugOptions.Dump;
import static org.graalvm.compiler.debug.DebugOptions.DumpPath;
import static org.graalvm.compiler.debug.DebugOptions.MethodFilter;
@ -43,6 +42,7 @@ import java.io.PrintStream;
import java.util.Map;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.debug.DiagnosticsOutputDirectory;
import org.graalvm.compiler.debug.PathUtilities;
import org.graalvm.compiler.debug.TTY;
@ -276,7 +276,7 @@ public abstract class CompilationWrapper<T> {
}
OptionValues retryOptions = new OptionValues(initialOptions,
Dump, ":" + VERBOSE_LEVEL,
Dump, ":" + DebugOptions.DiagnoseDumpLevel.getValue(initialOptions),
MethodFilter, null,
DumpPath, dumpPath.getPath(),
TrackNodeSourcePosition, true);

@ -31,6 +31,7 @@ import org.graalvm.compiler.core.common.util.CompilationAlarm;
import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
import org.graalvm.compiler.debug.MethodFilter;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
@ -208,9 +209,11 @@ public class GraalCompiler {
try (DebugContext.Scope s = debug.scope("FrontEnd"); DebugCloseable a = FrontEnd.start(debug)) {
HighTierContext highTierContext = new HighTierContext(providers, graphBuilderSuite, optimisticOpts);
if (graph.start().next() == null) {
graphBuilderSuite.apply(graph, highTierContext);
new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing");
try (CompilerPhaseScope cps = debug.enterCompilerPhase("Parsing")) {
graphBuilderSuite.apply(graph, highTierContext);
new DeadCodeEliminationPhase(DeadCodeEliminationPhase.Optionality.Optional).apply(graph);
debug.dump(DebugContext.BASIC_LEVEL, graph, "After parsing");
}
} else {
debug.dump(DebugContext.INFO_LEVEL, graph, "initial state");
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@ -49,16 +49,16 @@ public class GraalServiceThread extends Thread {
/**
* Substituted by {@code com.oracle.svm.graal.hotspot.libgraal.
* Target_org_graalvm_compiler_truffle_common_TruffleCompilerRuntimeInstance} to attach to the
* peer runtime if required.
* Target_org_graalvm_compiler_core_GraalServiceThread} to attach to the peer runtime if
* required.
*/
private void afterRun() {
}
/**
* Substituted by {@code com.oracle.svm.graal.hotspot.libgraal.
* Target_org_graalvm_compiler_truffle_common_TruffleCompilerRuntimeInstance} to attach to the
* peer runtime if required.
* Target_org_graalvm_compiler_core_GraalServiceThread} to attach to the peer runtime if
* required.
*/
private void beforeRun() {
}

@ -1,6 +1,11 @@
Specifies the action to take when compilation fails.
The accepted values are:
Silent - Print nothing to the console.
Print - Print a stack trace to the console.
Diagnose - Retry the compilation with extra diagnostics.
ExitVM - Same as Diagnose except that the VM process exits after retrying.
Silent - Print nothing to the console.
Print - Print a stack trace to the console.
Diagnose* - Retry the compilation with extra diagnostics.
ExitVM - Same as Diagnose except that the VM process exits after retrying.
* If "Diagnose" is set compilation will be retried with extra diagnostics enabled including dumping (see file:doc-files/DumpHelp.txt).
In such a scenario DiagnoseDumpLevel can be used to specify the dump level (DebugContext dump levels) accordingly.

@ -30,6 +30,7 @@ import java.util.Queue;
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.Equivalence;
import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
@ -66,10 +67,12 @@ import jdk.vm.ci.meta.Value;
public class DebugInfoBuilder {
protected final NodeValueMap nodeValueMap;
protected final MetaAccessExtensionProvider metaAccessExtensionProvider;
protected final DebugContext debug;
public DebugInfoBuilder(NodeValueMap nodeValueMap, DebugContext debug) {
public DebugInfoBuilder(NodeValueMap nodeValueMap, MetaAccessExtensionProvider metaAccessExtensionProvider, DebugContext debug) {
this.nodeValueMap = nodeValueMap;
this.metaAccessExtensionProvider = metaAccessExtensionProvider;
this.debug = debug;
}
@ -129,7 +132,7 @@ public class DebugInfoBuilder {
for (int i = 0; i < entryCount; i++) {
ValueNode value = currentField.values().get(i);
if (value == null) {
JavaKind entryKind = vobjNode.entryKind(i);
JavaKind entryKind = vobjNode.entryKind(metaAccessExtensionProvider, i);
values[pos] = JavaConstant.defaultForKind(entryKind.getStackKind());
slotKinds[pos] = entryKind.getStackKind();
pos++;
@ -140,9 +143,9 @@ public class DebugInfoBuilder {
} else {
assert value.getStackKind() == JavaKind.Illegal;
ValueNode previousValue = currentField.values().get(i - 1);
assert (previousValue != null && (previousValue.getStackKind().needsTwoSlots()) || vobjNode.isVirtualByteArray()) : vobjNode + " " + i +
assert (previousValue != null && (previousValue.getStackKind().needsTwoSlots()) || vobjNode.isVirtualByteArray(metaAccessExtensionProvider)) : vobjNode + " " + i +
" " + previousValue + " " + currentField.values().snapshot();
if (vobjNode.isVirtualByteArray()) {
if (vobjNode.isVirtualByteArray(metaAccessExtensionProvider)) {
/*
* Let Illegals pass through to help knowing the number of bytes to
* write. For example, writing a short to index 2 of a byte array of
@ -158,7 +161,7 @@ public class DebugInfoBuilder {
pos++;
} else if (previousValue == null || !previousValue.getStackKind().needsTwoSlots()) {
// Don't allow the IllegalConstant to leak into the debug info
JavaKind entryKind = vobjNode.entryKind(i);
JavaKind entryKind = vobjNode.entryKind(metaAccessExtensionProvider, i);
values[pos] = JavaConstant.defaultForKind(entryKind.getStackKind());
slotKinds[pos] = entryKind.getStackKind();
pos++;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -39,6 +39,7 @@ import org.graalvm.compiler.core.target.Backend;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.lir.LIR;
@ -200,7 +201,7 @@ public class LIRCompilerBackend {
ResolvedJavaMethod installedCodeOwner,
CompilationResultBuilderFactory factory) {
DebugContext debug = lirGenRes.getLIR().getDebug();
try (DebugCloseable a = EmitCode.start(debug)) {
try (DebugCloseable a = EmitCode.start(debug); CompilerPhaseScope cps = debug.enterCompilerPhase("Emit code");) {
LIRGenerationProvider lirBackend = (LIRGenerationProvider) backend;
FrameMap frameMap = lirGenRes.getFrameMap();

@ -43,6 +43,7 @@ import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.core.common.cfg.BlockMap;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.match.ComplexMatchValue;
import org.graalvm.compiler.core.match.MatchPattern;
@ -99,6 +100,8 @@ import org.graalvm.compiler.nodes.calc.IntegerTestNode;
import org.graalvm.compiler.nodes.calc.IsNullNode;
import org.graalvm.compiler.nodes.cfg.Block;
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
import org.graalvm.compiler.nodes.extended.ForeignCall;
import org.graalvm.compiler.nodes.extended.ForeignCallWithExceptionNode;
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
import org.graalvm.compiler.nodes.extended.SwitchNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
@ -155,7 +158,7 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
}
protected DebugInfoBuilder createDebugInfoBuilder(StructuredGraph graph, NodeValueMap nodeValueMap) {
return new DebugInfoBuilder(nodeValueMap, graph.getDebug());
return new DebugInfoBuilder(nodeValueMap, gen.getProviders().getMetaAccessExtensionProvider(), graph.getDebug());
}
/**
@ -620,6 +623,28 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
}
}
@Override
public void emitForeignCall(ForeignCall x) {
ForeignCallLinkage linkage = gen.getForeignCalls().lookupForeignCall(x.getDescriptor());
LabelRef exceptionEdge = null;
if (x instanceof ForeignCallWithExceptionNode) {
exceptionEdge = getLIRBlock(((ForeignCallWithExceptionNode) x).exceptionEdge());
}
LIRFrameState callState = stateWithExceptionEdge(x, exceptionEdge);
Value[] args = x.operands(this);
Value result = gen.emitForeignCall(linkage, callState, args);
if (result != null) {
setResult(x.asNode(), result);
}
if (x instanceof ForeignCallWithExceptionNode) {
gen.emitJump(getLIRBlock(((ForeignCallWithExceptionNode) x).next()));
}
}
protected abstract void emitDirectCall(DirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
protected abstract void emitIndirectCall(IndirectCallTargetNode callTarget, Value result, Value[] parameters, Value[] temps, LIRFrameState callState);
@ -735,7 +760,7 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
if (gen.needOnlyOopMaps()) {
return new LIRFrameState(null, null, null);
}
assert state != null : deopt;
assert state != null : "Deopt node=" + deopt + " needs a state ";
return getDebugInfoBuilder().build(deopt, state, exceptionEdge);
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,7 +24,6 @@
package org.graalvm.compiler.core.phases;
import static org.graalvm.compiler.core.common.GraalOptions.LateMembars;
import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
import org.graalvm.compiler.core.common.GraalOptions;
@ -37,7 +36,6 @@ import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.graalvm.compiler.phases.common.ExpandLogicPhase;
import org.graalvm.compiler.phases.common.FixReadsPhase;
import org.graalvm.compiler.phases.common.InsertMembarsPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.common.ProfileCompiledMethodsPhase;
import org.graalvm.compiler.phases.common.PropagateDeoptimizeProbabilityPhase;
@ -80,9 +78,6 @@ public class LowTier extends BaseTier<LowTierContext> {
appendPhase(new PropagateDeoptimizeProbabilityPhase());
if (LateMembars.getValue(options)) {
appendPhase(new InsertMembarsPhase());
}
appendPhase(new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST_OUT_OF_LOOPS));
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, 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
@ -30,7 +30,7 @@ import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.common.CompilationIdentifier;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallSignature;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.core.gen.LIRCompilerBackend;
import org.graalvm.compiler.debug.DebugContext;
@ -63,8 +63,8 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
private final Providers providers;
private final ArrayList<CodeInstallationTaskFactory> codeInstallationTaskFactories;
public static final ForeignCallDescriptor ARITHMETIC_FREM = new ForeignCallDescriptor("arithmeticFrem", float.class, float.class, float.class);
public static final ForeignCallDescriptor ARITHMETIC_DREM = new ForeignCallDescriptor("arithmeticDrem", double.class, double.class, double.class);
public static final ForeignCallSignature ARITHMETIC_FREM = new ForeignCallSignature("arithmeticFrem", float.class, float.class, float.class);
public static final ForeignCallSignature ARITHMETIC_DREM = new ForeignCallSignature("arithmeticDrem", double.class, double.class, double.class);
protected Backend(Providers providers) {
this.providers = providers;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,7 +33,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import java.util.stream.Collectors;
@ -43,6 +42,7 @@ import org.graalvm.compiler.debug.Assertions;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.DebugContext.Scope;
import org.graalvm.compiler.debug.DebugDumpHandler;
import org.graalvm.compiler.debug.DebugHandler;
@ -80,7 +80,7 @@ public class DebugContextTest {
};
DebugContext openDebugContext(OptionValues options) {
return DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(logOutput), Collections.singletonList(handlers));
return new Builder(options, handlers).logStream(new PrintStream(logOutput)).build();
}
}
@ -203,7 +203,7 @@ public class DebugContextTest {
map.put(DebugOptions.DumpOnError, true);
OptionValues options = new OptionValues(map);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).globalMetrics(NO_GLOBAL_METRIC_VALUES).description(NO_DESCRIPTION).logStream(new PrintStream(baos)).build();
Exception e = new Exception("testEnabledSandbox");
String scopeName = "";
try {
@ -233,7 +233,7 @@ public class DebugContextTest {
map.put(DebugOptions.DumpOnError, true);
OptionValues options = new OptionValues(map);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).globalMetrics(NO_GLOBAL_METRIC_VALUES).description(NO_DESCRIPTION).logStream(new PrintStream(baos)).build();
Exception e = new Exception("testDisabledSandbox");
try {
// Test a disabled sandbox scope
@ -263,7 +263,7 @@ public class DebugContextTest {
// Configure with an option that enables counters
map.put(DebugOptions.Counters, "");
OptionValues options = new OptionValues(map);
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
CounterKey counter = DebugContext.counter("DebugContextTestCounter");
AssertionError[] result = {null};
Thread thread = new Thread() {
@ -291,7 +291,7 @@ public class DebugContextTest {
map.put(DebugOptions.DumpOnError, true);
OptionValues options = new OptionValues(map);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, new PrintStream(baos), DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).globalMetrics(NO_GLOBAL_METRIC_VALUES).description(NO_DESCRIPTION).logStream(new PrintStream(baos)).build();
Exception e = new Exception();
try {
try (DebugCloseable disabled = debug.disableIntercept(); Scope s1 = debug.scope("ScopeWithDisabledIntercept")) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,15 +24,13 @@
package org.graalvm.compiler.debug.test;
import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM;
import static org.graalvm.compiler.debug.DebugContext.NO_CONFIG_CUSTOMIZERS;
import static org.graalvm.compiler.debug.DebugContext.NO_DESCRIPTION;
import static org.graalvm.compiler.debug.DebugContext.NO_GLOBAL_METRIC_VALUES;
import static org.junit.Assert.assertEquals;
import jdk.internal.vm.compiler.collections.EconomicMap;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.options.OptionKey;
@ -88,7 +86,7 @@ public class TimerKeyTest {
EconomicMap<OptionKey<?>, Object> map = EconomicMap.create();
map.put(DebugOptions.Time, "");
OptionValues options = new OptionValues(map);
DebugContext debug = DebugContext.create(options, NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, NO_CONFIG_CUSTOMIZERS);
DebugContext debug = new Builder(options, NO_CONFIG_CUSTOMIZERS).build();
TimerKey timerC = DebugContext.timer("TimerC");
try (DebugCloseable c1 = timerC.start(debug)) {

@ -0,0 +1,57 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.debug;
import org.graalvm.compiler.debug.DebugContext.CompilerPhaseScope;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* Implemented by clients interested in when the compiler starts/ends a {@linkplain #enterPhase
* phase} or {@linkplain #notifyInlining considers inlining} a method.
*/
public interface CompilationListener {
/**
* Notifies this listener that the compiler is starting a compiler phase.
*
* @param name the name of the phase
* @return an object whose {@link CompilerPhaseScope#close()} method will be called when the
* phase completes
*/
CompilerPhaseScope enterPhase(CharSequence name, int nesting);
/**
* Notifies this listener when the compiler considers inlining {@code callee} into
* {@code caller}.
*
* @param caller caller method
* @param callee callee method considered for inlining into {@code caller}
* @param succeeded true if {@code callee} was inlined into {@code caller}
* @param message extra information about inlining decision
* @param bci byte code index of call site
*/
void notifyInlining(ResolvedJavaMethod caller, ResolvedJavaMethod callee, boolean succeeded, CharSequence message, int bci);
}

@ -59,6 +59,7 @@ import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.function.Supplier;
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.EconomicSet;
@ -68,7 +69,9 @@ import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.serviceprovider.GraalServices;
import org.graalvm.graphio.GraphOutput;
import jdk.vm.ci.common.NativeImageReinitialize;
import jdk.vm.ci.meta.JavaMethod;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* A facility for logging and dumping as well as a container for values associated with
@ -86,8 +89,6 @@ public final class DebugContext implements AutoCloseable {
public static final GlobalMetrics NO_GLOBAL_METRIC_VALUES = null;
public static final Iterable<DebugHandlersFactory> NO_CONFIG_CUSTOMIZERS = Collections.emptyList();
public static final PrintStream DEFAULT_LOG_STREAM = TTY.out;
/**
* Contains the immutable parts of a debug context. This separation allows the immutable parts
* to be shared and reduces the overhead of initialization since most immutable fields are
@ -114,6 +115,10 @@ public final class DebugContext implements AutoCloseable {
*/
private long[] metricValues;
public static PrintStream getDefaultLogStream() {
return TTY.out;
}
/**
* Determines if dynamic scopes are enabled.
*/
@ -128,6 +133,7 @@ public final class DebugContext implements AutoCloseable {
if (sharedChannel == null) {
sharedChannel = new IgvDumpChannel(() -> getDumpPath(".bgv", false), immutable.options);
}
builder.attr(GraphOutput.ATTR_VM_ID, GraalServices.getExecutionID());
final GraphOutput<G, M> output = builder.build(sharedChannel);
parentOutput = output;
return output;
@ -315,7 +321,7 @@ public final class DebugContext implements AutoCloseable {
/**
* Singleton used to represent a disabled debug context.
*/
private static final DebugContext DISABLED = new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, new Immutable(), NO_CONFIG_CUSTOMIZERS);
private static final DebugContext DISABLED = new DebugContext(NO_DESCRIPTION, null, NO_GLOBAL_METRIC_VALUES, getDefaultLogStream(), new Immutable(), NO_CONFIG_CUSTOMIZERS);
/**
* Create a DebugContext with debugging disabled.
@ -324,7 +330,7 @@ public final class DebugContext implements AutoCloseable {
if (options == null || options.getMap().isEmpty()) {
return DISABLED;
}
return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), NO_CONFIG_CUSTOMIZERS);
return new DebugContext(NO_DESCRIPTION, null, NO_GLOBAL_METRIC_VALUES, getDefaultLogStream(), Immutable.create(options), NO_CONFIG_CUSTOMIZERS);
}
/**
@ -377,6 +383,8 @@ public final class DebugContext implements AutoCloseable {
private final Description description;
private final CompilationListener compilationListener;
/**
* Gets a description of the computation associated with this debug context.
*
@ -386,6 +394,89 @@ public final class DebugContext implements AutoCloseable {
return description;
}
/**
* Determines if {@link #enterCompilerPhase} and {@link #notifyInlining} do anything.
*
* @return {@code true} if there is a listener for compiler phase and inlining events attached
* to this object, {@code false} otherwise
*/
public boolean hasCompilationListener() {
return compilationListener != null;
}
private int compilerPhaseNesting = 0;
/**
* Scope for a compiler phase event.
*/
public interface CompilerPhaseScope extends AutoCloseable {
/**
* Notifies the listener that the phase has ended.
*/
@Override
void close();
}
/**
* Notifies this object that the compiler is entering a phase.
*
* It is recommended to use this method in a try-with-resource statement.
*
* @param phaseName name of the phase being entered
* @return {@code null} if {@link #hasCompilationListener()} returns {@code false} otherwise an
* object whose {@link CompilerPhaseScope#close()} method must be called when the phase
* ends
*/
public CompilerPhaseScope enterCompilerPhase(CharSequence phaseName) {
if (compilationListener != null) {
return enterCompilerPhase(() -> phaseName);
}
return null;
}
/**
* Notifies this object that the compiler is entering a phase.
*
* It is recommended to use this method in a try-with-resource statement.
*
* @param phaseName name of the phase being entered
* @return {@code null} if {@link #hasCompilationListener()} returns {@code false} otherwise an
* object whose {@link CompilerPhaseScope#close()} method must be called when the phase
* ends
*/
public CompilerPhaseScope enterCompilerPhase(Supplier<CharSequence> phaseName) {
CompilationListener l = compilationListener;
if (l != null) {
CompilerPhaseScope scope = l.enterPhase(phaseName.get(), compilerPhaseNesting++);
return new CompilerPhaseScope() {
@Override
public void close() {
--compilerPhaseNesting;
scope.close();
}
};
}
return null;
}
/**
* Notifies this object when the compiler considers inlining {@code callee} into {@code caller}.
* A call to this method should be guarded with {@link #hasCompilationListener()} if
* {@code message} is not a string literal or pre-computed value
*
* @param caller caller method
* @param callee callee method considered for inlining into {@code caller}
* @param succeeded true if {@code callee} was inlined into {@code caller}
* @param message extra information about inlining decision
* @param bci byte code index of call site
*/
public void notifyInlining(ResolvedJavaMethod caller, ResolvedJavaMethod callee, boolean succeeded, CharSequence message, int bci) {
if (compilationListener != null) {
compilationListener.notifyInlining(caller, callee, succeeded, message, bci);
}
}
/**
* Gets the global metrics associated with this debug context.
*
@ -396,43 +487,91 @@ public final class DebugContext implements AutoCloseable {
}
/**
* Creates a {@link DebugContext} based on a given set of option values and {@code factory}.
* Object used to create a {@link DebugContext}.
*/
public static DebugContext create(OptionValues options, DebugHandlersFactory factory) {
return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), Collections.singletonList(factory));
public static class Builder {
private final OptionValues options;
private Description description = NO_DESCRIPTION;
private CompilationListener compilationListener;
private GlobalMetrics globalMetrics = NO_GLOBAL_METRIC_VALUES;
private PrintStream logStream = getDefaultLogStream();
private final Iterable<DebugHandlersFactory> factories;
/**
* Builder for a {@link DebugContext} based on {@code options} and
* {@link DebugHandlersFactory#LOADER}.
*/
public Builder(OptionValues options) {
this.options = options;
this.factories = DebugHandlersFactory.LOADER;
}
/**
* Builder for a {@link DebugContext} based on {@code options} and {@code factories}. The
* {@link DebugHandlersFactory#LOADER} value can be used for the latter.
*/
public Builder(OptionValues options, Iterable<DebugHandlersFactory> factories) {
this.options = options;
this.factories = factories;
}
/**
* Builder for a {@link DebugContext} based {@code options} and {@code factory}. The latter
* can be null in which case {@link DebugContext#NO_CONFIG_CUSTOMIZERS} is used.
*/
public Builder(OptionValues options, DebugHandlersFactory factory) {
this.options = options;
this.factories = factory == null ? NO_CONFIG_CUSTOMIZERS : Collections.singletonList(factory);
}
/**
* Sets the description for the debug context. The default is for a context to have no
* description.
*/
public Builder description(Description desc) {
this.description = desc;
return this;
}
/**
* Sets the compilation listener for the debug context. The default is for a context to have
* no compilation listener.
*/
public Builder compilationListener(CompilationListener listener) {
this.compilationListener = listener;
return this;
}
public Builder globalMetrics(GlobalMetrics metrics) {
this.globalMetrics = metrics;
return this;
}
public Builder logStream(PrintStream stream) {
this.logStream = stream;
return this;
}
public DebugContext build() {
return new DebugContext(description,
compilationListener,
globalMetrics,
logStream,
Immutable.create(options),
factories);
}
}
/**
* Creates a {@link DebugContext} based on a given set of option values and {@code factories}.
* The {@link DebugHandlersFactory#LOADER} can be used for the latter.
*/
public static DebugContext create(OptionValues options, Iterable<DebugHandlersFactory> factories) {
return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), factories);
}
public static DebugContext create(OptionValues options, PrintStream logStream, DebugHandlersFactory factory) {
return new DebugContext(NO_DESCRIPTION, NO_GLOBAL_METRIC_VALUES, logStream, Immutable.create(options), Collections.singletonList(factory));
}
/**
* Creates a {@link DebugContext} based on a given set of option values and {@code factories}.
* The {@link DebugHandlersFactory#LOADER} can be used for the latter.
*/
public static DebugContext create(OptionValues options, Description description, Iterable<DebugHandlersFactory> factories) {
return new DebugContext(description, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, Immutable.create(options), factories);
}
/**
* Creates a {@link DebugContext}.
*/
public static DebugContext create(OptionValues options, Description description, GlobalMetrics globalMetrics, PrintStream logStream, Iterable<DebugHandlersFactory> factories) {
return new DebugContext(description, globalMetrics, logStream, Immutable.create(options), factories);
}
private DebugContext(Description description, GlobalMetrics globalMetrics, PrintStream logStream, Immutable immutable, Iterable<DebugHandlersFactory> factories) {
private DebugContext(Description description,
CompilationListener compilationListener,
GlobalMetrics globalMetrics,
PrintStream logStream,
Immutable immutable,
Iterable<DebugHandlersFactory> factories) {
this.immutable = immutable;
this.description = description;
this.globalMetrics = globalMetrics;
this.compilationListener = compilationListener;
if (immutable.scopesEnabled) {
OptionValues options = immutable.options;
List<DebugDumpHandler> dumpHandlers = new ArrayList<>();
@ -653,7 +792,11 @@ public final class DebugContext implements AutoCloseable {
}
}
private final Invariants invariants = Assertions.assertionsEnabled() ? new Invariants() : null;
/**
* Arbitrary threads cannot be in the image so null out {@code DebugContext.invariants} which
* holds onto a thread and is only used for assertions.
*/
@NativeImageReinitialize private final Invariants invariants = Assertions.assertionsEnabled() ? new Invariants() : null;
static StackTraceElement[] getStackTrace(Thread thread) {
return thread.getStackTrace();

@ -115,13 +115,16 @@ public class DebugOptions {
@Option(help = "file:doc-files/MetricsFileHelp.txt", type = OptionType.Debug)
public static final OptionKey<String> MetricsFile = new OptionKey<>(null);
@Option(help = "File to which aggregated metrics are dumped at shutdown. A CSV format is used if the file ends with .csv " +
"otherwise a more human readable format is used. If not specified, metrics are dumped to the console.", type = OptionType.Debug)
"otherwise a more human readable format is used. If not specified, metrics are dumped to the console.", type = OptionType.Debug)
public static final OptionKey<String> AggregatedMetricsFile = new OptionKey<>(null);
@Option(help = "Enable debug output for stub code generation and snippet preparation.", type = OptionType.Debug)
public static final OptionKey<Boolean> DebugStubsAndSnippets = new OptionKey<>(false);
@Option(help = "Send compiler IR to dump handlers on error.", type = OptionType.Debug)
public static final OptionKey<Boolean> DumpOnError = new OptionKey<>(false);
@Option(help = "Specify the DumpLevel if CompilationFailureAction#Diagnose is used." +
"See CompilationFailureAction for details. file:doc-files/CompilationFailureActionHelp.txt", type = OptionType.Debug)
public static final OptionKey<Integer> DiagnoseDumpLevel = new OptionKey<>(DebugContext.VERBOSE_LEVEL);
@Option(help = "Disable intercepting exceptions in debug scopes.", type = OptionType.Debug)
public static final OptionKey<Boolean> DisableIntercept = new OptionKey<>(false);
@Option(help = "Intercept also bailout exceptions", type = OptionType.Debug)
@ -137,7 +140,9 @@ public class DebugOptions {
@Option(help = "Enable dumping to the C1Visualizer. Enabling this option implies PrintBackendCFG.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintCFG = new OptionKey<>(false);
@Option(help = "Enable dumping LIR, register allocation and code generation info to the C1Visualizer.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintBackendCFG = new OptionKey<>(true);
public static final OptionKey<Boolean> PrintBackendCFG = new OptionKey<>(false);
@Option(help = "Enable dumping CFG built during initial BciBlockMapping", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintBlockMapping = new OptionKey<>(false);
@Option(help = "file:doc-files/PrintGraphHelp.txt", type = OptionType.Debug)
public static final EnumOptionKey<PrintGraphTarget> PrintGraph = new EnumOptionKey<>(PrintGraphTarget.File);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -42,6 +42,7 @@ import java.util.zip.ZipOutputStream;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.serviceprovider.GraalServices;
import org.graalvm.compiler.serviceprovider.IsolateUtil;
/**
* Manages a directory into which diagnostics such crash reports and dumps should be written. The
@ -107,7 +108,7 @@ public class DiagnosticsOutputDirectory {
// directory specified by the DumpPath option.
baseDir = Paths.get(".");
}
return baseDir.resolve("graal_diagnostics_" + GraalServices.getExecutionID()).toAbsolutePath().toString();
return baseDir.resolve("graal_diagnostics_" + GraalServices.getExecutionID() + '@' + IsolateUtil.getIsolateID()).toAbsolutePath().toString();
}
/**

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package org.graalvm.compiler.debug;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
@ -35,6 +36,7 @@ import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.MapCursor;
import jdk.internal.vm.compiler.collections.Pair;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.serviceprovider.IsolateUtil;
/**
* Metric values that can be {@linkplain #add(DebugContext) updated} by multiple threads.
@ -75,10 +77,30 @@ public class GlobalMetrics {
return res;
}
private static PrintStream openPrintStream(String metricsFile) throws IOException {
if (metricsFile == null) {
return DebugContext.getDefaultLogStream();
} else {
long isolateID = IsolateUtil.getIsolateID();
Path path;
if (isolateID != 0L) {
int lastDot = metricsFile.lastIndexOf('.');
if (lastDot != -1) {
path = Paths.get(metricsFile.substring(0, lastDot) + '@' + isolateID + metricsFile.substring(lastDot));
} else {
path = Paths.get(metricsFile + isolateID);
}
} else {
path = Paths.get(metricsFile);
}
return new PrintStream(Files.newOutputStream(path));
}
}
/**
* Prints the values in the object to the file specified by
* {@link DebugOptions#AggregatedMetricsFile} if present otherwise to
* {@link DebugContext#DEFAULT_LOG_STREAM}.
* {@link DebugContext#getDefaultLogStream()}.
*/
public void print(OptionValues options) {
long[] vals = values;
@ -88,10 +110,11 @@ public class GlobalMetrics {
boolean csv = metricsFile != null && (metricsFile.endsWith(".csv") || metricsFile.endsWith(".CSV"));
PrintStream p = null;
try {
p = metricsFile == null ? DebugContext.DEFAULT_LOG_STREAM : new PrintStream(Files.newOutputStream(Paths.get(metricsFile)));
p = openPrintStream(metricsFile);
String isolateID = IsolateUtil.getIsolateID(false);
if (!csv) {
if (!map.isEmpty()) {
p.println("++ Aggregated Metrics ++");
p.printf("++ Aggregated Metrics %s ++%n", isolateID);
}
}
String csvFormat = CSVUtil.buildFormatString("%s", "%s", "%s");
@ -107,7 +130,7 @@ public class GlobalMetrics {
}
if (!csv) {
if (!map.isEmpty()) {
p.println("-- Aggregated Metrics --");
p.printf("-- Aggregated Metrics %s --%n", isolateID);
}
}
} catch (IOException e) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,8 +25,8 @@
package org.graalvm.compiler.graph.test;
import org.graalvm.compiler.api.test.Graal;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugContext.Builder;
import org.graalvm.compiler.options.OptionValues;
import org.junit.After;
@ -46,7 +46,7 @@ public abstract class GraphTest {
}
throw new AssertionError("At most one " + DebugContext.class.getName() + " object should be created per test");
}
DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER);
DebugContext debug = new Builder(options).build();
cachedDebug.set(debug);
return debug;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, 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
@ -44,6 +44,7 @@ import org.graalvm.graphio.GraphTypes;
import static org.junit.Assert.assertSame;
import org.junit.Test;
import java.lang.reflect.Field;
import static org.junit.Assert.assertEquals;
public final class GraphOutputTest {
@ -131,6 +132,96 @@ public final class GraphOutputTest {
assertSame(CustomEnum.class, clazz);
}
@Test
@SuppressWarnings({"static-method", "unchecked"})
public void testBuilderPromotesVersion() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (WritableByteChannel channel = Channels.newChannel(out)) {
GraphOutput.Builder<MockGraph, Void, ?> builder = GraphOutput.newBuilder(new MockGraphStructure()).attr("test", "failed");
try (GraphOutput<MockGraph, ?> graphOutput = builder.build(channel)) {
graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
} catch (IllegalStateException ise) {
// expected exception
}
}
byte[] bytes = out.toByteArray();
// there's B-I-G-V, major, minor
assertEquals("Major version 7 must be auto-selected", 7, bytes[4]);
}
@Test
@SuppressWarnings({"static-method", "unchecked"})
public void testTooOldVersionFails() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (WritableByteChannel channel = Channels.newChannel(out)) {
GraphOutput.Builder<MockGraph, Void, ?> builder = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(6, 1);
try {
builder.attr("test", "failed");
fail("Should have failed, attr() requires version 7.0");
} catch (IllegalStateException ex) {
// expected
}
try (GraphOutput<MockGraph, ?> graphOutput = builder.build(channel)) {
graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
} catch (IllegalStateException ise) {
// expected exception
}
}
}
@Test
@SuppressWarnings({"static-method", "unchecked"})
public void testVersionDowngradeFails() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (WritableByteChannel channel = Channels.newChannel(out)) {
GraphOutput.Builder<MockGraph, Void, ?> builder = GraphOutput.newBuilder(new MockGraphStructure());
builder.attr("test", "failed");
try {
builder.protocolVersion(6, 0);
fail("Should fail, cannot downgrade from required version.");
} catch (IllegalArgumentException e) {
// expected
}
try (GraphOutput<MockGraph, ?> graphOutput = builder.build(channel)) {
graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
} catch (IllegalStateException ise) {
// expected exception
}
}
}
@Test
@SuppressWarnings({"static-method", "unchecked"})
public void testManualAncientVersion() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (WritableByteChannel channel = Channels.newChannel(out)) {
GraphOutput.Builder<MockGraph, Void, ?> builder = GraphOutput.newBuilder(new MockGraphStructure()).protocolVersion(3, 0);
try (GraphOutput<MockGraph, ?> graphOutput = builder.build(channel)) {
graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
}
}
byte[] bytes = out.toByteArray();
// there's B-I-G-V, major, minor
assertEquals("Protocol version 3 was requested", 3, bytes[4]);
}
@Test
@SuppressWarnings({"static-method", "unchecked"})
public void testManualVersionUpgradeOK() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (WritableByteChannel channel = Channels.newChannel(out)) {
GraphOutput.Builder<MockGraph, Void, ?> builder = GraphOutput.newBuilder(new MockGraphStructure());
builder.attr("some", "thing");
builder.protocolVersion(7, 0);
try (GraphOutput<MockGraph, ?> graphOutput = builder.build(channel)) {
graphOutput.print(new MockGraph(), Collections.emptyMap(), 0, "Mock Graph");
}
}
byte[] bytes = out.toByteArray();
// there's B-I-G-V, major, minor
assertEquals("Protocol version 7 was requested", 7, bytes[4]);
}
private static ByteBuffer generateData(int size) {
ByteBuffer buffer = ByteBuffer.allocate(size);
for (int i = 0; i < size; i++) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020, 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
@ -56,8 +56,8 @@ public final class NodeEncodingTest {
}
@Test
public void defaultVersionTheNodeIsntDumpedWithItsID() throws Exception {
runTheNodeIsntDumpedWithItsID(false);
public void defaultVersionTheNodeIsDumpedWithItsID() throws Exception {
runTheNodeIsTreatedPoolEntry(false);
}
private void runTheNodeIsntDumpedWithItsID(boolean explicitVersion) throws Exception {

@ -427,12 +427,30 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
}
/**
* Checks whether this node has exactly one usgae.
* Checks whether this node has exactly one usage.
*/
public final boolean hasExactlyOneUsage() {
return hasUsages() && !hasMoreThanOneUsage();
}
/**
* Checks whether this node has only usages of that type.
*
* @param type the type of usages to look for
*/
public final boolean hasOnlyUsagesOfType(InputType type) {
for (Node usage : usages()) {
for (Position pos : usage.inputPositions()) {
if (pos.get(usage) == this) {
if (pos.getInputType() != type) {
return false;
}
}
}
}
return true;
}
/**
* Adds a given node to this node's {@linkplain #usages() usages}.
*
@ -858,7 +876,7 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
}
}
public void replaceAtUsages(InputType type, Node other) {
public void replaceAtUsages(Node other, InputType type) {
checkReplaceWith(other);
int i = 0;
int usageCount = this.getUsageCount();
@ -882,6 +900,32 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
}
}
public void replaceAtUsages(Node other, InputType... inputTypes) {
checkReplaceWith(other);
int i = 0;
int usageCount = this.getUsageCount();
if (usageCount == 0) {
return;
}
usages: while (i < usageCount) {
Node usage = this.getUsageAt(i);
for (Position pos : usage.inputPositions()) {
for (InputType type : inputTypes) {
if (pos.getInputType() == type && pos.get(usage) == this) {
replaceAtUsagePos(other, usage, pos);
this.movUsageFromEndTo(i);
usageCount--;
continue usages;
}
}
}
i++;
}
if (hasNoUsages()) {
maybeNotifyZeroUsages(this);
}
}
private void maybeNotifyInputChanged(Node node) {
if (graph != null) {
assert !graph.isFrozen();

@ -164,8 +164,8 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
private static AtomicInteger nextIterableId = new AtomicInteger();
private static AtomicInteger nextLeafId = new AtomicInteger();
private static final AtomicInteger nextIterableId = new AtomicInteger();
private static final AtomicInteger nextLeafId = new AtomicInteger();
private final InputEdges inputs;
private final SuccessorEdges successors;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, 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
@ -31,10 +31,20 @@ import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.graph.iterators.NodeIterable;
public abstract class NodeList<T extends Node> extends AbstractList<T> implements NodeIterable<T>, RandomAccess {
/**
* This constant limits the maximum number of entries in a node list. The reason for the
* limitations is the constraints of the code iterating over a node's inputs and successors. It
* uses a bit data structure where only 16 bits are available for the current index into the
* list. See the methods {@link NodeClass#getSuccessorIterable(Node)} and
* {@link NodeClass#getInputIterable(Node)}.
*/
private static final int MAX_ENTRIES = 65536;
protected static final Node[] EMPTY_NODE_ARRAY = new Node[0];
protected final Node self;
@ -50,6 +60,7 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
protected NodeList(Node self, int initialSize) {
this.self = self;
checkMaxSize(initialSize);
this.size = initialSize;
this.initialSize = initialSize;
this.nodes = new Node[initialSize];
@ -62,8 +73,9 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
this.nodes = EMPTY_NODE_ARRAY;
this.initialSize = 0;
} else {
checkMaxSize(elements.length);
this.size = elements.length;
this.initialSize = elements.length;
this.initialSize = this.size;
this.nodes = new Node[elements.length];
for (int i = 0; i < elements.length; i++) {
this.nodes[i] = elements[i];
@ -79,8 +91,10 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
this.nodes = EMPTY_NODE_ARRAY;
this.initialSize = 0;
} else {
this.size = elements.size();
this.initialSize = elements.size();
int newSize = elements.size();
checkMaxSize(newSize);
this.size = newSize;
this.initialSize = newSize;
this.nodes = new Node[elements.size()];
for (int i = 0; i < elements.size(); i++) {
this.nodes[i] = elements.get(i);
@ -89,6 +103,12 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
}
}
private static void checkMaxSize(int value) {
if (value > MAX_ENTRIES) {
throw new PermanentBailoutException("Number of elements in a node list too high: %d", value);
}
}
protected NodeList(Node self, Collection<? extends NodeInterface> elements) {
this.self = self;
if (elements == null || elements.isEmpty()) {
@ -96,8 +116,10 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
this.nodes = EMPTY_NODE_ARRAY;
this.initialSize = 0;
} else {
this.size = elements.size();
this.initialSize = elements.size();
int newSize = elements.size();
checkMaxSize(newSize);
this.size = newSize;
this.initialSize = newSize;
this.nodes = new Node[elements.size()];
int i = 0;
for (NodeInterface n : elements) {
@ -109,7 +131,7 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
}
/**
* Removes null values from the list.
* Removes {@code null} values from the list.
*/
public void trim() {
int newSize = 0;
@ -150,10 +172,15 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
modCount++;
}
/**
* Adds a new node to the list. The total number of nodes in the list must not exceed
* {@link #MAX_ENTRIES}, otherwise a {@link PermanentBailoutException} is thrown.
*/
@SuppressWarnings("unchecked")
@Override
public boolean add(Node node) {
assert node == null || !node.isDeleted() : node;
checkMaxSize(size + 1);
self.incModCount();
incModCount();
int length = nodes.length;
@ -169,6 +196,9 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
return true;
}
/**
* Get a node from the list given an {@code index}.
*/
@Override
@SuppressWarnings("unchecked")
public T get(int index) {
@ -185,6 +215,9 @@ public abstract class NodeList<T extends Node> extends AbstractList<T> implement
return get(size() - 1);
}
/**
* Set the node of the list at the given {@code index} to a new value.
*/
@Override
@SuppressWarnings("unchecked")
public T set(int index, Node node) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,14 +24,15 @@
package org.graalvm.compiler.graph.spi;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.options.OptionValues;
public interface CanonicalizerTool {
Assumptions getAssumptions();
@ -42,6 +43,8 @@ public interface CanonicalizerTool {
ConstantFieldProvider getConstantFieldProvider();
MetaAccessExtensionProvider getMetaAccessExtensionProvider();
boolean canonicalizeReads();
/**

@ -54,6 +54,7 @@ import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
@ -81,7 +82,6 @@ import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterConfig;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.code.site.Mark;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
@ -152,9 +152,8 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
private boolean hasInvalidatePlaceholder(CompilationResult compilationResult) {
byte[] targetCode = compilationResult.getTargetCode();
int verifiedEntryOffset = 0;
for (Mark mark : compilationResult.getMarks()) {
Object markId = mark.id;
if (markId instanceof Integer && (int) markId == config.MARKID_VERIFIED_ENTRY) {
for (CompilationResult.CodeMark mark : compilationResult.getMarks()) {
if (mark.id == HotSpotMarkId.VERIFIED_ENTRY || mark.id == HotSpotMarkId.OSR_ENTRY) {
// The nmethod verified entry is located at some pc offset.
verifiedEntryOffset = mark.pcOffset;
break;
@ -203,6 +202,9 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
}
}
}
if (HotSpotMarkId.FRAME_COMPLETE.isAvailable()) {
crb.recordMark(HotSpotMarkId.FRAME_COMPLETE);
}
if (ZapStackOnMethodEntry.getValue(crb.getOptions())) {
try (ScratchRegister sc = masm.getScratchRegister()) {
Register scratch = sc.getRegister();
@ -312,7 +314,7 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
private void emitCodePrefix(CompilationResultBuilder crb, ResolvedJavaMethod installedCodeOwner, AArch64MacroAssembler masm, RegisterConfig regConfig, Label verifiedStub) {
HotSpotProviders providers = getProviders();
if (installedCodeOwner != null && !isStatic(installedCodeOwner.getModifiers())) {
crb.recordMark(config.MARKID_UNVERIFIED_ENTRY);
crb.recordMark(HotSpotMarkId.UNVERIFIED_ENTRY);
CallingConvention cc = regConfig.getCallingConvention(HotSpotCallingConventionType.JavaCallee, null, new JavaType[]{providers.getMetaAccess().lookupJavaType(Object.class)}, this);
// See definition of IC_Klass in c1_LIRAssembler_aarch64.cpp
// equal to scratch(1) careful!
@ -325,7 +327,7 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
Register klass = r10;
if (config.useCompressedClassPointers) {
masm.ldr(32, klass, klassAddress);
AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding(), config);
AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding());
} else {
masm.ldr(64, klass, klassAddress);
}
@ -338,9 +340,8 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(IC_MISS_HANDLER));
}
masm.align(config.codeEntryAlignment);
crb.recordMark(config.MARKID_OSR_ENTRY);
masm.bind(verifiedStub);
crb.recordMark(config.MARKID_VERIFIED_ENTRY);
crb.recordMark(crb.compilationResult.getEntryBCI() != -1 ? HotSpotMarkId.OSR_ENTRY : HotSpotMarkId.VERIFIED_ENTRY);
if (GeneratePIC.getValue(crb.getOptions())) {
// Check for method state
@ -385,12 +386,12 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend implements LIRGene
HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
try (ScratchRegister sc = masm.getScratchRegister()) {
Register scratch = sc.getRegister();
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
crb.recordMark(HotSpotMarkId.EXCEPTION_HANDLER_ENTRY);
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
AArch64Call.directCall(crb, masm, linkage, helper, null);
}
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
crb.recordMark(HotSpotMarkId.DEOPT_HANDLER_ENTRY);
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPT_BLOB_UNPACK);
masm.adr(lr, 0); // Warning: the argument is an offset from the instruction!
AArch64Call.directJmp(crb, masm, linkage);

@ -36,6 +36,7 @@ import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.aarch64.AArch64AddressLoweringByUse;
import org.graalvm.compiler.core.aarch64.AArch64LIRKindTool;
import org.graalvm.compiler.core.aarch64.AArch64SuitesCreator;
import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotBackendFactory;
@ -44,11 +45,12 @@ import org.graalvm.compiler.hotspot.HotSpotReplacementsImpl;
import org.graalvm.compiler.hotspot.meta.AddressLoweringHotSpotSuitesProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotConstantFieldProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotPlatformConfigurationProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraalConstantFieldProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotGraphBuilderPlugins;
import org.graalvm.compiler.hotspot.meta.HotSpotHostForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotLoweringProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotMetaAccessExtensionProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotPlatformConfigurationProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.meta.HotSpotRegisters;
import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
@ -116,6 +118,7 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
HotSpotLoweringProvider lowerer;
HotSpotStampProvider stampProvider;
HotSpotPlatformConfigurationProvider platformConfigurationProvider;
HotSpotMetaAccessExtensionProvider metaAccessExtensionProvider;
HotSpotSnippetReflectionProvider snippetReflection;
HotSpotReplacementsImpl replacements;
HotSpotSuitesProvider suites;
@ -141,11 +144,15 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
try (InitTimer rt = timer("create platform configuration provider")) {
platformConfigurationProvider = createConfigInfoProvider(config, metaAccess);
}
try (InitTimer rt = timer("create MetaAccessExtensionProvider")) {
metaAccessExtensionProvider = createMetaAccessExtensionProvider();
}
try (InitTimer rt = timer("create Lowerer provider")) {
lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, platformConfigurationProvider, target);
lowerer = createLowerer(graalRuntime, metaAccess, foreignCalls, registers, constantReflection, platformConfigurationProvider, metaAccessExtensionProvider, target);
}
Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, platformConfigurationProvider);
Providers p = new Providers(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, null, stampProvider, platformConfigurationProvider,
metaAccessExtensionProvider);
try (InitTimer rt = timer("create SnippetReflection provider")) {
snippetReflection = createSnippetReflection(graalRuntime, constantReflection, wordTypes);
@ -165,7 +172,7 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
suites = createSuites(config, graalRuntime, compilerConfiguration, plugins, replacements);
}
providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
snippetReflection, wordTypes, plugins, platformConfigurationProvider);
snippetReflection, wordTypes, plugins, platformConfigurationProvider, metaAccessExtensionProvider);
replacements.setProviders(providers);
replacements.maybeInitializeEncoder(options);
}
@ -197,7 +204,7 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
options,
target);
AArch64GraphBuilderPlugins.register(plugins, replacements, false, //
/* registerMathPlugins */true, /* emitJDK9StringSubstitutions */true, config.useFMAIntrinsics);
/* registerForeignCallMath */true, /* emitJDK9StringSubstitutions */true, config.useFMAIntrinsics);
return plugins;
}
@ -222,8 +229,10 @@ public class AArch64HotSpotBackendFactory extends HotSpotBackendFactory {
}
protected HotSpotLoweringProvider createLowerer(HotSpotGraalRuntimeProvider runtime, HotSpotMetaAccessProvider metaAccess, HotSpotForeignCallsProvider foreignCalls,
HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, PlatformConfigurationProvider platformConfig, TargetDescription target) {
return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, target);
HotSpotRegistersProvider registers, HotSpotConstantReflectionProvider constantReflection, PlatformConfigurationProvider platformConfig,
MetaAccessExtensionProvider metaAccessExtensionProvider,
TargetDescription target) {
return new AArch64HotSpotLoweringProvider(runtime, metaAccess, foreignCalls, registers, constantReflection, platformConfig, metaAccessExtensionProvider, target);
}
protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.inlineCache
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotMarkId;
import org.graalvm.compiler.lir.LIRFrameState;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
@ -58,14 +59,17 @@ final class AArch64HotSpotDirectStaticCallOp extends DirectCallOp {
}
@Override
@SuppressWarnings("try")
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
// The mark for an invocation that uses an inline cache must be placed at the
// instruction that loads the Klass from the inline cache.
// For the first invocation this is set to a bitpattern that is guaranteed to never be a
// valid object which causes the called function to call a handler that installs the
// correct inline cache value here.
crb.recordMark(invokeKind == InvokeKind.Static ? config.MARKID_INVOKESTATIC : config.MARKID_INVOKESPECIAL);
masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
super.emitCode(crb, masm);
try (CompilationResultBuilder.CallContext callContext = crb.openCallContext(invokeKind.isDirect())) {
// The mark for an invocation that uses an inline cache must be placed at the
// instruction that loads the Klass from the inline cache.
// For the first invocation this is set to a bitpattern that is guaranteed to never be a
// valid object which causes the called function to call a handler that installs the
// correct inline cache value here.
crb.recordMark(invokeKind == InvokeKind.Static ? HotSpotMarkId.INVOKESTATIC : HotSpotMarkId.INVOKESPECIAL);
masm.movNativeAddress(inlineCacheRegister, config.nonOopBits);
super.emitCode(crb, masm);
}
}
}

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