8222665: Update Graal
Reviewed-by: kvn
This commit is contained in:
parent
0ff8db34ca
commit
69647ce061
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user