8235927: Update Graal

Reviewed-by: kvn
This commit is contained in:
Igor Veresov 2019-12-19 15:13:24 -08:00
parent cfddf53c01
commit 261f4bffae
37 changed files with 1133 additions and 169 deletions

View File

@ -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.
*

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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:

View File

@ -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);
}
}
/**

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)) {

View File

@ -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) {

View File

@ -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;

View File

@ -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.
*

View File

@ -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;

View File

@ -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);
}
}
}
}

View File

@ -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());

View File

@ -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());

View File

@ -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;

View File

@ -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;

View File

@ -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) {

View File

@ -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);
}
}
/**

View File

@ -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())

View File

@ -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) {

View File

@ -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 {

View File

@ -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");
}

View File

@ -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");

View File

@ -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);

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;
}
/**

View File

@ -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) {

View File

@ -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;
/**

View File

@ -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;