mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-17 22:05:31 +00:00
8235927: Update Graal
Reviewed-by: kvn
This commit is contained in:
parent
cfddf53c01
commit
261f4bffae
@ -31,6 +31,7 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -43,6 +44,7 @@ import jdk.tools.jaotc.binformat.pecoff.JPECoffRelocObject;
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
|
||||
|
||||
/**
|
||||
* A format-agnostic container class that holds various components of a binary.
|
||||
@ -67,6 +69,8 @@ public final class BinaryContainer implements SymbolTable {
|
||||
|
||||
private final int codeEntryAlignment;
|
||||
|
||||
private final boolean threadLocalHandshakes;
|
||||
|
||||
/**
|
||||
* Container holding code bits and any other related information.
|
||||
*/
|
||||
@ -292,6 +296,8 @@ public final class BinaryContainer implements SymbolTable {
|
||||
|
||||
this.codeEntryAlignment = graalHotSpotVMConfig.codeEntryAlignment;
|
||||
|
||||
this.threadLocalHandshakes = graalHotSpotVMConfig.threadLocalHandshakes;
|
||||
|
||||
// Section unique name is limited to 8 characters due to limitation on Windows.
|
||||
// Name could be longer but only first 8 characters are stored on Windows.
|
||||
|
||||
@ -350,6 +356,12 @@ public final class BinaryContainer implements SymbolTable {
|
||||
// @formatter:on
|
||||
// @Checkstyle: resume
|
||||
|
||||
if (JavaVersionUtil.JAVA_SPEC < 14) {
|
||||
// See JDK-8220049. Thread local handshakes are on by default since JDK14, the command line option has been removed.
|
||||
booleanFlags = Arrays.copyOf(booleanFlags, booleanFlags.length + 1);
|
||||
booleanFlags[booleanFlags.length - 1] = graalHotSpotVMConfig.threadLocalHandshakes;
|
||||
}
|
||||
|
||||
byte[] booleanFlagsAsBytes = flagsToByteArray(booleanFlags);
|
||||
int size0 = configContainer.getByteStreamSize();
|
||||
|
||||
@ -449,6 +461,10 @@ public final class BinaryContainer implements SymbolTable {
|
||||
return codeEntryAlignment;
|
||||
}
|
||||
|
||||
public boolean getThreadLocalHandshakes() {
|
||||
return threadLocalHandshakes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the global AOT symbol associated with the function name.
|
||||
*
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -56,8 +56,11 @@ final class MarkProcessor {
|
||||
break;
|
||||
case POLL_FAR:
|
||||
case POLL_RETURN_FAR:
|
||||
// skip relocation
|
||||
break;
|
||||
if (binaryContainer.getThreadLocalHandshakes()) {
|
||||
// skip relocation
|
||||
break;
|
||||
}
|
||||
// fallthrough
|
||||
case CARD_TABLE_ADDRESS:
|
||||
case HEAP_TOP_ADDRESS:
|
||||
case HEAP_END_ADDRESS:
|
||||
|
||||
@ -29,16 +29,13 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.ParameterNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraalDirectives#blackhole}.
|
||||
@ -134,8 +131,8 @@ public class BlackholeDirectiveTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -33,9 +33,6 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.graph.Node;
|
||||
@ -46,11 +43,11 @@ import org.graalvm.compiler.nodes.ReturnNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
|
||||
public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
|
||||
|
||||
@ -244,8 +241,8 @@ public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -29,9 +29,6 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
@ -40,8 +37,8 @@ import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.calc.AddNode;
|
||||
import org.graalvm.compiler.nodes.calc.ConditionalNode;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraalDirectives#opaque}.
|
||||
@ -133,8 +130,8 @@ public class OpaqueDirectiveTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
package org.graalvm.compiler.asm.aarch64.test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64Address;
|
||||
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class AArch64LoadStoreMergingAssemblerTest extends GraalTest {
|
||||
private Register base;
|
||||
private Register rt1;
|
||||
private Register rt2;
|
||||
|
||||
@Before
|
||||
public void checkAArch64() {
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
assumeTrue("skipping non AArch64 specific test", target.arch instanceof AArch64);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setupEnvironment() {
|
||||
base = AArch64.sp;
|
||||
rt1 = AArch64.r1;
|
||||
rt2 = AArch64.r2;
|
||||
}
|
||||
|
||||
private abstract static class AArch64LoadStoreCodeGen {
|
||||
protected AArch64MacroAssembler masm1;
|
||||
protected AArch64MacroAssembler masm2;
|
||||
|
||||
AArch64LoadStoreCodeGen() {
|
||||
TargetDescription target = JVMCI.getRuntime().getHostJVMCIBackend().getTarget();
|
||||
masm1 = new AArch64MacroAssembler(target);
|
||||
masm2 = new AArch64MacroAssembler(target);
|
||||
}
|
||||
|
||||
void emitScaledImmLdr(int size, Register rt, Register base, int imm12) {
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12);
|
||||
masm2.ldr(size, rt, address);
|
||||
}
|
||||
|
||||
void emitUnscaledImmLdr(int size, Register rt, Register base, int imm9) {
|
||||
AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9);
|
||||
masm2.ldr(size, rt, address1);
|
||||
}
|
||||
|
||||
void emitScaledImmStr(int size, Register rt, Register base, int imm12) {
|
||||
AArch64Address address = AArch64Address.createScaledImmediateAddress(base, imm12);
|
||||
masm2.str(size, rt, address);
|
||||
}
|
||||
|
||||
void emitUnscaledImmStr(int size, Register rt, Register base, int imm9) {
|
||||
AArch64Address address1 = AArch64Address.createUnscaledImmediateAddress(base, imm9);
|
||||
masm2.str(size, rt, address1);
|
||||
}
|
||||
|
||||
void emitScaledLdp(int size, Register rt1, Register rt2, Register base, int imm7) {
|
||||
AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7);
|
||||
masm1.ldp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitScaledStp(int size, Register rt1, Register rt2, Register base, int imm7) {
|
||||
AArch64Address mergeAddress = AArch64Address.createScaledImmediateAddress(base, imm7);
|
||||
masm1.stp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitUnscaledLdp(int size, Register rt1, Register rt2, Register base, int imm) {
|
||||
AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm);
|
||||
masm1.ldp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
void emitUnscaledStp(int size, Register rt1, Register rt2, Register base, int imm) {
|
||||
AArch64Address mergeAddress = AArch64Address.createUnscaledImmediateAddress(base, imm);
|
||||
masm1.stp(size, rt1, rt2, mergeAddress);
|
||||
}
|
||||
|
||||
abstract void checkAssembly();
|
||||
}
|
||||
|
||||
private static class AArch64LoadStoreMergingCodeGen extends AArch64LoadStoreCodeGen {
|
||||
AArch64LoadStoreMergingCodeGen() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkAssembly() {
|
||||
byte[] expected = masm1.close(false);
|
||||
byte[] actual = masm2.close(false);
|
||||
assertArrayEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad64BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(64, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 5);
|
||||
codeGen.emitScaledLdp(64, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad32BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 5);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 4);
|
||||
codeGen.emitScaledLdp(32, rt2, rt1, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore64BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmStr(64, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(64, rt2, base, 5);
|
||||
codeGen.emitScaledStp(64, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore32BitsScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmStr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(32, rt2, base, 5);
|
||||
codeGen.emitScaledStp(32, rt1, rt2, base, 4);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad64BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(64, rt1, base, -32);
|
||||
codeGen.emitUnscaledImmLdr(64, rt2, base, -24);
|
||||
codeGen.emitUnscaledLdp(64, rt1, rt2, base, -32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad32BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 248);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 252);
|
||||
codeGen.emitUnscaledLdp(32, rt1, rt2, base, 248);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore64BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(64, rt1, base, 32);
|
||||
codeGen.emitUnscaledImmStr(64, rt2, base, 40);
|
||||
codeGen.emitUnscaledStp(64, rt1, rt2, base, 32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStore32BitsUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(32, rt1, base, 32);
|
||||
codeGen.emitUnscaledImmStr(32, rt2, base, 36);
|
||||
codeGen.emitUnscaledStp(32, rt1, rt2, base, 32);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadUnscaledScaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 48);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 13);
|
||||
codeGen.emitScaledLdp(32, rt1, rt2, base, 12);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadScaledUnscaledImmAddress() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 13);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 48);
|
||||
codeGen.emitUnscaledLdp(32, rt2, rt1, base, 48);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadMaxAlignedOffset() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(64, rt1, base, 62);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 63);
|
||||
codeGen.emitScaledLdp(64, rt1, rt2, base, 62);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreMinAlignedOffest() {
|
||||
AArch64LoadStoreMergingCodeGen codeGen = new AArch64LoadStoreMergingCodeGen();
|
||||
codeGen.emitUnscaledImmStr(32, rt1, base, -256);
|
||||
codeGen.emitUnscaledImmStr(32, rt2, base, -252);
|
||||
codeGen.emitUnscaledStp(32, rt1, rt2, base, -256);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
// All the following tests are the negative ones that ldr/str will not be merged to ldp/stp.
|
||||
private static class AArch64LoadStoreNotMergingCodeGen extends AArch64LoadStoreCodeGen {
|
||||
AArch64LoadStoreNotMergingCodeGen() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
void checkAssembly() {
|
||||
boolean isMerged = masm2.isImmLoadStoreMerged();
|
||||
masm2.close(false);
|
||||
Assert.assertFalse(isMerged);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentBase() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, AArch64.r3, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentSize() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(64, rt2, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameRt() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDependencyLdrs() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, rt1, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, rt1, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnalignedOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitUnscaledImmLdr(32, rt1, base, 34);
|
||||
codeGen.emitUnscaledImmLdr(32, rt2, base, 38);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUncontinuousOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 6);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGreaterThanMaxOffset() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 66);
|
||||
codeGen.emitScaledImmLdr(32, rt2, base, 67);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLdrStr() {
|
||||
AArch64LoadStoreNotMergingCodeGen codeGen = new AArch64LoadStoreNotMergingCodeGen();
|
||||
codeGen.emitScaledImmLdr(32, rt1, base, 4);
|
||||
codeGen.emitScaledImmStr(32, rt2, base, 5);
|
||||
codeGen.checkAssembly();
|
||||
}
|
||||
}
|
||||
@ -1301,6 +1301,16 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert ldp/stp at the specified position.
|
||||
*/
|
||||
protected void insertLdpStp(int size, Instruction instr, Register rt, Register rt2, Register base, int offset, int position) {
|
||||
InstructionType type = generalFromSize(size);
|
||||
int scaledOffset = maskField(7, offset);
|
||||
int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(base) | rt(rt);
|
||||
emitInt(memop | LoadStorePairOp | (0b010 << 23), position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Pair of Registers calculates an address from a base register value and an immediate
|
||||
* offset, and stores two 32-bit words or two 64-bit doublewords to the calculated address, from
|
||||
@ -1308,7 +1318,7 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
*/
|
||||
public void ldp(int size, Register rt, Register rt2, AArch64Address address) {
|
||||
assert size == 32 || size == 64;
|
||||
loadStorePairInstruction(LDP, rt, rt2, address, generalFromSize(size));
|
||||
loadStorePairInstruction(size, LDP, rt, rt2, address);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1318,15 +1328,24 @@ public abstract class AArch64Assembler extends Assembler {
|
||||
*/
|
||||
public void stp(int size, Register rt, Register rt2, AArch64Address address) {
|
||||
assert size == 32 || size == 64;
|
||||
loadStorePairInstruction(STP, rt, rt2, address, generalFromSize(size));
|
||||
loadStorePairInstruction(size, STP, rt, rt2, address);
|
||||
}
|
||||
|
||||
private void loadStorePairInstruction(Instruction instr, Register rt, Register rt2, AArch64Address address, InstructionType type) {
|
||||
int scaledOffset = maskField(7, address.getImmediateRaw()); // LDP/STP use a 7-bit scaled
|
||||
// offset
|
||||
private void loadStorePairInstruction(int size, Instruction instr, Register rt, Register rt2, AArch64Address address) {
|
||||
InstructionType type = generalFromSize(size);
|
||||
// LDP/STP uses a 7-bit scaled offset
|
||||
int offset = address.getImmediateRaw();
|
||||
if (address.getAddressingMode() == AddressingMode.IMMEDIATE_UNSCALED) {
|
||||
int sizeInBytes = size / Byte.SIZE;
|
||||
long mask = sizeInBytes - 1;
|
||||
assert (offset & mask) == 0 : "LDP/STP only supports aligned offset.";
|
||||
offset = offset / sizeInBytes;
|
||||
}
|
||||
int scaledOffset = maskField(7, offset);
|
||||
int memop = type.encoding | instr.encoding | scaledOffset << LoadStorePairImm7Offset | rt2(rt2) | rn(address.getBase()) | rt(rt);
|
||||
switch (address.getAddressingMode()) {
|
||||
case IMMEDIATE_SCALED:
|
||||
case IMMEDIATE_UNSCALED:
|
||||
emitInt(memop | LoadStorePairOp | (0b010 << 23));
|
||||
break;
|
||||
case IMMEDIATE_POST_INDEXED:
|
||||
|
||||
@ -35,6 +35,8 @@ import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.EXT
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_SCALED;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.IMMEDIATE_UNSCALED;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode.REGISTER_OFFSET;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.STP;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_BASE;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.ADD_TO_INDEX;
|
||||
import static org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler.AddressGenerationPlan.WorkPlan.NO_WORK;
|
||||
@ -55,6 +57,10 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
// Points to the next free scratch register
|
||||
private int nextFreeScratchRegister = 0;
|
||||
|
||||
// Last immediate ldr/str instruction, which is a candidate to be merged.
|
||||
private AArch64MemoryEncoding lastImmLoadStoreEncoding;
|
||||
private boolean isImmLoadStoreMerged = false;
|
||||
|
||||
public AArch64MacroAssembler(TargetDescription target) {
|
||||
super(target);
|
||||
}
|
||||
@ -81,6 +87,43 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
return scratchRegister[nextFreeScratchRegister++];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(Label l) {
|
||||
super.bind(l);
|
||||
// Clear last ldr/str instruction to prevent the labeled ldr/str being merged.
|
||||
lastImmLoadStoreEncoding = null;
|
||||
}
|
||||
|
||||
private static class AArch64MemoryEncoding {
|
||||
private AArch64Address address;
|
||||
private Register result;
|
||||
private int sizeInBytes;
|
||||
private int position;
|
||||
private boolean isStore;
|
||||
|
||||
AArch64MemoryEncoding(int sizeInBytes, Register result, AArch64Address address, boolean isStore, int position) {
|
||||
this.sizeInBytes = sizeInBytes;
|
||||
this.result = result;
|
||||
this.address = address;
|
||||
this.isStore = isStore;
|
||||
this.position = position;
|
||||
AArch64Address.AddressingMode addressingMode = address.getAddressingMode();
|
||||
assert addressingMode == IMMEDIATE_SCALED || addressingMode == IMMEDIATE_UNSCALED : "Invalid address mode" +
|
||||
"to merge: " + addressingMode;
|
||||
}
|
||||
|
||||
Register getBase() {
|
||||
return address.getBase();
|
||||
}
|
||||
|
||||
int getOffset() {
|
||||
if (address.getAddressingMode() == IMMEDIATE_UNSCALED) {
|
||||
return address.getImmediateRaw();
|
||||
}
|
||||
return address.getImmediate() * sizeInBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies what actions have to be taken to turn an arbitrary address of the form
|
||||
* {@code base + displacement [+ index [<< scale]]} into a valid AArch64Address.
|
||||
@ -321,6 +364,132 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryMerge(int sizeInBytes, Register rt, AArch64Address address, boolean isStore) {
|
||||
isImmLoadStoreMerged = false;
|
||||
if (lastImmLoadStoreEncoding == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only immediate scaled/unscaled address can be merged.
|
||||
// Pre-index and post-index mode can't be merged.
|
||||
AArch64Address.AddressingMode addressMode = address.getAddressingMode();
|
||||
if (addressMode != IMMEDIATE_SCALED && addressMode != IMMEDIATE_UNSCALED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only the two adjacent ldrs/strs can be merged.
|
||||
int lastPosition = position() - 4;
|
||||
if (lastPosition < 0 || lastPosition != lastImmLoadStoreEncoding.position) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isStore != lastImmLoadStoreEncoding.isStore) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only merge ldr/str with the same size of 32bits or 64bits.
|
||||
if (sizeInBytes != lastImmLoadStoreEncoding.sizeInBytes || (sizeInBytes != 4 && sizeInBytes != 8)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Base register must be the same one.
|
||||
Register curBase = address.getBase();
|
||||
Register preBase = lastImmLoadStoreEncoding.getBase();
|
||||
if (!curBase.equals(preBase)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the two ldrs have the same rt register, they can't be merged.
|
||||
// If the two ldrs have dependence, they can't be merged.
|
||||
Register curRt = rt;
|
||||
Register preRt = lastImmLoadStoreEncoding.result;
|
||||
if (!isStore && (curRt.equals(preRt) || preRt.equals(curBase))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Offset checking. Offsets of the two ldrs/strs must be continuous.
|
||||
int curOffset = address.getImmediateRaw();
|
||||
if (addressMode == IMMEDIATE_SCALED) {
|
||||
curOffset = curOffset * sizeInBytes;
|
||||
}
|
||||
int preOffset = lastImmLoadStoreEncoding.getOffset();
|
||||
if (Math.abs(curOffset - preOffset) != sizeInBytes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Offset must be in ldp/stp instruction's range.
|
||||
int offset = curOffset > preOffset ? preOffset : curOffset;
|
||||
int minOffset = -64 * sizeInBytes;
|
||||
int maxOffset = 63 * sizeInBytes;
|
||||
if (offset < minOffset || offset > maxOffset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Alignment checking.
|
||||
if (isFlagSet(AArch64.Flag.AvoidUnalignedAccesses)) {
|
||||
// AArch64 sp is 16-bytes aligned.
|
||||
if (curBase.equals(sp)) {
|
||||
long pairMask = sizeInBytes * 2 - 1;
|
||||
if ((offset & pairMask) != 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// If base is not sp, we can't guarantee the access is aligned.
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// ldp/stp only supports sizeInBytes aligned offset.
|
||||
long mask = sizeInBytes - 1;
|
||||
if ((curOffset & mask) != 0 || (preOffset & mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Merge two ldrs/strs to ldp/stp.
|
||||
Register rt1 = preRt;
|
||||
Register rt2 = curRt;
|
||||
if (curOffset < preOffset) {
|
||||
rt1 = curRt;
|
||||
rt2 = preRt;
|
||||
}
|
||||
int immediate = offset / sizeInBytes;
|
||||
Instruction instruction = isStore ? STP : LDP;
|
||||
int size = sizeInBytes * Byte.SIZE;
|
||||
insertLdpStp(size, instruction, rt1, rt2, curBase, immediate, lastPosition);
|
||||
lastImmLoadStoreEncoding = null;
|
||||
isImmLoadStoreMerged = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to merge two continuous ldr/str to one ldp/stp. If this current ldr/str is not merged,
|
||||
* save it as the last ldr/str.
|
||||
*/
|
||||
private boolean tryMergeLoadStore(int srcSize, Register rt, AArch64Address address, boolean isStore) {
|
||||
int sizeInBytes = srcSize / Byte.SIZE;
|
||||
if (tryMerge(sizeInBytes, rt, address, isStore)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Save last ldr/str if it is not merged.
|
||||
AArch64Address.AddressingMode addressMode = address.getAddressingMode();
|
||||
if (addressMode == IMMEDIATE_SCALED || addressMode == IMMEDIATE_UNSCALED) {
|
||||
if (addressMode == IMMEDIATE_UNSCALED) {
|
||||
long mask = sizeInBytes - 1;
|
||||
int offset = address.getImmediateRaw();
|
||||
if ((offset & mask) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
lastImmLoadStoreEncoding = new AArch64MemoryEncoding(sizeInBytes, rt, address, isStore, position());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isImmLoadStoreMerged() {
|
||||
return isImmLoadStoreMerged;
|
||||
}
|
||||
|
||||
public void movx(Register dst, Register src) {
|
||||
mov(64, dst, src);
|
||||
}
|
||||
@ -505,7 +674,7 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
assert targetSize == 32 || targetSize == 64;
|
||||
assert srcSize <= targetSize;
|
||||
if (targetSize == srcSize) {
|
||||
super.ldr(srcSize, rt, address);
|
||||
ldr(srcSize, rt, address);
|
||||
} else {
|
||||
super.ldrs(targetSize, srcSize, rt, address);
|
||||
}
|
||||
@ -521,7 +690,25 @@ public class AArch64MacroAssembler extends AArch64Assembler {
|
||||
*/
|
||||
@Override
|
||||
public void ldr(int srcSize, Register rt, AArch64Address address) {
|
||||
super.ldr(srcSize, rt, address);
|
||||
// Try to merge two adjacent loads into one ldp.
|
||||
if (!tryMergeLoadStore(srcSize, rt, address, false)) {
|
||||
super.ldr(srcSize, rt, address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores register rt into memory pointed by address.
|
||||
*
|
||||
* @param destSize number of bits written to memory. Must be 8, 16, 32 or 64.
|
||||
* @param rt general purpose register. May not be null or stackpointer.
|
||||
* @param address all addressing modes allowed. May not be null.
|
||||
*/
|
||||
@Override
|
||||
public void str(int destSize, Register rt, AArch64Address address) {
|
||||
// Try to merge two adjacent stores into one stp.
|
||||
if (!tryMergeLoadStore(destSize, rt, address, true)) {
|
||||
super.str(destSize, rt, address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, Arm Limited and affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
package org.graalvm.compiler.core.aarch64.test;
|
||||
|
||||
import jdk.vm.ci.aarch64.AArch64;
|
||||
import jdk.vm.ci.runtime.JVMCI;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
public class AArch64PairLoadStoreTest extends GraalCompilerTest {
|
||||
|
||||
@Before
|
||||
public void checkAArch64() {
|
||||
assumeTrue("skipping AArch64 specific test", JVMCI.getRuntime().getHostJVMCIBackend().getTarget().arch instanceof AArch64);
|
||||
}
|
||||
|
||||
public static long parameterSpill(long v1, long v2, long v3, long v4, long v5, long v6, long v7, long v8, long v9, long v10) {
|
||||
long value0 = v1 + v2 + v3 + v4 + v5 + v6 + v7 + v8;
|
||||
long value1 = v9 + v10;
|
||||
return value0 + value1;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterSpill() {
|
||||
test("parameterSpill", 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L);
|
||||
}
|
||||
|
||||
static class A {
|
||||
static String a = "adsaf";
|
||||
|
||||
static String b = "asfgsfd";
|
||||
|
||||
static int c;
|
||||
|
||||
static int d;
|
||||
}
|
||||
|
||||
public static int pairLoadStaticFields() {
|
||||
if (A.a == null || A.a != A.b) {
|
||||
return A.b.length();
|
||||
}
|
||||
return A.a.length();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPairLoadStaticFields() {
|
||||
test("pairLoadStaticFields");
|
||||
}
|
||||
|
||||
public static int pairStoreStaticFields(int m, int n) {
|
||||
A.c = m;
|
||||
A.d = n;
|
||||
return A.c + A.d;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPairStoreStaticFields() {
|
||||
test("pairStoreStaticFields", 1, 2);
|
||||
}
|
||||
}
|
||||
@ -116,6 +116,11 @@ public abstract class UnsafeArrayTypeWriter implements TypeWriter {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public final byte[] toArray() {
|
||||
byte[] result = new byte[TypeConversion.asS4(getBytesWritten())];
|
||||
return toArray(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void putS1(long value) {
|
||||
long offset = writeOffset(Byte.BYTES);
|
||||
|
||||
@ -190,6 +190,13 @@ public class CheckGraalInvariants extends GraalCompilerTest {
|
||||
public boolean shouldVerifyFoldableMethods() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes edits to the list of verifiers to be run.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected void updateVerifiers(List<VerifyPhase<CoreProviders>> verifiers) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -304,6 +311,8 @@ public class CheckGraalInvariants extends GraalCompilerTest {
|
||||
verifiers.add(foldableMethodsVerifier);
|
||||
}
|
||||
|
||||
tool.updateVerifiers(verifiers);
|
||||
|
||||
for (Method m : BadUsageWithEquals.class.getDeclaredMethods()) {
|
||||
ResolvedJavaMethod method = metaAccess.lookupJavaMethod(m);
|
||||
try (DebugContext debug = DebugContext.create(options, DebugHandlersFactory.LOADER)) {
|
||||
|
||||
@ -32,13 +32,11 @@ import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.spi.CoreProviders;
|
||||
import org.graalvm.compiler.nodes.spi.LoweringTool;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
|
||||
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
|
||||
import org.graalvm.compiler.phases.common.LoweringPhase;
|
||||
import org.graalvm.compiler.phases.schedule.SchedulePhase;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
@ -55,8 +53,8 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
|
||||
* code based on method profiles.
|
||||
*/
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
protected void testConditionalElimination(String snippet, String referenceSnippet) {
|
||||
|
||||
@ -45,7 +45,6 @@ import org.graalvm.compiler.nodes.spi.LIRLowerable;
|
||||
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
|
||||
import org.graalvm.compiler.nodes.util.GraphUtil;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
@ -647,9 +646,9 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
// Don't convert unreached paths into Guard
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.NONE);
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
private Object[] argsToBind;
|
||||
|
||||
@ -54,6 +54,7 @@ import java.util.function.Supplier;
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
import org.graalvm.compiler.api.test.ModuleSupport;
|
||||
import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.core.CompilationPrinter;
|
||||
import org.graalvm.compiler.core.GraalCompiler;
|
||||
@ -126,7 +127,6 @@ import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
|
||||
import org.graalvm.compiler.runtime.RuntimeProvider;
|
||||
import org.graalvm.compiler.test.AddExports;
|
||||
import org.graalvm.compiler.test.GraalTest;
|
||||
import org.graalvm.compiler.api.test.ModuleSupport;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
@ -606,11 +606,21 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
return providers;
|
||||
}
|
||||
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
/**
|
||||
* Override the {@link OptimisticOptimizations} settings used for the test. This is called for
|
||||
* all the paths where the value is set so it is the proper place for a test override. Setting
|
||||
* it in other places can result in inconsistent values being used in other parts of the
|
||||
* compiler.
|
||||
*/
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL;
|
||||
}
|
||||
|
||||
protected final HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), getOptimisticOptimizations());
|
||||
}
|
||||
|
||||
protected MidTierContext getDefaultMidTierContext() {
|
||||
protected final MidTierContext getDefaultMidTierContext() {
|
||||
return new MidTierContext(getProviders(), getTargetProvider(), getOptimisticOptimizations(), null);
|
||||
}
|
||||
|
||||
@ -1081,10 +1091,6 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
return compile(installedCodeOwner, graph, new CompilationResult(compilationId), compilationId, options);
|
||||
}
|
||||
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a given method.
|
||||
*
|
||||
|
||||
@ -29,8 +29,6 @@ import org.graalvm.compiler.nodes.ReturnNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MergeCanonicalizerTest extends GraalCompilerTest {
|
||||
@ -39,8 +37,8 @@ public class MergeCanonicalizerTest extends GraalCompilerTest {
|
||||
* These tests assume all code paths are reachable so disable profile based dead code removal.
|
||||
*/
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
public static int staticField;
|
||||
|
||||
@ -33,6 +33,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.graalvm.compiler.options.OptionDescriptor;
|
||||
import org.graalvm.compiler.options.OptionDescriptors;
|
||||
@ -54,12 +55,19 @@ import org.objectweb.asm.Type;
|
||||
*/
|
||||
public class OptionsVerifierTest {
|
||||
|
||||
private static Set<String> WHITELIST = new TreeSet<>(Arrays.asList(//
|
||||
// Generated options delegating default values to PolyglotCompilerOptions
|
||||
"org.graalvm.compiler.truffle.compiler.SharedTruffleCompilerOptions"));
|
||||
|
||||
@Test
|
||||
public void verifyOptions() throws IOException {
|
||||
HashSet<Class<?>> checked = new HashSet<>();
|
||||
for (OptionDescriptors opts : OptionsParser.getOptionsLoader()) {
|
||||
for (OptionDescriptor desc : opts) {
|
||||
OptionsVerifier.checkClass(desc.getDeclaringClass(), desc, checked);
|
||||
Class<?> descDeclaringClass = desc.getDeclaringClass();
|
||||
if (!WHITELIST.contains(descDeclaringClass.getName())) {
|
||||
OptionsVerifier.checkClass(descDeclaringClass, desc, checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +48,7 @@ public abstract class SubprocessTest extends GraalCompilerTest {
|
||||
runnable.run();
|
||||
} else {
|
||||
List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
|
||||
vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions());
|
||||
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
|
||||
vmArgs.add("-D" + recursionPropName + "=true");
|
||||
configSubprocess(vmArgs);
|
||||
SubprocessUtil.Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName());
|
||||
|
||||
@ -110,7 +110,7 @@ public class VerifyDebugUsage extends VerifyPhase<CoreProviders> {
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList<? extends ValueNode> args, ResolvedJavaType stringType, int startArgIdx) {
|
||||
protected void verifyParameters(MethodCallTargetNode callTarget, StructuredGraph callerGraph, NodeInputList<? extends ValueNode> args, ResolvedJavaType stringType, int startArgIdx) {
|
||||
if (callTarget.targetMethod().isVarArgs() && args.get(args.count() - 1) instanceof NewArrayNode) {
|
||||
// unpack the arguments to the var args
|
||||
List<ValueNode> unpacked = new ArrayList<>(args.snapshot());
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -24,14 +24,11 @@
|
||||
|
||||
package org.graalvm.compiler.core.test.ea;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.code.SourceStackTraceBailoutException;
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PEAAssertionsTest extends GraalCompilerTest {
|
||||
|
||||
@ -39,8 +36,8 @@ public class PEAAssertionsTest extends GraalCompilerTest {
|
||||
* These tests assume all code paths are reachable so disable profile based dead code removal.
|
||||
*/
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
public static Object field;
|
||||
|
||||
@ -53,6 +53,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Formatter;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
@ -2161,6 +2162,18 @@ public final class DebugContext implements AutoCloseable {
|
||||
out.println();
|
||||
}
|
||||
|
||||
public Map<MetricKey, Long> getMetricsSnapshot() {
|
||||
Map<MetricKey, Long> res = new HashMap<>();
|
||||
for (MetricKey key : KeyRegistry.getKeys()) {
|
||||
int index = ((AbstractKey) key).getIndex();
|
||||
if (index < metricValues.length && metricValues[index] != 0) {
|
||||
long value = metricValues[index];
|
||||
res.put(key, value);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
private static <E extends Exception> E rethrowSilently(Class<E> type, Throwable ex) throws E {
|
||||
throw (E) ex;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -81,7 +81,11 @@ public class AArch64HotSpotSafepointOp extends AArch64LIRInstruction {
|
||||
}
|
||||
|
||||
public static void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register thread, Register scratch, LIRFrameState state) {
|
||||
emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state);
|
||||
if (config.threadLocalHandshakes) {
|
||||
emitThreadLocalPoll(crb, masm, config, onReturn, thread, scratch, state);
|
||||
} else {
|
||||
emitGlobalPoll(crb, masm, config, onReturn, scratch, state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void emitGlobalPoll(CompilationResultBuilder crb, AArch64MacroAssembler masm, GraalHotSpotVMConfig config, boolean onReturn, Register scratch, LIRFrameState state) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -67,7 +67,12 @@ public final class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
|
||||
this.state = state;
|
||||
this.config = config;
|
||||
this.thread = thread;
|
||||
temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind()));
|
||||
if (config.threadLocalHandshakes || isPollingPageFar(config) || ImmutableCode.getValue(tool.getOptions())) {
|
||||
temp = tool.getLIRGeneratorTool().newVariable(LIRKind.value(tool.getLIRGeneratorTool().target().arch.getWordKind()));
|
||||
} else {
|
||||
// Don't waste a register if it's unneeded
|
||||
temp = Value.ILLEGAL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,7 +81,11 @@ public final class AMD64HotSpotSafepointOp extends AMD64LIRInstruction {
|
||||
}
|
||||
|
||||
public static void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread, Register scratch) {
|
||||
emitThreadLocalPoll(crb, asm, config, atReturn, state, thread, scratch);
|
||||
if (config.threadLocalHandshakes) {
|
||||
emitThreadLocalPoll(crb, asm, config, atReturn, state, thread, scratch);
|
||||
} else {
|
||||
emitGlobalPoll(crb, asm, config, atReturn, state, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -106,7 +106,7 @@ public class BenchmarkCounterOverflowTest extends LIRTest {
|
||||
List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
|
||||
vmArgs.add("-XX:JVMCICounterSize=1");
|
||||
vmArgs.add("-Dgraal." + BenchmarkCounters.Options.AbortOnBenchmarkCounterOverflow.getName() + "=true");
|
||||
vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions());
|
||||
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
|
||||
vmArgs.add("-D" + SUBPROCESS_PROPERTY + "=true");
|
||||
|
||||
// Disable increment range checks (e.g. HotSpotCounterOp.checkIncrements())
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -47,7 +47,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
testAllocation("test1snippet", 1 , 0, 0);
|
||||
testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0);
|
||||
}
|
||||
|
||||
public static long test1snippet(long x) {
|
||||
@ -56,7 +56,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
testAllocation("test2snippet", 1, 0, 0);
|
||||
testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0);
|
||||
}
|
||||
|
||||
public static long test2snippet(long x) {
|
||||
@ -65,7 +65,7 @@ public class SPARCAllocatorTest extends AllocatorTest {
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
testAllocation("test3snippet", 3, 0, 0);
|
||||
testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0);
|
||||
}
|
||||
|
||||
public static long test3snippet(long x) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -75,7 +75,11 @@ public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
|
||||
|
||||
public static void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm, GraalHotSpotVMConfig config, boolean atReturn, LIRFrameState state, Register thread,
|
||||
Value safepointPollAddress) {
|
||||
emitThreadLocalPoll(crb, masm, config, atReturn, state, thread);
|
||||
if (config.threadLocalHandshakes) {
|
||||
emitThreadLocalPoll(crb, masm, config, atReturn, state, thread);
|
||||
} else {
|
||||
emitGlobalPoll(crb, masm, config, atReturn, state, asRegister(safepointPollAddress));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -113,10 +117,19 @@ public class SPARCHotSpotSafepointOp extends SPARCLIRInstruction {
|
||||
}
|
||||
|
||||
static AllocatableValue getSafepointAddressValue(SPARCHotSpotLIRGenerator gen) {
|
||||
return Value.ILLEGAL;
|
||||
if (gen.config.threadLocalHandshakes) {
|
||||
return Value.ILLEGAL;
|
||||
} else {
|
||||
return gen.newVariable(LIRKind.value(gen.target().arch.getWordKind()));
|
||||
}
|
||||
}
|
||||
|
||||
static void emitPrologue(SPARCHotSpotNodeLIRBuilder lir, SPARCHotSpotLIRGenerator gen) {
|
||||
if (!gen.config.threadLocalHandshakes) {
|
||||
AllocatableValue var = gen.getSafepointAddressValue();
|
||||
lir.append(new SPARCHotSpotSafepointOp.SPARCLoadSafepointPollAddress(var, gen.config));
|
||||
gen.append(((HotSpotDebugInfoBuilder) lir.getDebugInfoBuilder()).lockStack());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SPARCLoadSafepointPollAddress extends SPARCLIRInstruction {
|
||||
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
package org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import static org.graalvm.compiler.test.SubprocessUtil.getPackageOpeningOptions;
|
||||
import static org.graalvm.compiler.test.SubprocessUtil.getVMCommandLine;
|
||||
import static org.graalvm.compiler.test.SubprocessUtil.withoutDebuggerArguments;
|
||||
|
||||
@ -51,13 +50,6 @@ import org.junit.Test;
|
||||
*/
|
||||
public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
|
||||
private static List<String> join(List<String> l1, List<String> l2) {
|
||||
ArrayList<String> result = new ArrayList<>(l1.size() + l2.size());
|
||||
result.addAll(l1);
|
||||
result.addAll(l2);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests compilation requested by the VM.
|
||||
*/
|
||||
@ -167,11 +159,11 @@ public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
public void testTruffleCompilation1() throws IOException, InterruptedException {
|
||||
assumeManagementLibraryIsLoadable();
|
||||
testHelper(Collections.emptyList(),
|
||||
join(getPackageOpeningOptions(),
|
||||
Arrays.asList(
|
||||
"-Dgraal.CompilationFailureAction=ExitVM",
|
||||
"-Dgraal.TrufflePerformanceWarningsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1")),
|
||||
Arrays.asList(
|
||||
SubprocessUtil.PACKAGE_OPENING_OPTIONS,
|
||||
"-Dgraal.CompilationFailureAction=ExitVM",
|
||||
"-Dgraal.TrufflePerformanceWarningsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1"),
|
||||
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
|
||||
}
|
||||
|
||||
@ -184,11 +176,11 @@ public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
new Probe("Exiting VM due to TruffleCompilationExceptionsAreFatal=true", 1),
|
||||
};
|
||||
testHelper(Arrays.asList(probes),
|
||||
join(getPackageOpeningOptions(),
|
||||
Arrays.asList(
|
||||
"-Dgraal.CompilationFailureAction=Silent",
|
||||
"-Dgraal.TruffleCompilationExceptionsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1")),
|
||||
Arrays.asList(
|
||||
SubprocessUtil.PACKAGE_OPENING_OPTIONS,
|
||||
"-Dgraal.CompilationFailureAction=Silent",
|
||||
"-Dgraal.TruffleCompilationExceptionsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1"),
|
||||
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
|
||||
}
|
||||
|
||||
@ -202,11 +194,11 @@ public class CompilationWrapperTest extends GraalCompilerTest {
|
||||
new Probe("Exiting VM due to TrufflePerformanceWarningsAreFatal=true", 1),
|
||||
};
|
||||
testHelper(Arrays.asList(probes),
|
||||
join(getPackageOpeningOptions(),
|
||||
Arrays.asList(
|
||||
"-Dgraal.CompilationFailureAction=Silent",
|
||||
"-Dgraal.TrufflePerformanceWarningsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1:PermanentBailout")),
|
||||
Arrays.asList(
|
||||
SubprocessUtil.PACKAGE_OPENING_OPTIONS,
|
||||
"-Dgraal.CompilationFailureAction=Silent",
|
||||
"-Dgraal.TrufflePerformanceWarningsAreFatal=true",
|
||||
"-Dgraal.CrashAt=root test1:PermanentBailout"),
|
||||
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
|
||||
}
|
||||
|
||||
|
||||
@ -67,12 +67,13 @@ public class ReservedStackAccessTest extends HotSpotGraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void run() throws IOException, InterruptedException {
|
||||
Assume.assumeFalse("GR-19833", runtime().getVMConfig().osName.equals("windows"));
|
||||
Assume.assumeTrue(runtime().getVMConfig().enableStackReservedZoneAddress != 0);
|
||||
List<String> vmArgs = SubprocessUtil.withoutDebuggerArguments(SubprocessUtil.getVMCommandLine());
|
||||
vmArgs.add("-XX:+UseJVMCICompiler");
|
||||
vmArgs.add("-Dgraal.Inline=false");
|
||||
vmArgs.add("-XX:CompileCommand=exclude,java/util/concurrent/locks/AbstractOwnableSynchronizer.setExclusiveOwnerThread");
|
||||
vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions());
|
||||
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
|
||||
|
||||
// Avoid SOE in HotSpotJVMCIRuntime.adjustCompilationLevel
|
||||
vmArgs.add("-Dgraal.CompileGraalWithC1Only=false");
|
||||
|
||||
@ -96,6 +96,7 @@ public class GraalHotSpotVMConfig extends GraalHotSpotVMConfigBase {
|
||||
public final boolean useAESCTRIntrinsics = getFlag("UseAESCTRIntrinsics", Boolean.class, false);
|
||||
public final boolean useCRC32Intrinsics = getFlag("UseCRC32Intrinsics", Boolean.class);
|
||||
public final boolean useCRC32CIntrinsics = versioned.useCRC32CIntrinsics;
|
||||
public final boolean threadLocalHandshakes = versioned.threadLocalHandshakes;
|
||||
|
||||
private final boolean useMultiplyToLenIntrinsic = getFlag("UseMultiplyToLenIntrinsic", Boolean.class);
|
||||
private final boolean useSHA1Intrinsics = getFlag("UseSHA1Intrinsics", Boolean.class);
|
||||
|
||||
@ -89,4 +89,7 @@ final class GraalHotSpotVMConfigVersioned extends HotSpotVMConfigAccess {
|
||||
// JDK-8186777
|
||||
int classMirrorOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle");
|
||||
boolean classMirrorIsHandle = true;
|
||||
|
||||
// JDK-8220049
|
||||
boolean threadLocalHandshakes = true;
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -26,14 +26,11 @@ package org.graalvm.compiler.jtt.optimize;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import jdk.vm.ci.meta.DeoptimizationReason;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations;
|
||||
import org.graalvm.compiler.phases.OptimisticOptimizations.Optimization;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.DeoptimizationReason;
|
||||
|
||||
public class ConditionalElimination02 extends JTTTest {
|
||||
|
||||
@ -68,8 +65,8 @@ public class ConditionalElimination02 extends JTTTest {
|
||||
* These tests assume all code paths are reachable so disable profile based dead code removal.
|
||||
*/
|
||||
@Override
|
||||
protected HighTierContext getDefaultHighTierContext() {
|
||||
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
|
||||
protected OptimisticOptimizations getOptimisticOptimizations() {
|
||||
return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.RemoveNeverExecutedCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -255,10 +255,19 @@ public class AArch64Move {
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
if (state != null) {
|
||||
crb.recordImplicitException(masm.position(), state);
|
||||
}
|
||||
int prePosition = masm.position();
|
||||
emitMemAccess(crb, masm);
|
||||
if (state != null) {
|
||||
int implicitExceptionPosition = prePosition;
|
||||
// Adjust implicit exception position if this ldr/str has been merged to ldp/stp.
|
||||
if (kind.isInteger() && prePosition == masm.position() && masm.isImmLoadStoreMerged()) {
|
||||
implicitExceptionPosition = prePosition - 4;
|
||||
if (crb.isImplicitExceptionExist(implicitExceptionPosition)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
crb.recordImplicitException(implicitExceptionPosition, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -346,8 +355,17 @@ public class AArch64Move {
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
crb.recordImplicitException(masm.position(), state);
|
||||
int prePosition = masm.position();
|
||||
masm.ldr(64, zr, address.toAddress());
|
||||
int implicitExceptionPosition = prePosition;
|
||||
// Adjust implicit exception position if this ldr has been merged to ldp.
|
||||
if (prePosition == masm.position() && masm.isImmLoadStoreMerged()) {
|
||||
implicitExceptionPosition = prePosition - 4;
|
||||
if (crb.isImplicitExceptionExist(implicitExceptionPosition)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
crb.recordImplicitException(implicitExceptionPosition, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -72,9 +72,7 @@ public class AArch64Unary {
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
if (state != null) {
|
||||
crb.recordImplicitException(masm.position(), state);
|
||||
}
|
||||
int prePosition = masm.position();
|
||||
AArch64Address address = input.toAddress();
|
||||
Register dst = asRegister(result);
|
||||
if (isSigned) {
|
||||
@ -82,6 +80,18 @@ public class AArch64Unary {
|
||||
} else {
|
||||
masm.ldr(srcSize, dst, address);
|
||||
}
|
||||
|
||||
if (state != null) {
|
||||
int implicitExceptionPosition = prePosition;
|
||||
// Adjust implicit exception position if this ldr/str has been merged to ldp/stp.
|
||||
if (prePosition == masm.position() && masm.isImmLoadStoreMerged()) {
|
||||
implicitExceptionPosition = prePosition - 4;
|
||||
if (crb.isImplicitExceptionExist(implicitExceptionPosition)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
crb.recordImplicitException(implicitExceptionPosition, state);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -72,6 +72,7 @@ import jdk.vm.ci.code.StackSlot;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.code.site.ConstantReference;
|
||||
import jdk.vm.ci.code.site.DataSectionReference;
|
||||
import jdk.vm.ci.code.site.Infopoint;
|
||||
import jdk.vm.ci.code.site.InfopointReason;
|
||||
import jdk.vm.ci.code.site.Mark;
|
||||
import jdk.vm.ci.meta.Constant;
|
||||
@ -295,6 +296,16 @@ public class CompilationResultBuilder {
|
||||
assert info.exceptionEdge == null;
|
||||
}
|
||||
|
||||
public boolean isImplicitExceptionExist(int pcOffset) {
|
||||
List<Infopoint> infopoints = compilationResult.getInfopoints();
|
||||
for (Infopoint infopoint : infopoints) {
|
||||
if (infopoint.pcOffset == pcOffset && infopoint.reason == InfopointReason.IMPLICIT_EXCEPTION) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void recordDirectCall(int posBefore, int posAfter, InvokeTarget callTarget, LIRFrameState info) {
|
||||
DebugInfo debugInfo = info != null ? info.debugInfo() : null;
|
||||
compilationResult.recordCall(posBefore, posAfter - posBefore, callTarget, debugInfo, true);
|
||||
|
||||
@ -160,17 +160,70 @@ public class GraphDecoder {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Marker to distinguish the reasons for the creation of a loop scope during partial evaluation.
|
||||
*/
|
||||
public enum LoopScopeTrigger {
|
||||
/**
|
||||
* Start loop scope: creation triggered manually at the beginning of partial evaluation.
|
||||
*/
|
||||
START,
|
||||
|
||||
/**
|
||||
* Loop scope created for the next iteration of a loop if unrolling is enabled in the loop
|
||||
* explosion mode. See {@link LoopExplosionKind#unrollLoops()} for details. Loop unrolling
|
||||
* will merge loop end nodes for each iteration of the original loop.
|
||||
*/
|
||||
LOOP_BEGIN_UNROLLING,
|
||||
|
||||
/**
|
||||
* Loop scope created for the next iteration of a loop along a particular loop end node if
|
||||
* {@link LoopExplosionKind#duplicateLoopEnds()} is enabled and loops are exploded. This
|
||||
* means for every loop end we duplicate the next loop iteration of the original loop.
|
||||
*/
|
||||
LOOP_END_DUPLICATION,
|
||||
|
||||
/**
|
||||
* Loop scope created for a loop exit node if {@link LoopExplosionKind#duplicateLoopExits()}
|
||||
* is enabled, i.e., code after a loop exit is duplicated per loop exit node.
|
||||
*
|
||||
* Special case nested loops: For compilation units with nested loops where inner loops
|
||||
* continue loops at a level n -1 the partial evaluation algorithm will merge outer loops to
|
||||
* avoid loop explosion along loop end nodes (which would be the same as
|
||||
* {@link #LOOP_END_DUPLICATION}.
|
||||
*/
|
||||
LOOP_EXIT_DUPLICATION
|
||||
}
|
||||
|
||||
/** Decoding state maintained for each loop in the encoded graph. */
|
||||
protected static class LoopScope {
|
||||
public final MethodScope methodScope;
|
||||
public final LoopScope outer;
|
||||
public final int loopDepth;
|
||||
public final int loopIteration;
|
||||
|
||||
/**
|
||||
* Upcoming loop iterations during loop explosions that have not been processed yet. Only
|
||||
* used when {@link MethodScope#loopExplosion} is not {@link LoopExplosionKind#NONE}.
|
||||
* Creation trigger of this particular loop scope, i.e., the reason it was created.
|
||||
*/
|
||||
public Deque<LoopScope> nextIterations;
|
||||
final LoopScopeTrigger trigger;
|
||||
/**
|
||||
* Upcoming, not yet processed, loop iterations created in the context of code duplication
|
||||
* along loop exits. Only used when {@link MethodScope#loopExplosion} has
|
||||
* {@link LoopExplosionKind#duplicateLoopExits()} enabled.
|
||||
*/
|
||||
public Deque<LoopScope> nextIterationFromLoopExitDuplication;
|
||||
/**
|
||||
* Same as {@link #nextIterationFromLoopExitDuplication} except that upcoming iterations
|
||||
* have been created because the duplication of loop ends
|
||||
* {@link LoopExplosionKind#duplicateLoopEnds()} is enabled.
|
||||
*/
|
||||
public Deque<LoopScope> nextIterationFromLoopEndDuplication;
|
||||
/**
|
||||
* Same as {@link #nextIterationFromLoopExitDuplication} except that upcoming iterations
|
||||
* have been created because the unrolling of a loop with constant iteration count
|
||||
* {@link LoopExplosionKind#unrollLoops()} is enabled.
|
||||
*/
|
||||
public Deque<LoopScope> nextIterationsFromUnrolling;
|
||||
/**
|
||||
* Information about already processed loop iterations for state merging during loop
|
||||
* explosion. Only used when {@link MethodScope#loopExplosion} is
|
||||
@ -196,7 +249,9 @@ public class GraphDecoder {
|
||||
protected LoopScope(MethodScope methodScope) {
|
||||
this.methodScope = methodScope;
|
||||
this.outer = null;
|
||||
this.nextIterations = methodScope.loopExplosion.duplicateLoopExits() ? new ArrayDeque<>(2) : null;
|
||||
this.nextIterationFromLoopExitDuplication = methodScope.loopExplosion.duplicateLoopExits() || methodScope.loopExplosion.mergeLoops() ? new ArrayDeque<>(2) : null;
|
||||
this.nextIterationFromLoopEndDuplication = methodScope.loopExplosion.duplicateLoopEnds() ? new ArrayDeque<>(2) : null;
|
||||
this.nextIterationsFromUnrolling = methodScope.loopExplosion.unrollLoops() ? new ArrayDeque<>(2) : null;
|
||||
this.loopDepth = 0;
|
||||
this.loopIteration = 0;
|
||||
this.iterationStates = null;
|
||||
@ -205,15 +260,21 @@ public class GraphDecoder {
|
||||
this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId);
|
||||
this.createdNodes = new Node[nodeCount];
|
||||
this.initialCreatedNodes = null;
|
||||
this.trigger = LoopScopeTrigger.START;
|
||||
}
|
||||
|
||||
protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes,
|
||||
Deque<LoopScope> nextIterations, EconomicMap<LoopExplosionState, LoopExplosionState> iterationStates) {
|
||||
protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, LoopScopeTrigger trigger, Node[] initialCreatedNodes, Node[] createdNodes,
|
||||
Deque<LoopScope> nextIterationFromLoopExitDuplication,
|
||||
Deque<LoopScope> nextIterationFromLoopEndDuplication,
|
||||
Deque<LoopScope> nextIterationsFromUnrolling, EconomicMap<LoopExplosionState, LoopExplosionState> iterationStates) {
|
||||
this.methodScope = methodScope;
|
||||
this.outer = outer;
|
||||
this.loopDepth = loopDepth;
|
||||
this.loopIteration = loopIteration;
|
||||
this.nextIterations = nextIterations;
|
||||
this.trigger = trigger;
|
||||
this.nextIterationFromLoopExitDuplication = nextIterationFromLoopExitDuplication;
|
||||
this.nextIterationFromLoopEndDuplication = nextIterationFromLoopEndDuplication;
|
||||
this.nextIterationsFromUnrolling = nextIterationsFromUnrolling;
|
||||
this.iterationStates = iterationStates;
|
||||
this.loopBeginOrderId = loopBeginOrderId;
|
||||
this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId);
|
||||
@ -223,7 +284,41 @@ public class GraphDecoder {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId);
|
||||
return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId) + " triggered by " + trigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if iterations generated when decoding this loop have yet to be processed.
|
||||
*
|
||||
* @return {@code true} if there are iterations to be decoded, {@code false} else
|
||||
*/
|
||||
public boolean hasIterationsToProcess() {
|
||||
return nextIterationFromLoopEndDuplication != null && !nextIterationFromLoopEndDuplication.isEmpty() ||
|
||||
nextIterationFromLoopExitDuplication != null && !nextIterationFromLoopExitDuplication.isEmpty() ||
|
||||
nextIterationsFromUnrolling != null && !nextIterationsFromUnrolling.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the next iteration yet to be processed that has been created in the context of
|
||||
* decoding this loop scope.
|
||||
*
|
||||
* @param remove determines if the query of the next iteration should remove it from the
|
||||
* list of iterations to be processed
|
||||
* @return the next {@link LoopScope} to be processed that has been created in the context
|
||||
* of decoding this loop scope. Note that the order is not necessarily reflecting
|
||||
* the number of loop iterations.
|
||||
*/
|
||||
public LoopScope getNextIterationToProcess(boolean remove) {
|
||||
if (nextIterationFromLoopEndDuplication != null && !nextIterationFromLoopEndDuplication.isEmpty()) {
|
||||
return remove ? nextIterationFromLoopEndDuplication.removeFirst() : nextIterationFromLoopEndDuplication.peekFirst();
|
||||
}
|
||||
if (nextIterationFromLoopExitDuplication != null && !nextIterationFromLoopExitDuplication.isEmpty()) {
|
||||
return remove ? nextIterationFromLoopExitDuplication.removeFirst() : nextIterationFromLoopExitDuplication.peekFirst();
|
||||
}
|
||||
if (nextIterationsFromUnrolling != null && !nextIterationsFromUnrolling.isEmpty()) {
|
||||
return remove ? nextIterationsFromUnrolling.removeFirst() : nextIterationsFromUnrolling.peekFirst();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,7 +503,6 @@ public class GraphDecoder {
|
||||
|
||||
/* Process loops of method. */
|
||||
while (loopScope != null) {
|
||||
|
||||
/* Process nodes of loop. */
|
||||
while (!loopScope.nodesToProcess.isEmpty()) {
|
||||
loopScope = processNextNode(methodScope, loopScope);
|
||||
@ -419,10 +513,8 @@ public class GraphDecoder {
|
||||
}
|
||||
|
||||
/* Finished with a loop. */
|
||||
if (loopScope.nextIterations != null && !loopScope.nextIterations.isEmpty()) {
|
||||
/* Loop explosion: process the loop iteration. */
|
||||
assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1;
|
||||
loopScope = loopScope.nextIterations.removeFirst();
|
||||
if (loopScope.hasIterationsToProcess()) {
|
||||
loopScope = loopScope.getNextIterationToProcess(true);
|
||||
} else {
|
||||
propagateCreatedNodes(loopScope);
|
||||
loopScope = loopScope.outer;
|
||||
@ -461,18 +553,34 @@ public class GraphDecoder {
|
||||
}
|
||||
}
|
||||
|
||||
public static final boolean DUMP_DURING_FIXED_NODE_PROCESSING = false;
|
||||
|
||||
protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) {
|
||||
int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0);
|
||||
loopScope.nodesToProcess.clear(nodeOrderId);
|
||||
|
||||
FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId);
|
||||
|
||||
if (node.isDeleted()) {
|
||||
return loopScope;
|
||||
}
|
||||
|
||||
if (DUMP_DURING_FIXED_NODE_PROCESSING) {
|
||||
if (node != null) {
|
||||
try {
|
||||
debug.dump(DebugContext.DETAILED_LEVEL, graph, "Before processing node %s", node);
|
||||
} catch (Throwable t) {
|
||||
// swallow here, dumping uninitialized nodes can cause problems
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((node instanceof MergeNode ||
|
||||
(node instanceof LoopBeginNode && (methodScope.loopExplosion.unrollLoops() && !methodScope.loopExplosion.mergeLoops()))) &&
|
||||
(node instanceof LoopBeginNode && (methodScope.loopExplosion.unrollLoops() &&
|
||||
!methodScope.loopExplosion.mergeLoops()))) &&
|
||||
((AbstractMergeNode) node).forwardEndCount() == 1) {
|
||||
/*
|
||||
* In case node is a loop begin and we are unrolling loops we remove the loop begin
|
||||
* since the loop will be gone after PE.
|
||||
*/
|
||||
AbstractMergeNode merge = (AbstractMergeNode) node;
|
||||
EndNode singleEnd = merge.forwardEndAt(0);
|
||||
|
||||
@ -498,10 +606,15 @@ public class GraphDecoder {
|
||||
* of the inner loop.
|
||||
*/
|
||||
LoopScope outerScope = loopScope.outer;
|
||||
int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1;
|
||||
successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId,
|
||||
int nextIterationNumber = outerScope.nextIterationFromLoopExitDuplication.isEmpty() ? outerScope.loopIteration + 1
|
||||
: outerScope.nextIterationFromLoopExitDuplication.getLast().loopIteration + 1;
|
||||
successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, LoopScopeTrigger.LOOP_EXIT_DUPLICATION,
|
||||
outerScope.initialCreatedNodes == null ? null : Arrays.copyOf(outerScope.initialCreatedNodes, outerScope.initialCreatedNodes.length),
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates);
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
|
||||
outerScope.nextIterationFromLoopExitDuplication,
|
||||
outerScope.nextIterationFromLoopEndDuplication,
|
||||
outerScope.nextIterationsFromUnrolling,
|
||||
outerScope.iterationStates);
|
||||
checkLoopExplosionIteration(methodScope, successorAddScope);
|
||||
|
||||
/*
|
||||
@ -513,7 +626,7 @@ public class GraphDecoder {
|
||||
successorAddScope.createdNodes[id] = null;
|
||||
}
|
||||
|
||||
outerScope.nextIterations.addLast(successorAddScope);
|
||||
outerScope.nextIterationFromLoopExitDuplication.addLast(successorAddScope);
|
||||
} else {
|
||||
successorAddScope = loopScope.outer;
|
||||
}
|
||||
@ -542,27 +655,91 @@ public class GraphDecoder {
|
||||
|
||||
} else if (node instanceof MergeNode) {
|
||||
handleMergeNode(((MergeNode) node));
|
||||
|
||||
} else if (node instanceof AbstractEndNode) {
|
||||
LoopScope phiInputScope = loopScope;
|
||||
LoopScope phiNodeScope = loopScope;
|
||||
|
||||
if (methodScope.loopExplosion.useExplosion() && node instanceof LoopEndNode) {
|
||||
node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node);
|
||||
phiNodeScope = loopScope.nextIterations.getLast();
|
||||
}
|
||||
|
||||
int mergeOrderId = readOrderId(methodScope);
|
||||
|
||||
boolean requiresMergeOfOuterLoop = methodScope.loopExplosion.unrollLoops() &&
|
||||
methodScope.loopExplosion.duplicateLoopExits() &&
|
||||
(!methodScope.loopExplosion.duplicateLoopEnds()) &&
|
||||
(!methodScope.loopExplosion.mergeLoops()) &&
|
||||
node instanceof LoopEndNode &&
|
||||
loopScope.trigger == LoopScopeTrigger.LOOP_EXIT_DUPLICATION;
|
||||
|
||||
if (requiresMergeOfOuterLoop) {
|
||||
EndNode replacementNode = graph.add(new EndNode());
|
||||
node.replaceAtPredecessor(replacementNode);
|
||||
node.safeDelete();
|
||||
node = replacementNode;
|
||||
/*
|
||||
* We are in a loop exit duplicated loop scope and see a loop end node, this can
|
||||
* only happen if we have a loop end to an outer loop. When duplicating over loop
|
||||
* exits we have to merge outer loops for nested inner loops.
|
||||
*
|
||||
* Therefore, we create a correct outer loop iteration and check if there is already
|
||||
* one, if not we create it else we re-use it.
|
||||
*/
|
||||
if (loopScope.nextIterationsFromUnrolling.isEmpty()) {
|
||||
// create it
|
||||
int nextIterationNumber = loopScope.nextIterationsFromUnrolling.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterationsFromUnrolling.getLast().loopIteration + 1;
|
||||
LoopScope outerLoopMergeScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId,
|
||||
LoopScopeTrigger.LOOP_BEGIN_UNROLLING,
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
|
||||
loopScope.nextIterationFromLoopExitDuplication,
|
||||
loopScope.nextIterationFromLoopEndDuplication,
|
||||
loopScope.nextIterationsFromUnrolling,
|
||||
loopScope.iterationStates);
|
||||
checkLoopExplosionIteration(methodScope, outerLoopMergeScope);
|
||||
loopScope.nextIterationsFromUnrolling.addLast(outerLoopMergeScope);
|
||||
registerNode(outerLoopMergeScope, loopScope.loopBeginOrderId, null, true, true);
|
||||
makeStubNode(methodScope, outerLoopMergeScope, loopScope.loopBeginOrderId);
|
||||
phiNodeScope = outerLoopMergeScope;
|
||||
} else {
|
||||
// re-use it
|
||||
phiNodeScope = loopScope.nextIterationsFromUnrolling.getLast();
|
||||
}
|
||||
|
||||
} else if (methodScope.loopExplosion.useExplosion() && node instanceof LoopEndNode) {
|
||||
EndNode replacementNode = graph.add(new EndNode());
|
||||
node.replaceAtPredecessor(replacementNode);
|
||||
node.safeDelete();
|
||||
node = replacementNode;
|
||||
LoopScopeTrigger trigger = handleLoopExplosionEnd(methodScope, loopScope);
|
||||
Deque<LoopScope> phiScope = loopScope.nextIterationsFromUnrolling;
|
||||
if (trigger == LoopScopeTrigger.LOOP_END_DUPLICATION) {
|
||||
phiScope = loopScope.nextIterationFromLoopEndDuplication;
|
||||
}
|
||||
phiNodeScope = phiScope.getLast();
|
||||
}
|
||||
AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId);
|
||||
if (merge == null) {
|
||||
merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId);
|
||||
|
||||
if (merge instanceof LoopBeginNode) {
|
||||
/*
|
||||
* In contrast to the LoopScopeTrigger.START created at the beginning of every
|
||||
* PE, we see a real loop here and create the first real loop scope associated
|
||||
* with a loop.
|
||||
*
|
||||
* Creation of a loop scope if we reach a loop begin node. We process a loop
|
||||
* begin node (always before encountering a loop end associated with the loop
|
||||
* begin) and simply create a normal loop scope. This does not imply an advanced
|
||||
* unrolling strategy (however it can later if we see duplicate over loop end or
|
||||
* exits). Therefore, we still use the start marker here, we could also use the
|
||||
* unrolling marker.
|
||||
*
|
||||
* If we unroll loops we will later remove the loop begin node and replace it
|
||||
* with its forward end (since we do not need to create a loop begin node if we
|
||||
* unroll the entire loop and it has a constant trip count).
|
||||
*/
|
||||
assert phiNodeScope == phiInputScope && phiNodeScope == loopScope;
|
||||
resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId,
|
||||
resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId, LoopScopeTrigger.START,
|
||||
methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null,
|
||||
methodScope.loopExplosion.useExplosion() ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, //
|
||||
methodScope.loopExplosion.useExplosion() ? new ArrayDeque<>(2) : null, //
|
||||
methodScope.loopExplosion.duplicateLoopExits() || methodScope.loopExplosion.mergeLoops() ? new ArrayDeque<>(2) : null,
|
||||
methodScope.loopExplosion.duplicateLoopEnds() ? new ArrayDeque<>(2) : null,
|
||||
methodScope.loopExplosion.unrollLoops() ? new ArrayDeque<>(2) : null, //
|
||||
methodScope.loopExplosion.mergeLoops() ? EconomicMap.create(Equivalence.DEFAULT) : null);
|
||||
phiInputScope = resultScope;
|
||||
phiNodeScope = resultScope;
|
||||
@ -574,9 +751,7 @@ public class GraphDecoder {
|
||||
resultScope.nodesToProcess.set(mergeOrderId);
|
||||
}
|
||||
}
|
||||
|
||||
handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge);
|
||||
|
||||
} else if (node instanceof Invoke) {
|
||||
InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
|
||||
resultScope = handleInvoke(methodScope, loopScope, invokeData);
|
||||
@ -585,7 +760,15 @@ public class GraphDecoder {
|
||||
} else {
|
||||
handleFixedNode(methodScope, loopScope, nodeOrderId, node);
|
||||
}
|
||||
|
||||
if (DUMP_DURING_FIXED_NODE_PROCESSING) {
|
||||
if (node != null) {
|
||||
try {
|
||||
debug.dump(DebugContext.DETAILED_LEVEL, graph, "After processing node %s", node);
|
||||
} catch (Throwable t) {
|
||||
// swallow here, dumping uninitialized nodes can cause problems
|
||||
}
|
||||
}
|
||||
}
|
||||
return resultScope;
|
||||
}
|
||||
|
||||
@ -738,23 +921,44 @@ public class GraphDecoder {
|
||||
throw shouldNotReachHere("when subclass uses loop explosion, it needs to implement this method");
|
||||
}
|
||||
|
||||
protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) {
|
||||
EndNode replacementNode = graph.add(new EndNode());
|
||||
loopEnd.replaceAtPredecessor(replacementNode);
|
||||
loopEnd.safeDelete();
|
||||
|
||||
assert methodScope.loopExplosion.useExplosion();
|
||||
if (methodScope.loopExplosion.duplicateLoopEnds() || loopScope.nextIterations.isEmpty()) {
|
||||
int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
|
||||
LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId,
|
||||
protected LoopScopeTrigger handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope) {
|
||||
/*
|
||||
* This method is only called if we reach a loop end and we use some kind of loop explosion,
|
||||
* i.e., we unroll loops or explode along loop ends.
|
||||
*/
|
||||
LoopScopeTrigger trigger = null;
|
||||
Deque<LoopScope> nextIterations = null;
|
||||
if (methodScope.loopExplosion.duplicateLoopEnds()) {
|
||||
/*
|
||||
* Loop explosion along loop ends: We see a loop end, however we do not merge all loop
|
||||
* ends at a common merge node but rather duplicate the rest of the loop for every loop
|
||||
* end.
|
||||
*/
|
||||
trigger = LoopScopeTrigger.LOOP_END_DUPLICATION;
|
||||
nextIterations = loopScope.nextIterationFromLoopEndDuplication;
|
||||
} else if (loopScope.nextIterationsFromUnrolling.isEmpty()) {
|
||||
/*
|
||||
* Regular loop unrolling, i.e., we reach a loop end node of a loop that should be
|
||||
* unrolled: We create a new successor scope.
|
||||
*/
|
||||
trigger = LoopScopeTrigger.LOOP_BEGIN_UNROLLING;
|
||||
nextIterations = loopScope.nextIterationsFromUnrolling;
|
||||
}
|
||||
if (trigger != null) {
|
||||
int nextIterationNumber = nextIterations.isEmpty() ? loopScope.loopIteration + 1 : nextIterations.getLast().loopIteration + 1;
|
||||
LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, trigger,
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates);
|
||||
Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
|
||||
loopScope.nextIterationFromLoopExitDuplication,
|
||||
loopScope.nextIterationFromLoopEndDuplication,
|
||||
loopScope.nextIterationsFromUnrolling,
|
||||
loopScope.iterationStates);
|
||||
checkLoopExplosionIteration(methodScope, nextIterationScope);
|
||||
loopScope.nextIterations.addLast(nextIterationScope);
|
||||
nextIterations.addLast(nextIterationScope);
|
||||
registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true);
|
||||
makeStubNode(methodScope, nextIterationScope, loopScope.loopBeginOrderId);
|
||||
}
|
||||
return replacementNode;
|
||||
return trigger;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -117,7 +117,7 @@ public class RedefineIntrinsicTest extends ReplacementsTest {
|
||||
} else {
|
||||
List<String> vmArgs = withoutDebuggerArguments(getVMCommandLine());
|
||||
vmArgs.add("-D" + recursionPropName + "=true");
|
||||
vmArgs.addAll(SubprocessUtil.getPackageOpeningOptions());
|
||||
vmArgs.add(SubprocessUtil.PACKAGE_OPENING_OPTIONS);
|
||||
vmArgs.add("-Djdk.attach.allowAttachSelf=true");
|
||||
Subprocess proc = java(vmArgs, "com.oracle.mxtool.junit.MxJUnitWrapper", getClass().getName());
|
||||
if (proc.exitCode != 0) {
|
||||
|
||||
@ -49,7 +49,7 @@ public class Classfile {
|
||||
private final List<ClassfileBytecode> codeAttributes;
|
||||
|
||||
private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7
|
||||
private static final int MAJOR_VERSION_JAVA_MAX = 58; // JDK14
|
||||
private static final int MAJOR_VERSION_JAVA_MAX = 59; // JDK15
|
||||
private static final int MAGIC = 0xCAFEBABE;
|
||||
|
||||
/**
|
||||
|
||||
@ -29,6 +29,8 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
@ -47,6 +49,14 @@ import org.junit.Assume;
|
||||
*/
|
||||
public final class SubprocessUtil {
|
||||
|
||||
/**
|
||||
* The name of the boolean system property that can be set to preserve temporary files created
|
||||
* as arguments files passed to the java launcher.
|
||||
*
|
||||
* @see "https://docs.oracle.com/javase/9/tools/java.htm#JSWOR-GUID-4856361B-8BFD-4964-AE84-121F5F6CF111"
|
||||
*/
|
||||
public static final String KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME = "test." + SubprocessUtil.class.getSimpleName() + ".keepTempArgumentFiles";
|
||||
|
||||
private SubprocessUtil() {
|
||||
}
|
||||
|
||||
@ -184,8 +194,14 @@ public final class SubprocessUtil {
|
||||
*/
|
||||
public final List<String> output;
|
||||
|
||||
public Subprocess(List<String> command, int exitCode, List<String> output) {
|
||||
/**
|
||||
* Explicit environment variables.
|
||||
*/
|
||||
private Map<String, String> env;
|
||||
|
||||
public Subprocess(List<String> command, Map<String, String> env, int exitCode, List<String> output) {
|
||||
this.command = command;
|
||||
this.env = env;
|
||||
this.exitCode = exitCode;
|
||||
this.output = output;
|
||||
}
|
||||
@ -202,6 +218,13 @@ public final class SubprocessUtil {
|
||||
if (delimiter != null) {
|
||||
msg.format("%s%n", delimiter);
|
||||
}
|
||||
if (env != null && !env.isEmpty()) {
|
||||
msg.format("env");
|
||||
for (Map.Entry<String, String> e : env.entrySet()) {
|
||||
msg.format(" %s=%s", e.getKey(), quoteShellArg(e.getValue()));
|
||||
}
|
||||
msg.format("\\%n");
|
||||
}
|
||||
msg.format("%s%n", CollectionsUtil.mapAndJoin(command, e -> quoteShellArg(String.valueOf(e)), " "));
|
||||
for (String line : output) {
|
||||
msg.format("%s%n", line);
|
||||
@ -222,6 +245,14 @@ public final class SubprocessUtil {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A sentinel value which when present in the {@code vmArgs} parameter for any of the
|
||||
* {@code java(...)} methods in this class is replaced with a temporary argument file containing
|
||||
* the contents of {@link #getPackageOpeningOptions}. The argument file is preserved if the
|
||||
* {@link #KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME} system property is true.
|
||||
*/
|
||||
public static final String PACKAGE_OPENING_OPTIONS = ";:PACKAGE_OPENING_OPTIONS_IN_TEMPORARY_ARGUMENTS_FILE:;";
|
||||
|
||||
/**
|
||||
* Executes a Java subprocess.
|
||||
*
|
||||
@ -272,7 +303,22 @@ public final class SubprocessUtil {
|
||||
* @param mainClassAndArgs the main class and its arguments
|
||||
*/
|
||||
private static Subprocess javaHelper(List<String> vmArgs, Map<String, String> env, List<String> mainClassAndArgs) throws IOException, InterruptedException {
|
||||
List<String> command = new ArrayList<>(vmArgs);
|
||||
List<String> command = new ArrayList<>(vmArgs.size());
|
||||
Path packageOpeningOptionsArgumentsFile = null;
|
||||
for (String vmArg : vmArgs) {
|
||||
if (vmArg == PACKAGE_OPENING_OPTIONS) {
|
||||
if (packageOpeningOptionsArgumentsFile == null) {
|
||||
List<String> packageOpeningOptions = getPackageOpeningOptions();
|
||||
if (!packageOpeningOptions.isEmpty()) {
|
||||
packageOpeningOptionsArgumentsFile = Files.createTempFile(Paths.get("."), "package-opening-options-arguments-file", ".txt").toAbsolutePath();
|
||||
Files.write(packageOpeningOptionsArgumentsFile, packageOpeningOptions);
|
||||
command.add("@" + packageOpeningOptionsArgumentsFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
command.add(vmArg);
|
||||
}
|
||||
}
|
||||
command.addAll(mainClassAndArgs);
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
if (env != null) {
|
||||
@ -280,14 +326,22 @@ public final class SubprocessUtil {
|
||||
processBuilderEnv.putAll(env);
|
||||
}
|
||||
processBuilder.redirectErrorStream(true);
|
||||
Process process = processBuilder.start();
|
||||
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
List<String> output = new ArrayList<>();
|
||||
while ((line = stdout.readLine()) != null) {
|
||||
output.add(line);
|
||||
try {
|
||||
Process process = processBuilder.start();
|
||||
BufferedReader stdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
List<String> output = new ArrayList<>();
|
||||
while ((line = stdout.readLine()) != null) {
|
||||
output.add(line);
|
||||
}
|
||||
return new Subprocess(command, env, process.waitFor(), output);
|
||||
} finally {
|
||||
if (packageOpeningOptionsArgumentsFile != null) {
|
||||
if (!Boolean.getBoolean(KEEP_TEMPORARY_ARGUMENT_FILES_PROPERTY_NAME)) {
|
||||
Files.delete(packageOpeningOptionsArgumentsFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
return new Subprocess(command, process.waitFor(), output);
|
||||
}
|
||||
|
||||
private static final boolean isJava8OrEarlier = JavaVersionUtil.JAVA_SPEC <= 8;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user