8222665: Update Graal

Reviewed-by: kvn
This commit is contained in:
Jesper Wilhelmsson 2019-05-06 21:50:20 +02:00
parent 0ff8db34ca
commit 69647ce061
37 changed files with 2416 additions and 198 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ import org.graalvm.compiler.serviceprovider.JMXService;
import com.sun.management.ThreadMXBean;
/**
* Implementation of {@link JMXService} for JDK 11 and later.
* Implementation of {@link JMXService} for JDK 13 and later.
*/
@ServiceProvider(JMXService.class)
public class JMXServiceProvider extends JMXService {

View File

@ -3003,6 +3003,18 @@ public class AMD64Assembler extends AMD64BaseAssembler {
emitByte(0x99);
}
public final void repStosb() {
emitByte(0xf3);
rexw();
emitByte(0xaa);
}
public final void repStosq() {
emitByte(0xf3);
rexw();
emitByte(0xab);
}
public final void cmovq(ConditionFlag cc, Register dst, Register src) {
prefixq(dst, src);
emitByte(0x0F);

View File

@ -121,6 +121,7 @@ import org.graalvm.compiler.lir.amd64.AMD64MulDivOp;
import org.graalvm.compiler.lir.amd64.AMD64ShiftOp;
import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp;
import org.graalvm.compiler.lir.amd64.AMD64Unary;
import org.graalvm.compiler.lir.amd64.AMD64ZeroMemoryOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorBinary.AVXBinaryOp;
import org.graalvm.compiler.lir.amd64.vector.AMD64VectorUnary;
@ -1102,6 +1103,12 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
return new AMD64MathPowOp().emitLIRWrapper(getLIRGen(), x, y);
}
@Override
public void emitZeroMemory(Value address, Value length) {
RegisterValue lengthReg = moveToReg(AMD64.rcx, length);
getLIRGen().append(new AMD64ZeroMemoryOp(getAMD64LIRGen().asAddressValue(address), lengthReg));
}
protected AMD64LIRGenerator getAMD64LIRGen() {
return (AMD64LIRGenerator) getLIRGen();
}

View File

@ -279,9 +279,13 @@ public final class GraalOptions {
@Option(help = "Enable inlining decision tracing in stubs and snippets.", type = OptionType.Debug)
public static final OptionKey<Boolean> TraceInliningForStubsAndSnippets = new OptionKey<>(false);
@Option(help = "Use Graal-generated stubs for complicated LIR operations instead of embedding all the emitted code.")
@Option(help = "Use Graal-generated stubs for complicated LIR operations instead of embedding all the emitted code.", type = OptionType.Expert)
public static final OptionKey<Boolean> UseGraalStubs = new OptionKey<>(true);
@Option(help = "Encode and decode snippets and substitutions before parsing to test libgraal code path. This option is ignored in the context of libgraal.")
public static final OptionKey<Boolean> UseEncodedGraphs = new OptionKey<>(false);
@Option(help = "If applicable, use bulk zeroing instructions when the zeroing size in bytes exceeds this threshold.", type = OptionType.Expert)
public static final OptionKey<Integer> MinimalBulkZeroingSize = new OptionKey<>(2048);
}

View File

@ -318,8 +318,10 @@ public class FloatStamp extends PrimitiveStamp {
/*
* There are many forms of NaNs and any operations on them can silently convert them into
* the canonical NaN.
*
* We need to exclude 0 here since it can contain -0.0 && 0.0 .
*/
return (Double.compare(lowerBound, upperBound) == 0 && nonNaN);
return (Double.compare(lowerBound, upperBound) == 0 && nonNaN) && lowerBound != 0;
}
private static FloatStamp stampForConstant(Constant constant) {

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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;
public class ConditionalEliminationPiTest extends ConditionalEliminationTestBase {
static int SideEffect;
static double oracleValue1 = -0.0;
static double oracleValue2;
public static double testSnippet1(int a) {
double phi;
if (a > 0) {
double oracle = oracleValue1;
if (oracle == 0.0) {
SideEffect = 1;
} else {
return 123;
}
phi = oracle;
} else {
double oracle = oracleValue2;
if (oracle == 0.0) {
SideEffect = 1;
phi = oracle;
} else {
return 0;
}
}
if (Double.doubleToRawLongBits(phi) == Double.doubleToRawLongBits(-0.0)) {
return 12;
}
return 2;
}
@Test
public void test1() {
test("testSnippet1", 1);
}
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.StampPair;
import org.graalvm.compiler.core.common.type.TypeReference;
import org.graalvm.compiler.nodes.ParameterNode;
import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.junit.Test;
import jdk.vm.ci.meta.ResolvedJavaMethod;
/**
* Check that multiple bounds checks are correctly grouped together.
*/
public class ConditionalEliminationTest16 extends ConditionalEliminationTestBase {
public static int testCastExactInstance(Object object) {
if (object.getClass() == Integer.class) {
return ((Integer) object).intValue();
}
GraalDirectives.deoptimizeAndInvalidate();
return -1;
}
@Override
protected boolean checkHighTierGraph(StructuredGraph graph) {
for (ParameterNode param : graph.getNodes().filter(ParameterNode.class)) {
if (param.index() == 0) {
ParameterNode newParam = new ParameterNode(0, StampPair.createSingle(StampFactory.object(TypeReference.createExactTrusted(getMetaAccess().lookupJavaType(Integer.class)))));
graph.addWithoutUnique(newParam);
param.replaceAtUsages(newParam);
param.safeDelete();
break;
}
}
new CanonicalizerPhase().apply(graph, getDefaultHighTierContext());
return super.checkHighTierGraph(graph);
}
@Override
protected boolean checkMidTierGraph(StructuredGraph graph) {
int count = 0;
for (PiNode node : graph.getNodes().filter(PiNode.class)) {
assertTrue(node.getGuard() != null, "must have guarding node");
count++;
}
assertTrue(count > 0, "expected at least one Pi");
return super.checkMidTierGraph(graph);
}
@Test
public void test1() {
ResolvedJavaMethod method = getResolvedJavaMethod("testCastExactInstance");
StructuredGraph graph = parseForCompile(method);
compile(method, graph);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -129,4 +129,9 @@ public class AMD64HotSpotLoweringProvider extends DefaultHotSpotLoweringProvider
public Integer smallestCompareWidth() {
return 8;
}
@Override
public boolean supportBulkZeroing() {
return true;
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.test;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.hotspot.JVMCIVersionCheck;
import org.junit.Assert;
import org.junit.Test;
public class JVMCIVersionCheckTest extends GraalCompilerTest {
@Test
public void test01() {
Properties sprops = System.getProperties();
Map<String, String> props = new HashMap<>(sprops.size());
for (String name : sprops.stringPropertyNames()) {
props.put(name, sprops.getProperty(name));
}
for (int i = 0; i < 100; i++) {
int minMajor = i;
int minMinor = 100 - i;
for (int j = 0; j < 100; j++) {
int major = j;
int minor = 100 - j;
boolean ok = (major > minMajor) || (major == minMajor && minor >= minMinor);
for (String sep : new String[]{".", "-b"}) {
String javaVmVersion = String.format("prefix-jvmci-%03d%s%03d-suffix", major, sep, minor);
if (ok) {
JVMCIVersionCheck.check(props, minMajor, minMinor, "1.8", javaVmVersion, false);
} else {
try {
JVMCIVersionCheck.check(props, minMajor, minMinor, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against " + minMajor + "." + minMinor);
} catch (InternalError e) {
// pass
}
}
}
}
}
// Test handling of version components bigger than Integer.MAX_VALUE
for (String sep : new String[]{".", "-b"}) {
for (String version : new String[]{"0" + sep + Long.MAX_VALUE, Long.MAX_VALUE + sep + 0}) {
String javaVmVersion = String.format("prefix-jvmci-%s-suffix", version);
try {
JVMCIVersionCheck.check(props, 0, 59, "1.8", javaVmVersion, false);
Assert.fail("expected to fail checking " + javaVmVersion + " against 0.59");
} catch (InternalError e) {
// pass
}
}
}
}
}

View File

@ -32,7 +32,6 @@ import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
import java.io.PrintStream;
import java.util.List;
import jdk.internal.vm.compiler.collections.EconomicMap;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
@ -44,7 +43,6 @@ import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugDumpScope;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
@ -52,7 +50,6 @@ import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
import jdk.vm.ci.code.BailoutException;
import jdk.vm.ci.code.CodeCacheProvider;
import jdk.vm.ci.hotspot.EventProvider;
import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
import jdk.vm.ci.hotspot.HotSpotCompilationRequestResult;
import jdk.vm.ci.hotspot.HotSpotInstalledCode;
@ -60,23 +57,9 @@ import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
import jdk.vm.ci.hotspot.HotSpotNmethod;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.runtime.JVMCICompiler;
import jdk.vm.ci.services.JVMCIServiceLocator;
public class CompilationTask {
private static final EventProvider eventProvider;
static {
List<EventProvider> providers = JVMCIServiceLocator.getProviders(EventProvider.class);
if (providers.size() > 1) {
throw new GraalError("Multiple %s providers found: %s", EventProvider.class.getName(), providers);
} else if (providers.isEmpty()) {
eventProvider = EventProvider.createEmptyEventProvider();
} else {
eventProvider = providers.get(0);
}
}
private final HotSpotJVMCIRuntime jvmciRuntime;
private final HotSpotGraalCompiler compiler;
@ -94,12 +77,10 @@ public class CompilationTask {
private final boolean shouldRetainLocalVariables;
final class HotSpotCompilationWrapper extends CompilationWrapper<HotSpotCompilationRequestResult> {
private final EventProvider.CompilationEvent compilationEvent;
CompilationResult result;
HotSpotCompilationWrapper(EventProvider.CompilationEvent compilationEvent) {
HotSpotCompilationWrapper() {
super(compiler.getGraalRuntime().getOutputDirectory(), compiler.getGraalRuntime().getCompilationProblemsPerAction());
this.compilationEvent = compilationEvent;
}
@Override
@ -125,13 +106,6 @@ public class CompilationTask {
*/
return HotSpotCompilationRequestResult.failure(bailout.getMessage(), !bailout.isPermanent());
}
// Log a failure event.
EventProvider.CompilerFailureEvent event = eventProvider.newCompilerFailureEvent();
if (event.shouldWrite()) {
event.setCompileId(getId());
event.setMessage(t.getMessage());
event.commit();
}
/*
* Treat random exceptions from the compiler as indicating a problem compiling this
@ -181,14 +155,9 @@ public class CompilationTask {
final CompilationPrinter printer = CompilationPrinter.begin(debug.getOptions(), compilationId, method, entryBCI);
try (DebugContext.Scope s = debug.scope("Compiling", new DebugDumpScope(getIdString(), true))) {
// Begin the compilation event.
compilationEvent.begin();
result = compiler.compile(method, entryBCI, useProfilingInfo, shouldRetainLocalVariables, compilationId, debug);
} catch (Throwable e) {
throw debug.handle(e);
} finally {
// End the compilation event.
compilationEvent.end();
}
if (result != null) {
@ -322,9 +291,6 @@ public class CompilationTask {
boolean isOSR = entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI;
HotSpotResolvedJavaMethod method = getMethod();
// Log a compilation event.
EventProvider.CompilationEvent compilationEvent = eventProvider.newCompilationEvent();
if (installAsDefault || isOSR) {
// If there is already compiled code for this method on our level we simply return.
// JVMCI compiles are always at the highest compile level, even in non-tiered mode so we
@ -337,7 +303,7 @@ public class CompilationTask {
}
}
HotSpotCompilationWrapper compilation = new HotSpotCompilationWrapper(compilationEvent);
HotSpotCompilationWrapper compilation = new HotSpotCompilationWrapper();
try (DebugCloseable a = CompilationTime.start(debug)) {
return compilation.run(debug);
} finally {
@ -354,18 +320,6 @@ public class CompilationTask {
InstalledCodeSize.add(debug, codeSize);
}
}
// Log a compilation event.
if (compilationEvent.shouldWrite()) {
compilationEvent.setMethod(method.format("%H.%n(%p)"));
compilationEvent.setCompileId(getId());
compilationEvent.setCompileLevel(config.compilationLevelFullOptimization);
compilationEvent.setSucceeded(compilation.result != null && installedCode != null);
compilationEvent.setIsOsr(isOSR);
compilationEvent.setCodeSize(codeSize);
compilationEvent.setInlinedBytes(compiledBytecodes);
compilationEvent.commit();
}
} catch (Throwable t) {
return compilation.handleException(t);
}

View File

@ -460,6 +460,7 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase {
public final int objectMonitorRecursions = getFieldOffset("ObjectMonitor::_recursions", Integer.class, "intptr_t", -1);
public final int objectMonitorCxq = getFieldOffset("ObjectMonitor::_cxq", Integer.class, "ObjectWaiter*", -1);
public final int objectMonitorEntryList = getFieldOffset("ObjectMonitor::_EntryList", Integer.class, "ObjectWaiter*", -1);
public final int objectMonitorSucc = getFieldOffset("ObjectMonitor::_succ", Integer.class, "Thread*", -1);
public final int markWordNoHashInPlace = getConstant("markOopDesc::no_hash_in_place", Integer.class);
public final int markWordNoLockInPlace = getConstant("markOopDesc::no_lock_in_place", Integer.class);

View File

@ -39,7 +39,7 @@ import java.util.Properties;
*
* This class only depends on the JDK so that it can be used without building Graal.
*/
class JVMCIVersionCheck {
public final class JVMCIVersionCheck {
// 0.57 introduces HotSpotJVMCIRuntime.excludeFromJVMCICompilation
private static final int JVMCI8_MIN_MAJOR_VERSION = 0;
@ -73,42 +73,115 @@ class JVMCIVersionCheck {
}
}
private final String javaSpecVersion;
private final String vmVersion;
private int cursor;
private final Map<String, String> props;
private JVMCIVersionCheck(Map<String, String> props, String javaSpecVersion, String vmVersion) {
this.props = props;
this.javaSpecVersion = javaSpecVersion;
this.vmVersion = vmVersion;
}
static void check(Map<String, String> props, boolean exitOnFailure) {
JVMCIVersionCheck checker = new JVMCIVersionCheck(props, props.get("java.specification.version"), props.get("java.vm.version"));
checker.run(exitOnFailure, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
}
/**
* Entry point for testing.
*/
public static void check(Map<String, String> props,
int jvmci8MinMajorVersion,
int jvmci8MinMinorVersion,
String javaSpecVersion,
String javaVmVersion,
boolean exitOnFailure) {
JVMCIVersionCheck checker = new JVMCIVersionCheck(props, javaSpecVersion, javaVmVersion);
checker.run(exitOnFailure, jvmci8MinMajorVersion, jvmci8MinMinorVersion);
}
/**
* Parses a positive decimal number at {@link #cursor}.
*
* @return -1 if there is no positive decimal number at {@link #cursor}
*/
private int parseNumber() {
int result = -1;
while (cursor < vmVersion.length()) {
int digit = vmVersion.charAt(cursor) - '0';
if (digit >= 0 && digit <= 9) {
if (result == -1) {
result = digit;
} else {
long r = (long) result * (long) 10;
if ((int) r != r) {
// Overflow
return -1;
}
result = (int) r + digit;
}
cursor++;
} else {
break;
}
}
return result;
}
/**
* Parse {@code "."} or {@code "-b"} at {@link #cursor}.
*
* @return {@code true} iff there was an expected separator at {@link #cursor}
*/
private boolean parseSeparator() {
if (cursor < vmVersion.length()) {
char ch = vmVersion.charAt(cursor);
if (ch == '.') {
cursor++;
return true;
}
if (ch == '-') {
cursor++;
if (cursor < vmVersion.length()) {
if (vmVersion.charAt(cursor) == 'b') {
cursor++;
return true;
}
}
return false;
}
}
return false;
}
private void run(boolean exitOnFailure, int jvmci8MinMajorVersion, int jvmci8MinMinorVersion) {
// Don't use regular expressions to minimize Graal startup time
String javaSpecVersion = props.get("java.specification.version");
String vmVersion = props.get("java.vm.version");
if (javaSpecVersion.compareTo("1.9") < 0) {
int start = vmVersion.indexOf("-jvmci-");
if (start >= 0) {
start += "-jvmci-".length();
int end = vmVersion.indexOf('.', start);
if (end > 0) {
int major;
try {
major = Integer.parseInt(vmVersion.substring(start, end));
} catch (NumberFormatException e) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI major version from java.vm.version property: %s.%n", vmVersion);
return;
}
start = end + 1;
end = start;
while (end < vmVersion.length() && Character.isDigit(vmVersion.charAt(end))) {
end++;
}
int minor;
try {
minor = Integer.parseInt(vmVersion.substring(start, end));
} catch (NumberFormatException e) {
cursor = vmVersion.indexOf("-jvmci-");
if (cursor >= 0) {
cursor += "-jvmci-".length();
int major = parseNumber();
if (major == -1) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI major version from java.vm.version property: %s.%n", vmVersion);
return;
}
if (parseSeparator()) {
int minor = parseNumber();
if (minor == -1) {
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal.%n" +
"Cannot read JVMCI minor version from java.vm.version property: %s.%n", vmVersion);
return;
}
if (major >= JVMCI8_MIN_MAJOR_VERSION && minor >= JVMCI8_MIN_MINOR_VERSION) {
if (major > jvmci8MinMajorVersion || (major >= jvmci8MinMajorVersion && minor >= jvmci8MinMinorVersion)) {
return;
}
failVersionCheck(props, exitOnFailure, "The VM does not support the minimum JVMCI API version required by Graal: %d.%d < %d.%d.%n",
major, minor, JVMCI8_MIN_MAJOR_VERSION, JVMCI8_MIN_MINOR_VERSION);
major, minor, jvmci8MinMajorVersion, jvmci8MinMinorVersion);
return;
}
}

View File

@ -571,7 +571,7 @@ public class SymbolicSnippetEncoder {
try {
replacement = ((SymbolicJVMCIReference<?>) o).resolve(type);
break;
} catch (NoClassDefFoundError | AssertionError e) {
} catch (NoClassDefFoundError e) {
}
}
} else if (o instanceof UnresolvedJavaType) {
@ -579,7 +579,7 @@ public class SymbolicSnippetEncoder {
try {
replacement = ((UnresolvedJavaType) o).resolve(type);
break;
} catch (NoClassDefFoundError | AssertionError e) {
} catch (NoClassDefFoundError e) {
}
}
} else if (o instanceof UnresolvedJavaMethod) {
@ -589,7 +589,7 @@ public class SymbolicSnippetEncoder {
try {
replacement = ((UnresolvedJavaField) o).resolve(type);
break;
} catch (NoClassDefFoundError | AssertionError e) {
} catch (NoClassDefFoundError e) {
}
}
} else if (o instanceof GraalCapability) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it

View File

@ -516,6 +516,11 @@ public class HotSpotReplacementsUtil {
return config.objectMonitorEntryList;
}
@Fold
public static int objectMonitorSuccOffset(@InjectedParameter GraalHotSpotVMConfig config) {
return config.objectMonitorSucc;
}
/**
* Mask for a biasable, locked or unlocked mark word.
*
@ -685,6 +690,8 @@ public class HotSpotReplacementsUtil {
public static final LocationIdentity OBJECT_MONITOR_ENTRY_LIST_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_EntryList");
public static final LocationIdentity OBJECT_MONITOR_SUCC_LOCATION = NamedLocationIdentity.mutable("ObjectMonitor::_succ");
@Fold
public static int lockDisplacedMarkOffset(@InjectedParameter GraalHotSpotVMConfig config) {
return config.basicLockDisplacedHeaderOffset;

View File

@ -25,6 +25,7 @@
package org.graalvm.compiler.hotspot.replacements;
import static jdk.vm.ci.code.MemoryBarriers.LOAD_STORE;
import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import static jdk.vm.ci.code.MemoryBarriers.STORE_STORE;
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_OPTIONVALUES;
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
@ -38,6 +39,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_ENTRY_LIST_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_OWNER_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_RECURSION_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.OBJECT_MONITOR_SUCC_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.PROTOTYPE_MARK_WORD_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.ageMaskInPlace;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.biasedLockMaskInPlace;
@ -51,6 +53,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorEntryListOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorOwnerOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorRecursionsOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.objectMonitorSuccOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.pageSize;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.prototypeMarkWordOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
@ -574,6 +577,32 @@ public class MonitorSnippets implements Snippets {
traceObject(trace, "-lock{inflated:simple}", object, false);
counters.unlockInflatedSimple.inc();
return true;
} else {
int succOffset = objectMonitorSuccOffset(INJECTED_VMCONFIG);
Word succ = monitor.readWord(succOffset, OBJECT_MONITOR_SUCC_LOCATION);
if (probability(FREQUENT_PROBABILITY, succ.isNonNull())) {
// There may be a thread spinning on this monitor. Temporarily setting
// the monitor owner to null, and hope that the other thread will grab it.
monitor.writeWord(ownerOffset, zero());
memoryBarrier(STORE_STORE | STORE_LOAD);
succ = monitor.readWord(succOffset, OBJECT_MONITOR_SUCC_LOCATION);
if (probability(NOT_FREQUENT_PROBABILITY, succ.isNonNull())) {
// We manage to release the monitor before the other running thread even
// notices.
traceObject(trace, "-lock{inflated:transfer}", object, false);
counters.unlockInflatedTransfer.inc();
return true;
} else {
// Either the monitor is grabbed by a spinning thread, or the spinning
// thread parks. Now we attempt to reset the owner of the monitor.
if (probability(FREQUENT_PROBABILITY, !monitor.logicCompareAndSwapWord(ownerOffset, zero(), thread, OBJECT_MONITOR_OWNER_LOCATION))) {
// The monitor is stolen.
traceObject(trace, "-lock{inflated:transfer}", object, false);
counters.unlockInflatedTransfer.inc();
return true;
}
}
}
}
}
counters.unlockStubInflated.inc();
@ -692,6 +721,7 @@ public class MonitorSnippets implements Snippets {
public final SnippetCounter unlockStub;
public final SnippetCounter unlockStubInflated;
public final SnippetCounter unlockInflatedSimple;
public final SnippetCounter unlockInflatedTransfer;
public Counters(SnippetCounter.Group.Factory factory) {
SnippetCounter.Group enter = factory.createSnippetCounterGroup("MonitorEnters");
@ -716,6 +746,7 @@ public class MonitorSnippets implements Snippets {
unlockStub = new SnippetCounter(exit, "unlock{stub}", "stub-unlocked an object");
unlockStubInflated = new SnippetCounter(exit, "unlock{stub:inflated}", "stub-unlocked an object with inflated monitor");
unlockInflatedSimple = new SnippetCounter(exit, "unlock{inflated}", "unlocked an object monitor");
unlockInflatedTransfer = new SnippetCounter(exit, "unlock{inflated:transfer}", "unlocked an object monitor in the presence of ObjectMonitor::_succ");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,6 +27,7 @@ package org.graalvm.compiler.hotspot.replacements;
import static jdk.vm.ci.meta.DeoptimizationAction.None;
import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.core.common.GraalOptions.MinimalBulkZeroingSize;
import static org.graalvm.compiler.core.common.calc.UnsignedMath.belowThan;
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_OPTIONVALUES;
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
@ -130,6 +131,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
import org.graalvm.compiler.replacements.nodes.ZeroMemoryNode;
import org.graalvm.compiler.word.Word;
import jdk.internal.vm.compiler.word.LocationIdentity;
import jdk.internal.vm.compiler.word.WordFactory;
@ -311,21 +313,39 @@ public class NewObjectSnippets implements Snippets {
public static final int MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH = 0x00FFFFFF;
@Snippet
public static Object allocatePrimitiveArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext,
public static Object allocatePrimitiveArrayPIC(KlassPointer hub,
int length,
Word prototypeMarkWord,
@ConstantParameter int headerSize,
@ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ConstantParameter boolean useBulkZeroing,
@ConstantParameter Counters counters) {
// Primitive array types are eagerly pre-resolved. We can use a floating load.
KlassPointer picHub = LoadConstantIndirectlyNode.loadKlass(hub);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, counters);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
}
@Snippet
public static Object allocateArrayPIC(KlassPointer hub, int length, Word prototypeMarkWord, @ConstantParameter int headerSize, @ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister, @ConstantParameter boolean maybeUnroll, @ConstantParameter String typeContext,
public static Object allocateArrayPIC(KlassPointer hub,
int length,
Word prototypeMarkWord,
@ConstantParameter int headerSize,
@ConstantParameter int log2ElementSize,
@ConstantParameter boolean fillContents,
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ConstantParameter boolean useBulkZeroing,
@ConstantParameter Counters counters) {
// Array type would be resolved by dominating resolution.
KlassPointer picHub = LoadConstantIndirectlyFixedNode.loadKlass(hub);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, maybeUnroll, typeContext, counters);
return allocateArrayImpl(picHub, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, maybeUnroll, typeContext, useBulkZeroing, counters);
}
@Snippet
@ -338,6 +358,7 @@ public class NewObjectSnippets implements Snippets {
@ConstantParameter Register threadRegister,
@ConstantParameter boolean maybeUnroll,
@ConstantParameter String typeContext,
@ConstantParameter boolean useBulkZeroing,
@ConstantParameter Counters counters) {
Object result = allocateArrayImpl(hub,
length,
@ -348,7 +369,7 @@ public class NewObjectSnippets implements Snippets {
threadRegister,
maybeUnroll,
typeContext,
useBulkZeroing,
counters);
return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
}
@ -363,7 +384,7 @@ public class NewObjectSnippets implements Snippets {
}
private static Object allocateArrayImpl(KlassPointer hub, int length, Word prototypeMarkWord, int headerSize, int log2ElementSize, boolean fillContents, Register threadRegister,
boolean maybeUnroll, String typeContext, Counters counters) {
boolean maybeUnroll, String typeContext, boolean useBulkZeroing, Counters counters) {
Object result;
long allocationSize = arrayAllocationSize(length, headerSize, log2ElementSize);
Word thread = registerAsWord(threadRegister);
@ -378,7 +399,7 @@ public class NewObjectSnippets implements Snippets {
if (theCounters != null && theCounters.arrayLoopInit != null) {
theCounters.arrayLoopInit.inc();
}
result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, counters);
result = formatArray(hub, allocationSize, length, headerSize, top, prototypeMarkWord, fillContents, maybeUnroll, useBulkZeroing, counters);
} else {
result = newArrayStub(hub, length);
}
@ -435,15 +456,23 @@ public class NewObjectSnippets implements Snippets {
public static native Object dynamicNewInstanceOrNull(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
@Snippet
public static Object allocateArrayDynamic(Class<?> elementType, Class<?> voidClass, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
@ConstantParameter JavaKind knownElementKind, @ConstantParameter int knownLayoutHelper, Word prototypeMarkWord,
public static Object allocateArrayDynamic(Class<?> elementType,
Class<?> voidClass,
int length,
@ConstantParameter boolean fillContents,
@ConstantParameter Register threadRegister,
@ConstantParameter JavaKind knownElementKind,
@ConstantParameter int knownLayoutHelper,
@ConstantParameter boolean useBulkZeroing,
Word prototypeMarkWord,
@ConstantParameter Counters counters) {
Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, threadRegister, knownElementKind, knownLayoutHelper, prototypeMarkWord, counters);
Object result = allocateArrayDynamicImpl(elementType, voidClass, length, fillContents, threadRegister, knownElementKind,
knownLayoutHelper, useBulkZeroing, prototypeMarkWord, counters);
return result;
}
private static Object allocateArrayDynamicImpl(Class<?> elementType, Class<?> voidClass, int length, boolean fillContents, Register threadRegister, JavaKind knownElementKind,
int knownLayoutHelper, Word prototypeMarkWord, Counters counters) {
int knownLayoutHelper, boolean useBulkZeroing, Word prototypeMarkWord, Counters counters) {
/*
* We only need the dynamic check for void when we have no static information from
* knownElementKind.
@ -485,7 +514,8 @@ public class NewObjectSnippets implements Snippets {
int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents, threadRegister, false, "dynamic type", counters);
Object result = allocateArrayImpl(nonNullKlass, length, prototypeMarkWord, headerSize, log2ElementSize, fillContents,
threadRegister, false, "dynamic type", useBulkZeroing, counters);
return piArrayCastToSnippetReplaceeStamp(verifyOop(result), length);
}
@ -538,12 +568,15 @@ public class NewObjectSnippets implements Snippets {
* @param constantSize is {@code size} known to be constant in the snippet
* @param startOffset offset to begin zeroing. May not be word aligned.
* @param manualUnroll maximally unroll zeroing
* @param useBulkZeroing apply bulk zeroing
*/
private static void zeroMemory(long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, Counters counters) {
fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, counters);
private static void zeroMemory(long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll,
boolean useBulkZeroing, Counters counters) {
fillMemory(0, size, memory, constantSize, startOffset, manualUnroll, useBulkZeroing, counters);
}
private static void fillMemory(long value, long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, Counters counters) {
private static void fillMemory(long value, long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll,
boolean useBulkZeroing, Counters counters) {
ReplacementsUtil.runtimeAssert((size & 0x7) == 0, "unaligned object size");
int offset = startOffset;
if ((offset & 0x7) != 0) {
@ -571,22 +604,35 @@ public class NewObjectSnippets implements Snippets {
} else {
// Use Word instead of int to avoid extension to long in generated code
Word off = WordFactory.signed(offset);
if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
if (theCounters != null && theCounters.instanceSeqInit != null) {
theCounters.instanceSeqInit.inc();
if (useBulkZeroing && probability(SLOW_PATH_PROBABILITY, size >= getMinimalBulkZeroingSize(INJECTED_OPTIONVALUES))) {
if (theCounters != null && theCounters.instanceBulkInit != null) {
theCounters.instanceBulkInit.inc();
}
explodeLoop();
ZeroMemoryNode.zero(memory.add(off), size - offset, LocationIdentity.init());
} else {
if (theCounters != null && theCounters.instanceLoopInit != null) {
theCounters.instanceLoopInit.inc();
if (constantSize && ((size - offset) / 8) <= MAX_UNROLLED_OBJECT_ZEROING_STORES) {
if (theCounters != null && theCounters.instanceSeqInit != null) {
theCounters.instanceSeqInit.inc();
}
explodeLoop();
} else {
if (theCounters != null && theCounters.instanceLoopInit != null) {
theCounters.instanceLoopInit.inc();
}
}
}
for (; off.rawValue() < size; off = off.add(8)) {
memory.initializeLong(off, value, LocationIdentity.init());
for (; off.rawValue() < size; off = off.add(8)) {
memory.initializeLong(off, value, LocationIdentity.init());
}
}
}
}
@Fold
static int getMinimalBulkZeroingSize(@InjectedParameter OptionValues optionValues) {
return MinimalBulkZeroingSize.getValue(optionValues);
}
/**
* Fill uninitialized memory with garbage value in a newly allocated object, unrolling as
* necessary and ensuring that stores are aligned.
@ -598,7 +644,7 @@ public class NewObjectSnippets implements Snippets {
* @param manualUnroll maximally unroll zeroing
*/
private static void fillWithGarbage(long size, Word memory, boolean constantSize, int startOffset, boolean manualUnroll, Counters counters) {
fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, counters);
fillMemory(0xfefefefefefefefeL, size, memory, constantSize, startOffset, manualUnroll, false, counters);
}
/**
@ -608,7 +654,7 @@ public class NewObjectSnippets implements Snippets {
Word prototypeMarkWord = useBiasedLocking(INJECTED_VMCONFIG) ? hub.readWord(prototypeMarkWordOffset(INJECTED_VMCONFIG), PROTOTYPE_MARK_WORD_LOCATION) : compileTimePrototypeMarkWord;
initializeObjectHeader(memory, prototypeMarkWord, hub);
if (fillContents) {
zeroMemory(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, counters);
zeroMemory(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, false, counters);
} else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
fillWithGarbage(size, memory, constantSize, instanceHeaderSize(INJECTED_VMCONFIG), false, counters);
}
@ -632,7 +678,7 @@ public class NewObjectSnippets implements Snippets {
* Formats some allocated memory with an object header and zeroes out the rest.
*/
private static Object formatArray(KlassPointer hub, long allocationSize, int length, int headerSize, Word memory, Word prototypeMarkWord, boolean fillContents, boolean maybeUnroll,
Counters counters) {
boolean useBulkZeroing, Counters counters) {
memory.writeInt(arrayLengthOffset(INJECTED_VMCONFIG), length, LocationIdentity.init());
/*
* store hub last as the concurrent garbage collectors assume length is valid if hub field
@ -640,7 +686,7 @@ public class NewObjectSnippets implements Snippets {
*/
initializeObjectHeader(memory, prototypeMarkWord, hub);
if (fillContents) {
zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, counters);
zeroMemory(allocationSize, memory, false, headerSize, maybeUnroll, useBulkZeroing, counters);
} else if (REPLACEMENTS_ASSERTIONS_ENABLED) {
fillWithGarbage(allocationSize, memory, false, headerSize, maybeUnroll, counters);
}
@ -654,12 +700,14 @@ public class NewObjectSnippets implements Snippets {
Group newArray = factory.createSnippetCounterGroup("NewArray");
instanceSeqInit = new SnippetCounter(newInstance, "tlabSeqInit", "TLAB alloc with unrolled zeroing");
instanceLoopInit = new SnippetCounter(newInstance, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
instanceBulkInit = new SnippetCounter(newArray, "tlabBulkInit", "TLAB alloc with bulk zeroing");
arrayLoopInit = new SnippetCounter(newArray, "tlabLoopInit", "TLAB alloc with zeroing in a loop");
stub = new SnippetCounter(newInstance, "stub", "alloc and zeroing via stub");
}
final SnippetCounter instanceSeqInit;
final SnippetCounter instanceLoopInit;
final SnippetCounter instanceBulkInit;
final SnippetCounter arrayLoopInit;
final SnippetCounter stub;
}
@ -753,6 +801,7 @@ public class NewObjectSnippets implements Snippets {
args.addConst("threadRegister", registers.getThreadRegister());
args.addConst("maybeUnroll", length.isConstant());
args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
args.addConst("useBulkZeroing", tool.getLowerer().supportBulkZeroing());
args.addConst("counters", counters);
SnippetTemplate template = template(newArrayNode, args);
graph.getDebug().log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
@ -775,7 +824,7 @@ public class NewObjectSnippets implements Snippets {
public void lower(DynamicNewArrayNode newArrayNode, HotSpotRegistersProvider registers, LoweringTool tool) {
StructuredGraph graph = newArrayNode.graph();
Arguments args = new Arguments(allocateArrayDynamic, newArrayNode.graph().getGuardsStage(), tool.getLoweringStage());
Arguments args = new Arguments(allocateArrayDynamic, graph.getGuardsStage(), tool.getLoweringStage());
args.add("elementType", newArrayNode.getElementType());
ValueNode voidClass = newArrayNode.getVoidClass();
assert voidClass != null;
@ -794,6 +843,7 @@ public class NewObjectSnippets implements Snippets {
} else {
args.addConst("knownLayoutHelper", 0);
}
args.addConst("useBulkZeroing", tool.getLowerer().supportBulkZeroing());
args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
args.addConst("counters", counters);
SnippetTemplate template = template(newArrayNode, args);

View File

@ -93,6 +93,7 @@ import static org.graalvm.compiler.bytecode.Bytecodes.SASTORE;
import static org.graalvm.compiler.bytecode.Bytecodes.TABLESWITCH;
import static org.graalvm.compiler.core.common.GraalOptions.SupportJsrBytecodes;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -117,7 +118,7 @@ import jdk.vm.ci.meta.ExceptionHandler;
/**
* Builds a mapping between bytecodes and basic blocks and builds a conservative control flow graph
* (CFG). It makes one linear passes over the bytecodes to build the CFG where it detects block
* (CFG). It makes one linear pass over the bytecodes to build the CFG where it detects block
* headers and connects them.
* <p>
* It also creates exception dispatch blocks for exception handling. These blocks are between a
@ -477,6 +478,18 @@ public final class BciBlockMapping {
}
}
private static final class TraversalStep {
private BciBlock block;
private int currentSuccessorIndex;
private long loops;
private TraversalStep(BciBlock block) {
this.block = block;
this.currentSuccessorIndex = 0;
this.loops = 0;
}
}
/**
* The blocks found in this method, in reverse postorder.
*/
@ -857,7 +870,7 @@ public final class BciBlockMapping {
b.visited = false;
}
long loop = fixLoopBits(blockMap, blockMap[0]);
long loop = fixLoopBits(blockMap[0]);
if (loop != 0) {
// There is a path from a loop end to the method entry that does not pass the loop
@ -1029,78 +1042,107 @@ public final class BciBlockMapping {
}
/**
* Depth-first traversal of the control flow graph. The flag {@linkplain BciBlock#visited} is
* used to visit every block only once. The flag {@linkplain BciBlock#active} is used to detect
* cycles (backward edges).
* Non-recursive depth-first traversal of the control flow graph. The flag
* {@linkplain BciBlock#visited} is used to visit every block only once. The flag
* {@linkplain BciBlock#active} is used to detect cycles (backward edges)
*/
private long computeBlockOrder(BciBlock block) {
if (block.visited) {
if (block.active) {
// Reached block via backward branch.
makeLoopHeader(block);
// Return cached loop information for this block.
return block.loops;
} else if (block.isLoopHeader) {
return block.loops & ~(1L << block.loopId);
private long computeBlockOrder(BciBlock initialBlock) {
ArrayDeque<TraversalStep> workStack = new ArrayDeque<>();
workStack.push(new TraversalStep(initialBlock));
while (true) {
TraversalStep step = workStack.peek();
BciBlock block = step.block;
if (step.currentSuccessorIndex == 0) {
block.visited = true;
block.active = true;
} else {
return block.loops;
BciBlock successor = block.getSuccessor(step.currentSuccessorIndex - 1);
if (successor.active) {
// Reached block via backward branch.
step.loops |= (1L << successor.loopId);
}
}
if (step.currentSuccessorIndex < block.successors.size()) {
BciBlock successor = block.getSuccessors().get(step.currentSuccessorIndex);
if (successor.visited) {
if (successor.active) {
// Reached block via backward branch.
makeLoopHeader(successor);
step.loops |= successor.loops;
} else if (successor.isLoopHeader) {
step.loops |= successor.loops & ~(1L << successor.loopId);
} else {
step.loops |= successor.loops;
}
} else {
workStack.push(new TraversalStep(successor));
}
step.currentSuccessorIndex++;
} else {
// We processed all the successors of this block.
block.loops = step.loops;
debug.log("computeBlockOrder(%s) -> %x", block, block.loops);
if (block.isLoopHeader) {
step.loops &= ~(1L << block.loopId);
}
block.active = false;
blocksNotYetAssignedId--;
blocks[blocksNotYetAssignedId] = block;
workStack.pop();
if (!workStack.isEmpty()) {
workStack.peek().loops |= step.loops;
} else {
return step.loops;
}
}
}
block.visited = true;
block.active = true;
long loops = 0;
for (BciBlock successor : block.getSuccessors()) {
// Recursively process successors.
loops |= computeBlockOrder(successor);
if (successor.active) {
// Reached block via backward branch.
loops |= (1L << successor.loopId);
}
}
block.loops = loops;
debug.log("computeBlockOrder(%s) -> %x", block, block.loops);
if (block.isLoopHeader) {
loops &= ~(1L << block.loopId);
}
block.active = false;
blocksNotYetAssignedId--;
blocks[blocksNotYetAssignedId] = block;
return loops;
}
private long fixLoopBits(BciBlock[] blockMap, BciBlock block) {
if (block.visited) {
// Return cached loop information for this block.
if (block.isLoopHeader) {
return block.loops & ~(1L << block.loopId);
private long fixLoopBits(BciBlock initialBlock) {
ArrayDeque<TraversalStep> workStack = new ArrayDeque<>();
workStack.push(new TraversalStep(initialBlock));
while (true) {
TraversalStep step = workStack.peek();
BciBlock block = step.block;
if (step.currentSuccessorIndex == 0) {
block.visited = true;
step.loops = block.loops;
}
if (step.currentSuccessorIndex < block.getSuccessors().size()) {
BciBlock successor = block.getSuccessors().get(step.currentSuccessorIndex);
if (successor.visited) {
// Return cached loop information for this block.
if (successor.isLoopHeader) {
step.loops |= successor.loops & ~(1L << successor.loopId);
} else {
step.loops |= successor.loops;
}
} else {
workStack.push(new TraversalStep(successor));
}
step.currentSuccessorIndex++;
} else {
return block.loops;
if (block.loops != step.loops) {
loopChanges = true;
block.loops = step.loops;
debug.log("fixLoopBits0(%s) -> %x", block, block.loops);
}
if (block.isLoopHeader) {
step.loops &= ~(1L << block.loopId);
}
workStack.pop();
if (!workStack.isEmpty()) {
workStack.peek().loops |= step.loops;
} else {
return step.loops;
}
}
}
block.visited = true;
long loops = block.loops;
for (BciBlock successor : block.getSuccessors()) {
// Recursively process successors.
loops |= fixLoopBits(blockMap, successor);
}
if (block.loops != loops) {
loopChanges = true;
block.loops = loops;
debug.log("fixLoopBits0(%s) -> %x", block, block.loops);
}
if (block.isLoopHeader) {
loops &= ~(1L << block.loopId);
}
return loops;
}
public static BciBlockMapping create(BytecodeStream stream, Bytecode code, OptionValues options, DebugContext debug) {

View File

@ -710,4 +710,71 @@ public class AArch64Move {
}
}
private abstract static class ZeroNullConversionOp extends AArch64LIRInstruction {
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue input;
protected ZeroNullConversionOp(LIRInstructionClass<? extends ZeroNullConversionOp> type, AllocatableValue result, AllocatableValue input) {
super(type);
this.result = result;
this.input = input;
}
@Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
Register nullRegister = crb.nullRegister;
if (!nullRegister.equals(Register.None)) {
emitConversion(asRegister(result), asRegister(input), nullRegister, masm);
}
}
protected abstract void emitConversion(Register resultRegister, Register inputRegister, Register nullRegister, AArch64MacroAssembler masm);
}
public static class ConvertNullToZeroOp extends ZeroNullConversionOp {
public static final LIRInstructionClass<ConvertNullToZeroOp> TYPE = LIRInstructionClass.create(ConvertNullToZeroOp.class);
public ConvertNullToZeroOp(AllocatableValue result, AllocatableValue input) {
super(TYPE, result, input);
}
@Override
protected final void emitConversion(Register resultRegister, Register inputRegister, Register nullRegister, AArch64MacroAssembler masm) {
if (inputRegister.equals(resultRegister)) {
masm.subs(64, inputRegister, inputRegister, nullRegister);
Label done = new Label();
masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, done);
masm.add(64, inputRegister, inputRegister, nullRegister);
masm.bind(done);
} else {
masm.subs(64, resultRegister, resultRegister, resultRegister);
masm.cmp(64, inputRegister, nullRegister);
Label done = new Label();
masm.branchConditionally(AArch64Assembler.ConditionFlag.EQ, done);
masm.movx(resultRegister, inputRegister);
masm.bind(done);
}
}
}
public static class ConvertZeroToNullOp extends ZeroNullConversionOp {
public static final LIRInstructionClass<ConvertZeroToNullOp> TYPE = LIRInstructionClass.create(ConvertZeroToNullOp.class);
public ConvertZeroToNullOp(AllocatableValue result, AllocatableValue input) {
super(TYPE, result, input);
}
@Override
protected final void emitConversion(Register resultRegister, Register inputRegister, Register nullRegister, AArch64MacroAssembler masm) {
if (!inputRegister.equals(resultRegister)) {
masm.movx(resultRegister, inputRegister);
}
Label done = new Label();
masm.ands(64, zr, inputRegister, inputRegister);
masm.branchConditionally(AArch64Assembler.ConditionFlag.NE, done);
masm.movx(resultRegister, nullRegister);
masm.bind(done);
}
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.lir.amd64;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.meta.Value;
/**
* Zeros a chunk of memory using rep stosb.
*/
@Opcode("ZERO_MEMORY")
public final class AMD64ZeroMemoryOp extends AMD64LIRInstruction {
public static final LIRInstructionClass<AMD64ZeroMemoryOp> TYPE = LIRInstructionClass.create(AMD64ZeroMemoryOp.class);
@Use({COMPOSITE}) protected AMD64AddressValue pointer;
@Use({REG}) protected RegisterValue length;
@Temp protected Value pointerTemp;
@Temp protected Value valueTemp;
@Temp protected Value lengthTemp;
public AMD64ZeroMemoryOp(AMD64AddressValue pointer, RegisterValue length) {
super(TYPE);
this.pointer = pointer;
this.length = length;
this.pointerTemp = AMD64.rdi.asValue(LIRKind.value(AMD64Kind.QWORD));
this.valueTemp = AMD64.rax.asValue(LIRKind.value(AMD64Kind.QWORD));
this.lengthTemp = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.QWORD));
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
assert AMD64.rcx.equals(length.getRegister());
masm.leaq(AMD64.rdi, pointer.toAddress());
masm.xorq(AMD64.rax, AMD64.rax);
masm.repStosb();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -132,4 +132,8 @@ public interface ArithmeticLIRGeneratorTool {
throw GraalError.unimplemented("No specialized implementation available");
}
@SuppressWarnings("unused")
default void emitZeroMemory(Value address, Value length) {
throw GraalError.unimplemented("Bulk zeroing is not supported on this platform");
}
}

View File

@ -83,7 +83,7 @@ public class PrimitiveStampBoundaryTest extends GraalTest {
}
static double[] doubleBoundaryValues = {Double.NEGATIVE_INFINITY, Double.MIN_VALUE, Float.NEGATIVE_INFINITY, Float.MIN_VALUE,
Long.MIN_VALUE, Long.MIN_VALUE + 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1, 0, 1,
Long.MIN_VALUE, Long.MIN_VALUE + 1, Integer.MIN_VALUE, Integer.MIN_VALUE + 1, -1, -0.0, +0.0, 1,
Integer.MAX_VALUE - 1, Integer.MAX_VALUE, Long.MAX_VALUE - 1, Long.MAX_VALUE,
Float.MAX_VALUE, Float.POSITIVE_INFINITY, Double.MAX_VALUE, Double.POSITIVE_INFINITY};
@ -171,11 +171,24 @@ public class PrimitiveStampBoundaryTest extends GraalTest {
checkConvertOperation(op, op.foldStamp(stamp), upper);
}
}
}
static void shouldConstantFold(boolean b, Stamp folded, Object o, Stamp s1) {
assertTrue(b || (folded instanceof FloatStamp && ((FloatStamp) folded).contains(0.0)), "should constant fold %s %s %s", o, s1, folded);
}
private static boolean constantFloatStampMayIncludeNegativeZero(Stamp s) {
if (s instanceof FloatStamp) {
FloatStamp f = (FloatStamp) s;
return Double.compare(f.lowerBound(), f.upperBound()) == 0 && f.isNonNaN();
}
return false;
}
private static void checkConvertOperation(ArithmeticOpTable.FloatConvertOp op, Stamp result, Stamp v1stamp) {
Stamp folded = op.foldStamp(v1stamp);
assertTrue(folded.isEmpty() || folded.asConstant() != null, "should constant fold %s %s %s", op, v1stamp, folded);
shouldConstantFold(folded.isEmpty() || folded.asConstant() != null, folded, op, v1stamp);
assertTrue(result.meet(folded).equals(result), "result out of range %s %s %s %s %s", op, v1stamp, folded, result, result.meet(folded));
}
@ -216,6 +229,9 @@ public class PrimitiveStampBoundaryTest extends GraalTest {
}
private static void checkBinaryOperation(ArithmeticOpTable.BinaryOp<?> op, Stamp result, Stamp v1stamp, Stamp v2stamp) {
if (constantFloatStampMayIncludeNegativeZero(v1stamp) || constantFloatStampMayIncludeNegativeZero(v2stamp)) {
return;
}
Stamp folded = op.foldStamp(v1stamp, v2stamp);
if (v1stamp.isEmpty() || v2stamp.isEmpty()) {
assertTrue(folded.isEmpty());

View File

@ -84,7 +84,7 @@ public class SignedRemNode extends IntegerDivRemNode implements LIRLowerable {
IntegerStamp yStamp = (IntegerStamp) forY.stamp(view);
if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) {
Stamp newStamp = IntegerStamp.OPS.getRem().foldStamp(forX.stamp(view), forY.stamp(view));
return canonical(null, forX, ConstantNode.forIntegerStamp(yStamp, -constY), zeroCheck, newStamp, view, tool);
return canonical(self, forX, ConstantNode.forIntegerStamp(yStamp, -constY), zeroCheck, newStamp, view, tool);
}
if (constY == 1) {
@ -104,10 +104,19 @@ public class SignedRemNode extends IntegerDivRemNode implements LIRLowerable {
}
}
}
return self != null ? self : new SignedRemNode(forX, forY, zeroCheck);
if (self != null && self.x == forX && self.y == forY) {
return self;
} else {
return new SignedRemNode(forX, forY, zeroCheck);
}
}
private static boolean allUsagesCompareAgainstZero(SignedRemNode self) {
if (self == null) {
// If the node was not yet created, then we do not know its usages yet.
return false;
}
int compareAgainstZero = 0;
int usageCount = self.getUsageCount();
for (int i = 0; i < usageCount; i++) {

View File

@ -33,6 +33,7 @@ import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
@ -44,6 +45,8 @@ import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
/**
* The {@code ArrayLength} instruction gets the length of an array.
@ -83,6 +86,9 @@ public final class ArrayLengthNode extends FixedWithNextNode implements Canonica
@Override
public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
if (forValue.isNullConstant()) {
return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
}
ValueNode length = readArrayLength(forValue, tool.getConstantReflection());
if (length != null) {
return length;

View File

@ -40,6 +40,7 @@ import org.graalvm.compiler.graph.spi.Simplifiable;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.LogicNode;
@ -140,6 +141,9 @@ public class LoadIndexedNode extends AccessIndexedNode implements Virtualizable,
@Override
public Node canonical(CanonicalizerTool tool) {
if (array().isNullConstant()) {
return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
}
ValueNode constant = tryConstantFold(array(), index(), tool.getMetaAccess(), tool.getConstantReflection());
if (constant != null) {
return constant;

View File

@ -60,7 +60,7 @@ public class NewInstanceNode extends AbstractNewObjectNode implements Virtualiza
protected NewInstanceNode(NodeClass<? extends NewInstanceNode> c, ResolvedJavaType type, boolean fillContents, FrameState stateBefore) {
super(c, StampFactory.objectNonNull(TypeReference.createExactTrusted(type)), fillContents, stateBefore);
assert !type.isArray() && !type.isInterface() && !type.isPrimitive() && !type.isAbstract();
assert !type.isArray() && !type.isInterface() && !type.isPrimitive() && !type.isAbstract() : type;
this.instanceClass = type;
}

View File

@ -27,10 +27,14 @@ package org.graalvm.compiler.nodes.java;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeCycles;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.ValueNode;
@ -39,13 +43,15 @@ import org.graalvm.compiler.nodes.spi.VirtualizerTool;
import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.ResolvedJavaField;
/**
* The {@code StoreFieldNode} represents a write to a static or instance field.
*/
@NodeInfo(nameTemplate = "StoreField#{p#field/s}")
public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable {
public final class StoreFieldNode extends AccessFieldNode implements StateSplit, Virtualizable, Canonicalizable {
public static final NodeClass<StoreFieldNode> TYPE = NodeClass.create(StoreFieldNode.class);
@Input ValueNode value;
@ -111,4 +117,12 @@ public final class StoreFieldNode extends AccessFieldNode implements StateSplit,
}
return super.estimatedNodeCycles();
}
@Override
public Node canonical(CanonicalizerTool tool) {
if (!field.isStatic() && object.isNullConstant()) {
return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
}
return this;
}
}

View File

@ -29,9 +29,13 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.ValueNode;
@ -43,6 +47,8 @@ import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaType;
@ -50,7 +56,7 @@ import jdk.vm.ci.meta.ResolvedJavaType;
* The {@code StoreIndexedNode} represents a write to an array element.
*/
@NodeInfo(cycles = CYCLES_8, size = SIZE_8)
public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable {
public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable, Canonicalizable {
public static final NodeClass<StoreIndexedNode> TYPE = NodeClass.create(StoreIndexedNode.class);
@ -110,4 +116,12 @@ public final class StoreIndexedNode extends AccessIndexedNode implements StateSp
public FrameState getState() {
return stateAfter;
}
@Override
public Node canonical(CanonicalizerTool tool) {
if (array().isNullConstant()) {
return new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException);
}
return this;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,4 +54,11 @@ public interface LoweringProvider {
// most platforms only support 32 and 64 bit compares
return 32;
}
/**
* Indicates whether the target platform supports bulk zeroing instruction.
*/
default boolean supportBulkZeroing() {
return false;
}
}

View File

@ -88,6 +88,7 @@ import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
import org.graalvm.compiler.nodes.extended.LoadHubNode;
import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.java.TypeSwitchNode;
import org.graalvm.compiler.nodes.spi.NodeWithState;
import org.graalvm.compiler.nodes.spi.StampInverter;
@ -364,7 +365,38 @@ public class ConditionalEliminationPhase extends BasePhase<PhaseContext> {
node.setCondition(LogicConstantNode.forBoolean(result, node.graph()), node.isNegated());
// Don't kill this branch immediately, see `processGuard`.
}
debug.log("Kill fixed guard guard");
if (guard instanceof DeoptimizingGuard && !node.isNegated() && !((DeoptimizingGuard) guard).isNegated()) {
LogicNode newCondition = ((DeoptimizingGuard) guard.asNode()).getCondition();
if (newCondition instanceof InstanceOfNode) {
InstanceOfNode inst = (InstanceOfNode) newCondition;
ValueNode originalValue = GraphUtil.skipPi(inst.getValue());
PiNode pi = null;
// Ensure that any Pi that's weaker than what the instanceof proves is
// replaced by one derived from the instanceof itself.
for (PiNode existing : guard.asNode().usages().filter(PiNode.class).snapshot()) {
if (!existing.isAlive()) {
continue;
}
if (originalValue != GraphUtil.skipPi(existing.object())) {
// Somehow these are unrelated values so leave it alone
continue;
}
// If the pi has a weaker stamp or the same stamp but a different input
// then replace it.
boolean strongerStamp = !existing.piStamp().join(inst.getCheckedStamp()).equals(inst.getCheckedStamp());
boolean differentStamp = !existing.piStamp().equals(inst.getCheckedStamp());
boolean differentObject = existing.object() != inst.getValue();
if (!strongerStamp && (differentStamp || differentObject)) {
if (pi == null) {
pi = graph.unique(new PiNode(inst.getValue(), inst.getCheckedStamp(), (ValueNode) guard));
}
existing.replaceAndDelete(pi);
}
}
}
}
debug.log("Kill fixed guard %s", node);
return true;
})) {
registerNewCondition(node.condition(), node.isNegated(), node);

View File

@ -91,7 +91,7 @@ public class BinaryGraphPrinter implements
public BinaryGraphPrinter(DebugContext ctx, SnippetReflectionProvider snippetReflection) throws IOException {
// @formatter:off
this.output = ctx.buildOutput(GraphOutput.newBuilder(this).
protocolVersion(6, 0).
protocolVersion(6, 1).
blocks(this).
elementsAndLocations(this, this).
types(this)

View File

@ -59,7 +59,13 @@ import sun.misc.Unsafe;
public class AArch64GraphBuilderPlugins {
public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks, boolean registerMathPlugins) {
public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks,
boolean registerMathPlugins) {
register(plugins, bytecodeProvider, explicitUnsafeNullChecks, registerMathPlugins, true);
}
public static void register(Plugins plugins, BytecodeProvider bytecodeProvider, boolean explicitUnsafeNullChecks,
boolean registerMathPlugins, boolean emitJDK9StringSubstitutions) {
InvocationPlugins invocationPlugins = plugins.getInvocationPlugins();
invocationPlugins.defer(new Runnable() {
@Override
@ -69,8 +75,10 @@ public class AArch64GraphBuilderPlugins {
if (registerMathPlugins) {
registerMathPlugins(invocationPlugins);
}
registerStringLatin1Plugins(invocationPlugins, bytecodeProvider);
registerStringUTF16Plugins(invocationPlugins, bytecodeProvider);
if (emitJDK9StringSubstitutions) {
registerStringLatin1Plugins(invocationPlugins, bytecodeProvider);
registerStringUTF16Plugins(invocationPlugins, bytecodeProvider);
}
registerUnsafePlugins(invocationPlugins, bytecodeProvider);
// This is temporarily disabled until we implement correct emitting of the CAS
// instructions of the proper width.

View File

@ -0,0 +1,73 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.replacements.nodes;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.memory.FixedAccessNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.word.Word;
import jdk.internal.vm.compiler.word.LocationIdentity;
/**
* Zeros a chunk of memory.
*/
@NodeInfo(nameTemplate = "ZeroMemory#{p#location/s}", allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_8, size = SIZE_8)
public class ZeroMemoryNode extends FixedAccessNode implements LIRLowerable {
public static final NodeClass<ZeroMemoryNode> TYPE = NodeClass.create(ZeroMemoryNode.class);
@Input ValueNode length;
public ZeroMemoryNode(ValueNode address, ValueNode length, LocationIdentity locationIdentity) {
this(OffsetAddressNode.create(address), length, locationIdentity, BarrierType.NONE);
}
public ZeroMemoryNode(AddressNode address, ValueNode length, LocationIdentity locationIdentity, BarrierType type) {
super(TYPE, address, locationIdentity, StampFactory.forVoid(), type);
this.length = length;
}
@Override
public void generate(NodeLIRBuilderTool gen) {
gen.getLIRGeneratorTool().getArithmetic().emitZeroMemory(gen.operand(getAddress()), gen.operand(length));
}
@Override
public boolean canNullCheck() {
return false;
}
@NodeIntrinsic
public static native void zero(Word address, long length, @ConstantNodeParameter LocationIdentity locationIdentity);
}

View File

@ -223,7 +223,7 @@ public final class GraphEffectList extends EffectList {
*/
public void replaceAtUsages(ValueNode node, ValueNode replacement, FixedNode insertBefore) {
assert node != null && replacement != null : node + " " + replacement;
assert node.stamp(NodeView.DEFAULT).isCompatible(replacement.stamp(NodeView.DEFAULT)) : "Replacement node stamp not compatible " + node.stamp(NodeView.DEFAULT) + " vs " +
assert !node.hasUsages() || node.stamp(NodeView.DEFAULT).isCompatible(replacement.stamp(NodeView.DEFAULT)) : "Replacement node stamp not compatible " + node.stamp(NodeView.DEFAULT) + " vs " +
replacement.stamp(NodeView.DEFAULT);
add("replace at usages", (graph, obsoleteNodes) -> {
assert node.isAlive();
@ -240,7 +240,7 @@ public final class GraphEffectList extends EffectList {
* to improve the stamp information of the read. Such a read might later be replaced
* with a read with a less precise stamp.
*/
if (!node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) {
if (node.hasUsages() && !node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) {
replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT)));
}
node.replaceAtUsages(replacementNode);

View File

@ -75,6 +75,9 @@ abstract class GraphProtocol<Graph, Node, NodeClass, Edges, Block, ResolvedJavaM
private static final byte[] MAGIC_BYTES = {'B', 'I', 'G', 'V'};
private static final int MAJOR_VERSION = 6;
private static final int MINOR_VERSION = 1;
private final ConstantPool constantPool;
private final ByteBuffer buffer;
private final WritableByteChannel channel;
@ -84,7 +87,7 @@ abstract class GraphProtocol<Graph, Node, NodeClass, Edges, Block, ResolvedJavaM
private boolean printing;
GraphProtocol(WritableByteChannel channel, int major, int minor, boolean embedded) throws IOException {
if (major > 6 || (major == 6 && minor > 0)) {
if (major > MAJOR_VERSION || (major == MAJOR_VERSION && minor > MINOR_VERSION)) {
throw new IllegalArgumentException("Unrecognized version " + major + "." + minor);
}
this.versionMajor = major;

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package micro.benchmarks;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Threads;
import org.openjdk.jmh.annotations.Warmup;
/**
* Benchmarks cost of ArrayList.
*/
public class ArrayAllocationBenchmark extends BenchmarkBase {
@State(Scope.Benchmark)
public static class ThreadState {
@Param({"128", "256", "512", "1024", "2048", "4096", "8192", "16384", "32768", "65536", "131072"}) int size;
byte[] result;
}
@Benchmark
@Threads(8)
@Warmup(iterations = 10)
public void arrayAllocate(ThreadState state) {
state.result = new byte[state.size];
}
}