8190710: Update Graal

Reviewed-by: kvn
This commit is contained in:
Dean Long 2017-11-06 20:29:49 -08:00
parent 545e8eb333
commit c8aacd3972
199 changed files with 5903 additions and 3303 deletions

View File

@ -67,6 +67,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.phases.common/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.compiler.virtual/src \
$(SRC_DIR)/org.graalvm.graphio/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
@ -125,6 +126,7 @@ ifeq ($(INCLUDE_GRAAL), true)
$(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
$(SRC_DIR)/org.graalvm.compiler.options/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
$(SRC_DIR)/org.graalvm.graphio/src \
$(SRC_DIR)/org.graalvm.util/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
$(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \

View File

@ -490,6 +490,8 @@ void AOTCodeHeap::link_stub_routines_symbols() {
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_checkcast_arraycopy", address, StubRoutines::_checkcast_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_generic_arraycopy", address, StubRoutines::_generic_arraycopy);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_encryptBlock", address, StubRoutines::_aescrypt_encryptBlock);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_aescrypt_decryptBlock", address, StubRoutines::_aescrypt_decryptBlock);
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_stub_routines_cipherBlockChaining_encryptAESCrypt", address, StubRoutines::_cipherBlockChaining_encryptAESCrypt);

View File

@ -192,6 +192,8 @@ public final class BinaryContainer implements SymbolTable {
{"StubRoutines::_checkcast_arraycopy", "_aot_stub_routines_checkcast_arraycopy"},
{"StubRoutines::_generic_arraycopy", "_aot_stub_routines_generic_arraycopy"},
{"StubRoutines::_aescrypt_encryptBlock", "_aot_stub_routines_aescrypt_encryptBlock"},
{"StubRoutines::_aescrypt_decryptBlock", "_aot_stub_routines_aescrypt_decryptBlock"},
{"StubRoutines::_cipherBlockChaining_encryptAESCrypt", "_aot_stub_routines_cipherBlockChaining_encryptAESCrypt"},

View File

@ -34,6 +34,9 @@ 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;
/**
* Tests for {@link GraalDirectives#blackhole}.
@ -128,6 +131,11 @@ public class BlackholeDirectiveTest extends GraalCompilerTest {
test("blackholeObjectSnippet", 37);
}
@Override
protected HighTierContext getDefaultHighTierContext() {
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
}
@Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
BlackholeSnippet snippet = graph.method().getAnnotation(BlackholeSnippet.class);

View File

@ -46,6 +46,9 @@ import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.debug.ControlFlowAnchorNode;
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 {
@ -238,6 +241,11 @@ public class ControlFlowAnchorDirectiveTest extends GraalCompilerTest {
return Collections.emptyList();
}
@Override
protected HighTierContext getDefaultHighTierContext() {
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
}
@Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
List<ControlFlowAnchorNode> anchors = graph.getNodes().filter(ControlFlowAnchorNode.class).snapshot();

View File

@ -37,6 +37,9 @@ import org.graalvm.compiler.nodes.ReturnNode;
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;
/**
* Tests for {@link GraalDirectives#opaque}.
@ -127,6 +130,11 @@ public class OpaqueDirectiveTest extends GraalCompilerTest {
test("opaqueObjectSnippet");
}
@Override
protected HighTierContext getDefaultHighTierContext() {
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
}
@Override
protected boolean checkLowTierGraph(StructuredGraph graph) {
OpaqueSnippet snippet = graph.method().getAnnotation(OpaqueSnippet.class);

View File

@ -35,6 +35,13 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface Snippet {
/**
* A partial intrinsic exits by (effectively) calling the intrinsified method. Normally, this
* call must use exactly the same arguments as the call that is being intrinsified. For well
* known snippets that are used after frame state assignment, we want to relax this restriction.
*/
boolean allowPartialIntrinsicArgumentMismatch() default false;
/**
* Denotes a snippet parameter representing 0 or more arguments that will be bound during
* snippet template instantiation. During snippet template creation, its value must be an array

View File

@ -22,10 +22,14 @@
*/
package org.graalvm.compiler.asm.amd64;
import static org.graalvm.compiler.core.common.NumUtil.isByte;
import static org.graalvm.compiler.core.common.NumUtil.isInt;
import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
import static org.graalvm.compiler.core.common.NumUtil.isUByte;
import static jdk.vm.ci.amd64.AMD64.CPU;
import static jdk.vm.ci.amd64.AMD64.XMM;
import static jdk.vm.ci.amd64.AMD64.r12;
import static jdk.vm.ci.amd64.AMD64.r13;
import static jdk.vm.ci.amd64.AMD64.rbp;
import static jdk.vm.ci.amd64.AMD64.rip;
import static jdk.vm.ci.amd64.AMD64.rsp;
import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseAddressNop;
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseNormalNop;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.ADD;
@ -47,25 +51,24 @@ import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.SS;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
import static jdk.vm.ci.amd64.AMD64.CPU;
import static jdk.vm.ci.amd64.AMD64.XMM;
import static jdk.vm.ci.amd64.AMD64.r12;
import static jdk.vm.ci.amd64.AMD64.r13;
import static jdk.vm.ci.amd64.AMD64.rbp;
import static jdk.vm.ci.amd64.AMD64.rip;
import static jdk.vm.ci.amd64.AMD64.rsp;
import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
import static org.graalvm.compiler.core.common.NumUtil.isByte;
import static org.graalvm.compiler.core.common.NumUtil.isInt;
import static org.graalvm.compiler.core.common.NumUtil.isShiftCount;
import static org.graalvm.compiler.core.common.NumUtil.isUByte;
import org.graalvm.compiler.asm.Assembler;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64.CPUFeature;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.Register.RegisterCategory;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.PlatformKind;
/**
* This class implements an assembler that can encode most X86 instructions.
@ -225,7 +228,7 @@ public class AMD64Assembler extends Assembler {
* The x86 operand sizes.
*/
public enum OperandSize {
BYTE(1) {
BYTE(1, AMD64Kind.BYTE) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
assert imm == (byte) imm;
@ -238,7 +241,7 @@ public class AMD64Assembler extends Assembler {
}
},
WORD(2, 0x66) {
WORD(2, AMD64Kind.WORD, 0x66) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
assert imm == (short) imm;
@ -251,7 +254,7 @@ public class AMD64Assembler extends Assembler {
}
},
DWORD(4) {
DWORD(4, AMD64Kind.DWORD) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
asm.emitInt(imm);
@ -263,7 +266,7 @@ public class AMD64Assembler extends Assembler {
}
},
QWORD(8) {
QWORD(8, AMD64Kind.QWORD) {
@Override
protected void emitImmediate(AMD64Assembler asm, int imm) {
asm.emitInt(imm);
@ -275,34 +278,35 @@ public class AMD64Assembler extends Assembler {
}
},
SS(4, 0xF3, true),
SS(4, AMD64Kind.SINGLE, 0xF3, true),
SD(8, 0xF2, true),
SD(8, AMD64Kind.DOUBLE, 0xF2, true),
PS(16, true),
PS(16, AMD64Kind.V128_SINGLE, true),
PD(16, 0x66, true);
PD(16, AMD64Kind.V128_DOUBLE, 0x66, true);
private final int sizePrefix;
private final int bytes;
private final boolean xmm;
private final AMD64Kind kind;
OperandSize(int bytes) {
this(bytes, 0);
OperandSize(int bytes, AMD64Kind kind) {
this(bytes, kind, 0);
}
OperandSize(int bytes, int sizePrefix) {
this(bytes, sizePrefix, false);
OperandSize(int bytes, AMD64Kind kind, int sizePrefix) {
this(bytes, kind, sizePrefix, false);
}
OperandSize(int bytes, boolean xmm) {
this(bytes, 0, xmm);
OperandSize(int bytes, AMD64Kind kind, boolean xmm) {
this(bytes, kind, 0, xmm);
}
OperandSize(int bytes, int sizePrefix, boolean xmm) {
OperandSize(int bytes, AMD64Kind kind, int sizePrefix, boolean xmm) {
this.sizePrefix = sizePrefix;
this.bytes = bytes;
this.kind = kind;
this.xmm = xmm;
}
@ -314,6 +318,19 @@ public class AMD64Assembler extends Assembler {
return xmm;
}
public AMD64Kind getKind() {
return kind;
}
public static OperandSize get(PlatformKind kind) {
for (OperandSize operandSize : OperandSize.values()) {
if (operandSize.kind.equals(kind)) {
return operandSize;
}
}
throw GraalError.shouldNotReachHere("Unexpected kind: " + kind.toString());
}
/**
* Emit an immediate of this size. Note that immediate {@link #QWORD} operands are encoded
* as sign-extended 32-bit values.
@ -2230,6 +2247,14 @@ public class AMD64Assembler extends Assembler {
emitOperandHelper(dst, src, 0);
}
public final void movzbl(Register dst, Register src) {
AMD64RMOp.MOVZXB.emit(this, OperandSize.DWORD, dst, src);
}
public final void movzbq(Register dst, Register src) {
AMD64RMOp.MOVZXB.emit(this, OperandSize.QWORD, dst, src);
}
public final void movzwl(Register dst, AMD64Address src) {
prefix(src, dst);
emitByte(0x0F);
@ -3198,6 +3223,13 @@ public class AMD64Assembler extends Assembler {
emitByte(0xC0 | encode);
}
public final void setb(ConditionFlag cc, Register dst) {
int encode = prefixAndEncode(dst.encoding, true);
emitByte(0x0F);
emitByte(0x90 | cc.getValue());
emitByte(0xC0 | encode);
}
public final void cmovq(ConditionFlag cc, Register dst, AMD64Address src) {
prefixq(src, dst);
emitByte(0x0F);

View File

@ -31,8 +31,8 @@ import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmLoadAndClearU
import static org.graalvm.compiler.asm.amd64.AMD64AsmOptions.UseXmmRegToRegMoveAll;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind;
@ -281,6 +281,16 @@ public class AMD64MacroAssembler extends AMD64Assembler {
}
public final void setl(ConditionFlag cc, Register dst) {
setb(cc, dst);
movzbl(dst, dst);
}
public final void setq(ConditionFlag cc, Register dst) {
setb(cc, dst);
movzbq(dst, dst);
}
public final void flog(Register dest, Register value, boolean base10) {
if (base10) {
fldlg2();

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.amd64.test;
import static org.junit.Assume.assumeTrue;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.amd64.AMD64AddressLowering;
import org.graalvm.compiler.core.amd64.AMD64AddressNode;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import jdk.vm.ci.amd64.AMD64;
public class AMD64AddressLoweringTest extends GraalCompilerTest {
private StructuredGraph graph;
private AMD64AddressLowering lowering;
@Before
public void checkAMD64() {
assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
graph = new StructuredGraph.Builder(getInitialOptions(), getDebugContext()).build();
lowering = new AMD64AddressLowering();
}
@Test
public void convertBaseAndIndexToDisplacement() {
ValueNode base = graph.unique(const64(1000));
ValueNode index = graph.unique(const64(10));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times1, 1010);
}
@Test
public void convertBaseToDisplacement() {
ValueNode constantAddress = graph.addOrUniqueWithInputs(const64(1000));
AddressNode result = lowering.lower(constantAddress, null);
assertAddress(result, null, null, Scale.Times1, 1000);
}
@Test
public void convertBaseAndShiftedIndexToDisplacement() {
ValueNode base = graph.addOrUniqueWithInputs(const64(1000));
ValueNode index = graph.addOrUniqueWithInputs(new LeftShiftNode(const64(10), const32(1)));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times2, 1020);
}
@Test
public void convertBaseAndNegatedShiftedIndexToDisplacement() {
ValueNode base = graph.addOrUniqueWithInputs(const64(1000));
ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times4, 960);
}
@Test
public void convertNegatedBaseAndNegatedShiftedIndexToDisplacement() {
ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(const64(1000)));
ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times4, -1040);
}
@Test
public void convertNegatedShiftedBaseAndNegatedIndexToDisplacement() {
ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(const64(10), const32(2))));
ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(const64(1000)));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times4, -1040);
}
@Test
public void convertTwoLevelsOfNegatedShiftedBaseAndNegatedIndexToDisplacement() {
ValueNode base = graph.addOrUniqueWithInputs(new NegateNode(new LeftShiftNode(new NegateNode(new LeftShiftNode(const64(500), const32(1))), const32(1))));
ValueNode index = graph.addOrUniqueWithInputs(new NegateNode(new AddNode(new NegateNode(const64(13)), const64(3))));
AddressNode result = lowering.lower(base, index);
assertAddress(result, null, null, Scale.Times4, 2010);
}
private static ConstantNode const64(long value) {
return ConstantNode.forIntegerBits(Long.SIZE, value);
}
private static ConstantNode const32(long value) {
return ConstantNode.forIntegerBits(Integer.SIZE, value);
}
private static void assertAddress(AddressNode actual, ValueNode expectedBase, ValueNode expectedIndex, Scale expectedScale, int expectedDisplacement) {
AMD64AddressNode address = (AMD64AddressNode) actual;
Assert.assertEquals(expectedBase, address.getBase());
Assert.assertEquals(expectedIndex, address.getIndex());
Assert.assertEquals(expectedScale, address.getScale());
Assert.assertEquals(expectedDisplacement, address.getDisplacement());
}
}

View File

@ -23,21 +23,22 @@
package org.graalvm.compiler.core.amd64;
import jdk.vm.ci.meta.JavaConstant;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.calc.NegateNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.phases.common.AddressLoweringPhase.AddressLowering;
public class AMD64AddressLowering extends AddressLowering {
import jdk.vm.ci.meta.JavaConstant;
public class AMD64AddressLowering extends AddressLowering {
@Override
public AddressNode lower(ValueNode address) {
return lower(address, null);
@ -46,24 +47,37 @@ public class AMD64AddressLowering extends AddressLowering {
@Override
public AddressNode lower(ValueNode base, ValueNode offset) {
AMD64AddressNode ret = new AMD64AddressNode(base, offset);
StructuredGraph graph = base.graph();
boolean changed;
do {
changed = improve(base.getDebug(), ret);
changed = improve(graph, base.getDebug(), ret, false, false);
} while (changed);
return base.graph().unique(ret);
return graph.unique(ret);
}
/**
* @param debug
* Tries to optimize addresses so that they match the AMD64-specific addressing mode better
* (base + index * scale + displacement).
*
* @param graph the current graph
* @param debug the current debug context
* @param ret the address that should be optimized
* @param isBaseNegated determines if the address base is negated. if so, all values that are
* extracted from the base will be negated as well
* @param isIndexNegated determines if the index is negated. if so, all values that are
* extracted from the index will be negated as well
* @return true if the address was modified
*/
protected boolean improve(DebugContext debug, AMD64AddressNode ret) {
ValueNode newBase = improveInput(ret, ret.getBase(), 0);
protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode ret, boolean isBaseNegated, boolean isIndexNegated) {
ValueNode newBase = improveInput(ret, ret.getBase(), 0, isBaseNegated);
if (newBase != ret.getBase()) {
ret.setBase(newBase);
return true;
}
ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2);
ValueNode newIdx = improveInput(ret, ret.getIndex(), ret.getScale().log2, isIndexNegated);
if (newIdx != ret.getIndex()) {
ret.setIndex(newIdx);
return true;
@ -83,55 +97,122 @@ public class AMD64AddressLowering extends AddressLowering {
}
if (ret.getScale() == Scale.Times1) {
if (ret.getBase() == null || ret.getIndex() == null) {
if (ret.getBase() instanceof AddNode) {
AddNode add = (AddNode) ret.getBase();
ret.setBase(add.getX());
ret.setIndex(add.getY());
return true;
} else if (ret.getIndex() instanceof AddNode) {
AddNode add = (AddNode) ret.getIndex();
ret.setBase(add.getX());
ret.setIndex(add.getY());
return true;
}
if (ret.getIndex() == null && ret.getBase() instanceof AddNode) {
AddNode add = (AddNode) ret.getBase();
ret.setBase(add.getX());
ret.setIndex(considerNegation(graph, add.getY(), isBaseNegated));
return true;
} else if (ret.getBase() == null && ret.getIndex() instanceof AddNode) {
AddNode add = (AddNode) ret.getIndex();
ret.setBase(considerNegation(graph, add.getX(), isIndexNegated));
ret.setIndex(add.getY());
return true;
}
if (ret.getBase() instanceof LeftShiftNode && !(ret.getIndex() instanceof LeftShiftNode)) {
ValueNode tmp = ret.getBase();
ret.setBase(ret.getIndex());
ret.setIndex(tmp);
ret.setBase(considerNegation(graph, ret.getIndex(), isIndexNegated != isBaseNegated));
ret.setIndex(considerNegation(graph, tmp, isIndexNegated != isBaseNegated));
return true;
}
}
return improveNegation(graph, debug, ret, isBaseNegated, isIndexNegated);
}
private boolean improveNegation(StructuredGraph graph, DebugContext debug, AMD64AddressNode ret, boolean originalBaseNegated, boolean originalIndexNegated) {
boolean baseNegated = originalBaseNegated;
boolean indexNegated = originalIndexNegated;
ValueNode originalBase = ret.getBase();
ValueNode originalIndex = ret.getIndex();
if (ret.getBase() instanceof NegateNode) {
NegateNode negate = (NegateNode) ret.getBase();
ret.setBase(negate.getValue());
baseNegated = !baseNegated;
}
if (ret.getIndex() instanceof NegateNode) {
NegateNode negate = (NegateNode) ret.getIndex();
ret.setIndex(negate.getValue());
indexNegated = !indexNegated;
}
if (baseNegated != originalBaseNegated || indexNegated != originalIndexNegated) {
ValueNode base = ret.getBase();
ValueNode index = ret.getIndex();
boolean improved = improve(graph, debug, ret, baseNegated, indexNegated);
if (baseNegated != originalBaseNegated) {
if (base == ret.getBase()) {
ret.setBase(originalBase);
} else if (ret.getBase() != null) {
ret.setBase(graph.maybeAddOrUnique(NegateNode.create(ret.getBase())));
}
}
if (indexNegated != originalIndexNegated) {
if (index == ret.getIndex()) {
ret.setIndex(originalIndex);
} else if (ret.getIndex() != null) {
ret.setIndex(graph.maybeAddOrUnique(NegateNode.create(ret.getIndex())));
}
}
return improved;
} else {
assert ret.getBase() == originalBase && ret.getIndex() == originalIndex;
}
return false;
}
private static ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift) {
private static ValueNode considerNegation(StructuredGraph graph, ValueNode value, boolean negate) {
if (negate && value != null) {
return graph.maybeAddOrUnique(NegateNode.create(value));
}
return value;
}
private ValueNode improveInput(AMD64AddressNode address, ValueNode node, int shift, boolean negateExtractedDisplacement) {
if (node == null) {
return null;
}
JavaConstant c = node.asJavaConstant();
if (c != null) {
return improveConstDisp(address, node, c, null, shift);
return improveConstDisp(address, node, c, null, shift, negateExtractedDisplacement);
} else {
if (node.stamp() instanceof IntegerStamp && ((IntegerStamp) node.stamp()).getBits() == 64) {
if (node instanceof ZeroExtendNode) {
if (((ZeroExtendNode) node).getInputBits() == 32) {
/*
* We can just swallow a zero-extend from 32 bit to 64 bit because the upper
* half of the register will always be zero.
*/
return ((ZeroExtendNode) node).getValue();
if (node.stamp() instanceof IntegerStamp) {
if (node instanceof ZeroExtendNode && (((ZeroExtendNode) node).getInputBits() == 32)) {
/*
* we can't just swallow all zero-extends as we might encounter something like
* the following: ZeroExtend(Add(negativeValue, positiveValue)).
*
* if we swallow the zero-extend in this case and subsequently optimize the add,
* we might end up with a negative value that has less than 64 bits in base or
* index. such a value would require sign extension instead of zero-extension
* but the backend can only do zero-extension. if we ever want to optimize that
* further, we would also need to be careful about over-/underflows.
*
* furthermore, we also can't swallow zero-extends with less than 32 bits as
* most of these values are immediately sign-extended to 32 bit by the backend
* (therefore, the subsequent implicit zero-extension to 64 bit won't do what we
* expect).
*/
ValueNode value = ((ZeroExtendNode) node).getValue();
if (!mightBeOptimized(value)) {
// if the value is not optimized further by the address lowering, then we
// can safely rely on the backend doing the implicitly zero-extension.
return value;
}
} else if (node instanceof AddNode) {
}
if (node instanceof AddNode) {
AddNode add = (AddNode) node;
if (add.getX().isConstant()) {
return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift);
return improveConstDisp(address, node, add.getX().asJavaConstant(), add.getY(), shift, negateExtractedDisplacement);
} else if (add.getY().isConstant()) {
return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift);
return improveConstDisp(address, node, add.getY().asJavaConstant(), add.getX(), shift, negateExtractedDisplacement);
}
}
}
@ -140,15 +221,30 @@ public class AMD64AddressLowering extends AddressLowering {
return node;
}
private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift) {
/**
* This method returns true for all nodes that might be optimized by the address lowering.
*/
protected boolean mightBeOptimized(ValueNode value) {
return value instanceof AddNode || value instanceof LeftShiftNode || value instanceof NegateNode || value instanceof ZeroExtendNode;
}
private static ValueNode improveConstDisp(AMD64AddressNode address, ValueNode original, JavaConstant c, ValueNode other, int shift, boolean negateExtractedDisplacement) {
if (c.getJavaKind().isNumericInteger()) {
long disp = address.getDisplacement();
disp += c.asLong() << shift;
if (NumUtil.isInt(disp)) {
address.setDisplacement((int) disp);
long delta = c.asLong() << shift;
if (updateDisplacement(address, delta, negateExtractedDisplacement)) {
return other;
}
}
return original;
}
protected static boolean updateDisplacement(AMD64AddressNode address, long displacementDelta, boolean negateDelta) {
long sign = negateDelta ? -1 : 1;
long disp = address.getDisplacement() + displacementDelta * sign;
if (NumUtil.isInt(disp)) {
address.setDisplacement((int) disp);
return true;
}
return false;
}
}

View File

@ -33,15 +33,17 @@ import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.isIntConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
@ -58,13 +60,17 @@ import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool;
import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
import org.graalvm.compiler.lir.amd64.AMD64Binary;
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
import org.graalvm.compiler.lir.amd64.AMD64ByteSwapOp;
import org.graalvm.compiler.lir.amd64.AMD64Call;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.BranchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondMoveOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.CondSetOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatBranchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondMoveOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.FloatCondSetOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.ReturnOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp;
@ -257,8 +263,7 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
@Override
public void emitCompareBranch(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, LabelRef trueLabel, LabelRef falseLabel, double trueLabelProbability) {
boolean mirrored = emitCompare(cmpKind, left, right);
Condition finalCondition = mirrored ? cond.mirror() : cond;
Condition finalCondition = emitCompare(cmpKind, left, right, cond);
if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
append(new FloatBranchOp(finalCondition, unorderedIsTrue, trueLabel, falseLabel, trueLabelProbability));
} else {
@ -290,14 +295,60 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
@Override
public Variable emitConditionalMove(PlatformKind cmpKind, Value left, Value right, Condition cond, boolean unorderedIsTrue, Value trueValue, Value falseValue) {
boolean mirrored = emitCompare(cmpKind, left, right);
Condition finalCondition = mirrored ? cond.mirror() : cond;
boolean isFloatComparison = cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE;
Variable result = newVariable(trueValue.getValueKind());
if (cmpKind == AMD64Kind.SINGLE || cmpKind == AMD64Kind.DOUBLE) {
append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(trueValue), load(falseValue)));
Condition finalCondition = cond;
Value finalTrueValue = trueValue;
Value finalFalseValue = falseValue;
if (isFloatComparison) {
// eliminate the parity check in case of a float comparison
Value finalLeft = left;
Value finalRight = right;
if (unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition)) {
if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.mirror())) {
finalCondition = finalCondition.mirror();
finalLeft = right;
finalRight = left;
} else if (finalCondition != Condition.EQ && finalCondition != Condition.NE) {
// negating EQ and NE does not make any sense as we would need to negate
// unorderedIsTrue as well (otherwise, we would no longer fulfill the Java
// NaN semantics)
assert unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate());
finalCondition = finalCondition.negate();
finalTrueValue = falseValue;
finalFalseValue = trueValue;
}
}
emitRawCompare(cmpKind, finalLeft, finalRight);
} else {
append(new CondMoveOp(result, finalCondition, load(trueValue), loadNonConst(falseValue)));
finalCondition = emitCompare(cmpKind, left, right, cond);
}
boolean isParityCheckNecessary = isFloatComparison && unorderedIsTrue != AMD64ControlFlow.trueOnUnordered(finalCondition);
Variable result = newVariable(finalTrueValue.getValueKind());
if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 1) && isIntConstant(finalFalseValue, 0)) {
if (isFloatComparison) {
append(new FloatCondSetOp(result, finalCondition));
} else {
append(new CondSetOp(result, finalCondition));
}
} else if (!isParityCheckNecessary && isIntConstant(finalTrueValue, 0) && isIntConstant(finalFalseValue, 1)) {
if (isFloatComparison) {
if (unorderedIsTrue == AMD64ControlFlow.trueOnUnordered(finalCondition.negate())) {
append(new FloatCondSetOp(result, finalCondition.negate()));
} else {
append(new FloatCondSetOp(result, finalCondition));
Variable negatedResult = newVariable(result.getValueKind());
append(new AMD64Binary.ConstOp(AMD64BinaryArithmetic.XOR, OperandSize.get(result.getPlatformKind()), negatedResult, result, 1));
result = negatedResult;
}
} else {
append(new CondSetOp(result, finalCondition.negate()));
}
} else if (isFloatComparison) {
append(new FloatCondMoveOp(result, finalCondition, unorderedIsTrue, load(finalTrueValue), load(finalFalseValue)));
} else {
append(new CondMoveOp(result, finalCondition, load(finalTrueValue), loadNonConst(finalFalseValue)));
}
return result;
}
@ -394,23 +445,21 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
*
* @param a the left operand of the comparison
* @param b the right operand of the comparison
* @param cond the condition of the comparison
* @return true if the left and right operands were switched, false otherwise
*/
private boolean emitCompare(PlatformKind cmpKind, Value a, Value b) {
Variable left;
Value right;
boolean mirrored;
private Condition emitCompare(PlatformKind cmpKind, Value a, Value b, Condition cond) {
if (LIRValueUtil.isVariable(b)) {
left = load(b);
right = loadNonConst(a);
mirrored = true;
emitRawCompare(cmpKind, b, a);
return cond.mirror();
} else {
left = load(a);
right = loadNonConst(b);
mirrored = false;
emitRawCompare(cmpKind, a, b);
return cond;
}
((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, left, right);
return mirrored;
}
private void emitRawCompare(PlatformKind cmpKind, Value left, Value right) {
((AMD64ArithmeticLIRGeneratorTool) arithmeticLIRGen).emitCompareOp((AMD64Kind) cmpKind, load(left), loadNonConst(right));
}
@Override

View File

@ -28,7 +28,7 @@ import org.graalvm.compiler.debug.GraalError;
import jdk.vm.ci.amd64.AMD64Kind;
public class AMD64LIRKindTool implements LIRKindTool {
public abstract class AMD64LIRKindTool implements LIRKindTool {
@Override
public LIRKind getIntegerKind(int bits) {
@ -67,12 +67,8 @@ public class AMD64LIRKindTool implements LIRKindTool {
}
@Override
public LIRKind getNarrowOopKind() {
return LIRKind.reference(AMD64Kind.DWORD);
}
public abstract LIRKind getNarrowOopKind();
@Override
public LIRKind getNarrowPointerKind() {
return LIRKind.value(AMD64Kind.DWORD);
}
public abstract LIRKind getNarrowPointerKind();
}

View File

@ -34,14 +34,6 @@ public final class CompressEncoding {
this.shift = shift;
}
public int compress(long ptr) {
if (ptr == 0L) {
return 0;
} else {
return (int) ((ptr - base) >>> shift);
}
}
public boolean hasBase() {
return base != 0;
}
@ -58,14 +50,6 @@ public final class CompressEncoding {
return shift;
}
public long uncompress(int ptr) {
if (ptr == 0) {
return 0L;
} else {
return ((ptr & 0xFFFFFFFFL) << shift) + base;
}
}
@Override
public String toString() {
return "base: " + base + " shift: " + shift;
@ -85,8 +69,7 @@ public final class CompressEncoding {
if (obj instanceof CompressEncoding) {
CompressEncoding other = (CompressEncoding) obj;
return base == other.base && shift == other.shift;
} else {
return false;
}
return false;
}
}

View File

@ -25,21 +25,23 @@ package org.graalvm.compiler.core.common.calc;
import org.graalvm.compiler.debug.GraalError;
public enum FloatConvert {
F2I(FloatConvertCategory.FloatingPointToInteger),
D2I(FloatConvertCategory.FloatingPointToInteger),
F2L(FloatConvertCategory.FloatingPointToInteger),
D2L(FloatConvertCategory.FloatingPointToInteger),
I2F(FloatConvertCategory.IntegerToFloatingPoint),
L2F(FloatConvertCategory.IntegerToFloatingPoint),
D2F(FloatConvertCategory.FloatingPointToFloatingPoint),
I2D(FloatConvertCategory.IntegerToFloatingPoint),
L2D(FloatConvertCategory.IntegerToFloatingPoint),
F2D(FloatConvertCategory.FloatingPointToFloatingPoint);
F2I(FloatConvertCategory.FloatingPointToInteger, 32),
D2I(FloatConvertCategory.FloatingPointToInteger, 64),
F2L(FloatConvertCategory.FloatingPointToInteger, 32),
D2L(FloatConvertCategory.FloatingPointToInteger, 64),
I2F(FloatConvertCategory.IntegerToFloatingPoint, 32),
L2F(FloatConvertCategory.IntegerToFloatingPoint, 64),
D2F(FloatConvertCategory.FloatingPointToFloatingPoint, 64),
I2D(FloatConvertCategory.IntegerToFloatingPoint, 32),
L2D(FloatConvertCategory.IntegerToFloatingPoint, 64),
F2D(FloatConvertCategory.FloatingPointToFloatingPoint, 32);
private FloatConvertCategory category;
private final FloatConvertCategory category;
private final int inputBits;
FloatConvert(FloatConvertCategory category) {
FloatConvert(FloatConvertCategory category, int inputBits) {
this.category = category;
this.inputBits = inputBits;
}
public FloatConvertCategory getCategory() {
@ -72,4 +74,8 @@ public enum FloatConvert {
throw GraalError.shouldNotReachHere();
}
}
public int getInputBits() {
return inputBits;
}
}

View File

@ -41,7 +41,6 @@ public abstract class Loop<T extends AbstractBlockBase<T>> {
this.parent = parent;
if (parent != null) {
this.depth = parent.getDepth() + 1;
parent.getChildren().add(this);
} else {
this.depth = 1;
}

View File

@ -96,6 +96,22 @@ public final class ArithmeticOpTable {
}
}
public BinaryOp<?>[] getBinaryOps() {
return new BinaryOp<?>[]{add, sub, mul, mulHigh, umulHigh, div, rem, and, or, xor};
}
public UnaryOp<?>[] getUnaryOps() {
return new UnaryOp<?>[]{neg, not, abs, sqrt};
}
public ShiftOp<?>[] getShiftOps() {
return new ShiftOp<?>[]{shl, shr, ushr};
}
public IntegerConvertOp<?>[] getIntegerConvertOps() {
return new IntegerConvertOp<?>[]{zeroExtend, signExtend, narrow};
}
public static final ArithmeticOpTable EMPTY = new ArithmeticOpTable(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
public interface ArithmeticOpWrapper {
@ -562,7 +578,10 @@ public final class ArithmeticOpTable {
}
/**
* Apply the operation to two {@linkplain Constant Constants}.
* Applies this operation to {@code a} and {@code b}.
*
* @return the result of applying this operation or {@code null} if applying it would raise
* an exception (e.g., {@link ArithmeticException} for dividing by 0)
*/
public abstract Constant foldConstant(Constant a, Constant b);

View File

@ -291,7 +291,7 @@ public class FloatStamp extends PrimitiveStamp {
@Override
public JavaConstant asConstant() {
if (nonNaN && Double.compare(lowerBound, upperBound) == 0) {
if (isConstant()) {
switch (getBits()) {
case 32:
return JavaConstant.forFloat((float) lowerBound);
@ -302,6 +302,68 @@ public class FloatStamp extends PrimitiveStamp {
return null;
}
private boolean isConstant() {
/*
* There are many forms of NaNs and any operations on them can silently convert them into
* the canonical NaN.
*/
return (Double.compare(lowerBound, upperBound) == 0 && nonNaN);
}
private static FloatStamp stampForConstant(Constant constant) {
FloatStamp result;
PrimitiveConstant value = (PrimitiveConstant) constant;
switch (value.getJavaKind()) {
case Float:
if (Float.isNaN(value.asFloat())) {
result = new FloatStamp(32, Double.NaN, Double.NaN, false);
} else {
result = new FloatStamp(32, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
}
break;
case Double:
if (Double.isNaN(value.asDouble())) {
result = new FloatStamp(64, Double.NaN, Double.NaN, false);
} else {
result = new FloatStamp(64, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
}
break;
default:
throw GraalError.shouldNotReachHere();
}
if (result.isConstant()) {
return result;
}
return null;
}
private static Stamp maybeFoldConstant(UnaryOp<?> op, FloatStamp stamp) {
if (stamp.isConstant()) {
JavaConstant constant = stamp.asConstant();
Constant folded = op.foldConstant(constant);
if (folded != null) {
return FloatStamp.stampForConstant(folded);
}
}
return null;
}
private static Stamp maybeFoldConstant(BinaryOp<?> op, FloatStamp stamp1, FloatStamp stamp2) {
if (stamp1.isConstant() && stamp2.isConstant()) {
JavaConstant constant1 = stamp1.asConstant();
JavaConstant constant2 = stamp2.asConstant();
Constant folded = op.foldConstant(constant1, constant2);
if (folded != null) {
FloatStamp stamp = stampForConstant(folded);
if (stamp != null && stamp.isConstant()) {
assert stamp.asConstant().equals(folded);
return stamp;
}
}
}
return null;
}
public static final ArithmeticOpTable OPS = new ArithmeticOpTable(
new UnaryOp.Neg() {
@ -322,8 +384,13 @@ public class FloatStamp extends PrimitiveStamp {
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) {
return folded;
}
return new FloatStamp(stamp.getBits(), -stamp.upperBound(), -stamp.lowerBound(), stamp.isNonNaN());
}
},
new BinaryOp.Add(false, true) {
@ -344,8 +411,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
// TODO
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -381,8 +453,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
// TODO
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -418,9 +495,14 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp a, Stamp b) {
// TODO
return a.unrestricted();
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@Override
@ -450,17 +532,24 @@ public class FloatStamp extends PrimitiveStamp {
assert a.getJavaKind() == b.getJavaKind();
switch (a.getJavaKind()) {
case Float:
return JavaConstant.forFloat(a.asFloat() / b.asFloat());
float floatDivisor = b.asFloat();
return (floatDivisor == 0) ? null : JavaConstant.forFloat(a.asFloat() / floatDivisor);
case Double:
return JavaConstant.forDouble(a.asDouble() / b.asDouble());
double doubleDivisor = b.asDouble();
return (doubleDivisor == 0) ? null : JavaConstant.forDouble(a.asDouble() / doubleDivisor);
default:
throw GraalError.shouldNotReachHere();
}
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
// TODO
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -496,8 +585,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
// TODO
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
},
@ -521,6 +615,17 @@ public class FloatStamp extends PrimitiveStamp {
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
JavaConstant constant = stamp.asConstant();
if (constant != null) {
Constant folded = foldConstant(constant);
if (folded != null) {
FloatStamp result = stampForConstant(folded);
if (result != null && result.isConstant()) {
return result;
}
}
}
return s.unrestricted();
}
},
@ -547,7 +652,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -576,7 +687,9 @@ public class FloatStamp extends PrimitiveStamp {
case Float:
int fa = Float.floatToRawIntBits(a.asFloat());
int fb = Float.floatToRawIntBits(b.asFloat());
return JavaConstant.forFloat(Float.intBitsToFloat(fa | fb));
float floatOr = Float.intBitsToFloat(fa | fb);
assert (fa | fb) == Float.floatToRawIntBits((floatOr));
return JavaConstant.forFloat(floatOr);
case Double:
long da = Double.doubleToRawLongBits(a.asDouble());
long db = Double.doubleToRawLongBits(b.asDouble());
@ -587,7 +700,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -627,7 +746,13 @@ public class FloatStamp extends PrimitiveStamp {
}
@Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
public Stamp foldStamp(Stamp s1, Stamp s2) {
FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
if (folded != null) {
return folded;
}
return stamp1.unrestricted();
}
@ -665,6 +790,10 @@ public class FloatStamp extends PrimitiveStamp {
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) {
return folded;
}
if (stamp.isNaN()) {
return stamp;
}
@ -689,6 +818,11 @@ public class FloatStamp extends PrimitiveStamp {
@Override
public Stamp foldStamp(Stamp s) {
FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) {
return folded;
}
return s.unrestricted();
}
},

View File

@ -597,6 +597,10 @@ public final class IntegerStamp extends PrimitiveStamp {
public Stamp foldStamp(Stamp s) {
IntegerStamp stamp = (IntegerStamp) s;
int bits = stamp.getBits();
if (stamp.lowerBound == stamp.upperBound) {
long value = CodeUtil.convert(-stamp.lowerBound(), stamp.getBits(), false);
return StampFactory.forInteger(stamp.getBits(), value, value);
}
if (stamp.lowerBound() != CodeUtil.minValue(bits)) {
// TODO(ls) check if the mask calculation is correct...
return StampFactory.forInteger(bits, -stamp.upperBound(), -stamp.lowerBound());
@ -624,6 +628,11 @@ public final class IntegerStamp extends PrimitiveStamp {
int bits = a.getBits();
assert bits == b.getBits();
if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound) {
long value = CodeUtil.convert(a.lowerBound() + b.lowerBound(), a.getBits(), false);
return StampFactory.forInteger(a.getBits(), value, value);
}
if (a.isUnrestricted()) {
return a;
} else if (b.isUnrestricted()) {
@ -711,6 +720,12 @@ public final class IntegerStamp extends PrimitiveStamp {
int bits = a.getBits();
assert bits == b.getBits();
if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound) {
long value = CodeUtil.convert(a.lowerBound() * b.lowerBound(), a.getBits(), false);
return StampFactory.forInteger(a.getBits(), value, value);
}
// if a==0 or b==0 result of a*b is always 0
if (a.upMask() == 0) {
return a;
@ -791,7 +806,7 @@ public final class IntegerStamp extends PrimitiveStamp {
long maxPosB = b.upperBound();
// multiplication has shift semantics
long newUpMask = ~CodeUtil.mask(Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask)) & CodeUtil.mask(bits);
long newUpMask = ~CodeUtil.mask(Math.min(64, Long.numberOfTrailingZeros(a.upMask) + Long.numberOfTrailingZeros(b.upMask))) & CodeUtil.mask(bits);
if (a.canBePositive()) {
if (b.canBePositive()) {
@ -1023,6 +1038,9 @@ public final class IntegerStamp extends PrimitiveStamp {
PrimitiveConstant a = (PrimitiveConstant) const1;
PrimitiveConstant b = (PrimitiveConstant) const2;
assert a.getJavaKind() == b.getJavaKind();
if (b.asLong() == 0) {
return null;
}
return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() / b.asLong());
}
@ -1031,9 +1049,12 @@ public final class IntegerStamp extends PrimitiveStamp {
IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits();
if (b.isStrictlyPositive()) {
long newLowerBound = a.lowerBound() / b.upperBound();
long newUpperBound = a.upperBound() / b.lowerBound();
if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound && b.lowerBound != 0) {
long value = CodeUtil.convert(a.lowerBound() / b.lowerBound(), a.getBits(), false);
return StampFactory.forInteger(a.getBits(), value, value);
} else if (b.isStrictlyPositive()) {
long newLowerBound = a.lowerBound() < 0 ? a.lowerBound() / b.lowerBound() : a.lowerBound() / b.upperBound();
long newUpperBound = a.upperBound() < 0 ? a.upperBound() / b.upperBound() : a.upperBound() / b.lowerBound();
return StampFactory.forInteger(a.getBits(), newLowerBound, newUpperBound);
} else {
return a.unrestricted();
@ -1054,6 +1075,9 @@ public final class IntegerStamp extends PrimitiveStamp {
PrimitiveConstant a = (PrimitiveConstant) const1;
PrimitiveConstant b = (PrimitiveConstant) const2;
assert a.getJavaKind() == b.getJavaKind();
if (b.asLong() == 0) {
return null;
}
return JavaConstant.forIntegerKind(a.getJavaKind(), a.asLong() % b.asLong());
}
@ -1062,6 +1086,12 @@ public final class IntegerStamp extends PrimitiveStamp {
IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits();
if (a.lowerBound == a.upperBound && b.lowerBound == b.upperBound && b.lowerBound != 0) {
long value = CodeUtil.convert(a.lowerBound() % b.lowerBound(), a.getBits(), false);
return StampFactory.forInteger(a.getBits(), value, value);
}
// zero is always possible
long newLowerBound = Math.min(a.lowerBound(), 0);
long newUpperBound = Math.max(a.upperBound(), 0);
@ -1364,6 +1394,10 @@ public final class IntegerStamp extends PrimitiveStamp {
public Stamp foldStamp(Stamp input) {
IntegerStamp stamp = (IntegerStamp) input;
int bits = stamp.getBits();
if (stamp.lowerBound == stamp.upperBound) {
long value = CodeUtil.convert(Math.abs(stamp.lowerBound()), stamp.getBits(), false);
return StampFactory.forInteger(stamp.getBits(), value, value);
}
if (stamp.lowerBound() == CodeUtil.minValue(bits)) {
return input.unrestricted();
} else {

View File

@ -49,8 +49,8 @@ import org.graalvm.compiler.core.CompilerThreadFactory;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
@ -73,6 +73,8 @@ import org.graalvm.compiler.phases.util.Providers;
import org.graalvm.compiler.phases.verify.VerifyBailoutUsage;
import org.graalvm.compiler.phases.verify.VerifyCallerSensitiveMethods;
import org.graalvm.compiler.phases.verify.VerifyDebugUsage;
import org.graalvm.compiler.phases.verify.VerifyGetOptionsUsage;
import org.graalvm.compiler.phases.verify.VerifyGraphAddUsage;
import org.graalvm.compiler.phases.verify.VerifyInstanceOfUsage;
import org.graalvm.compiler.phases.verify.VerifyUpdateUsages;
import org.graalvm.compiler.phases.verify.VerifyUsageWithEquals;
@ -381,6 +383,8 @@ public class CheckGraalInvariants extends GraalCompilerTest {
new VerifyUpdateUsages().apply(graph, context);
new VerifyBailoutUsage().apply(graph, context);
new VerifyInstanceOfUsage().apply(graph, context);
new VerifyGraphAddUsage().apply(graph, context);
new VerifyGetOptionsUsage().apply(graph, context);
if (graph.method().isBridge()) {
BridgeMethodUtils.getBridgedMethod(graph.method());
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.GuardNode;
import org.graalvm.compiler.nodes.LogicNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
import org.graalvm.compiler.nodes.memory.FloatingReadNode;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.FloatingReadPhase;
import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.meta.DeoptimizationReason;
/**
* Check that multiple bounds checks are correctly grouped together.
*/
public class ConditionalEliminationTest14 extends ConditionalEliminationTestBase {
public static void test1Snippet(Object[] args) {
Object a5 = args[5];
Object a7 = args[7];
Object a6 = args[6];
/*
* The order of the conditions matters: The scheduler processes the floating reads for the
* array loads in the order of the conditions here, and we want the index 7 access to be
* processed before the index 6 access.
*/
if (a5 != null && a7 != null && a6 != null) {
sink1 = 1;
}
sink0 = 0;
}
@Test
public void test1() {
StructuredGraph graph = parseEager("test1Snippet", AllowAssumptions.YES);
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
PhaseContext context = new PhaseContext(getProviders());
/* Convert the LoadIndexNode to ReadNode with floating guards. */
new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
/* Convert the ReadNode to FloatingReadNode. */
new FloatingReadPhase().apply(graph);
/* Apply the phase that we want to test. */
new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
Assert.assertEquals("All guards must be floating", 0, graph.getNodes(FixedGuardNode.TYPE).count());
Assert.assertEquals("All array accesses must have been lowered", 0, graph.getNodes().filter(LoadIndexedNode.class).count());
Assert.assertEquals("All reads must be floating", 0, graph.getNodes().filter(ReadNode.class).count());
Assert.assertEquals("Must have floating reads (3 array accesses, 1 array length)", 4, graph.getNodes().filter(FloatingReadNode.class).count());
NodeIterable<GuardNode> boundsChecks = graph.getNodes(GuardNode.TYPE).filter(n -> ((GuardNode) n).getReason() == DeoptimizationReason.BoundsCheckException);
Assert.assertEquals("Must have only 1 bounds check remaining", 1, boundsChecks.count());
LogicNode condition = boundsChecks.first().getCondition();
Assert.assertTrue("Bounds check must check for array length 8", condition instanceof IntegerBelowNode && ((IntegerBelowNode) condition).getY().valueEquals(ConstantNode.forInt(8)));
}
}

View File

@ -27,12 +27,15 @@ import org.graalvm.compiler.nodes.ProxyNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
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.ConvertDeoptimizeToGuardPhase;
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.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Assert;
@ -45,6 +48,15 @@ public class ConditionalEliminationTestBase extends GraalCompilerTest {
protected static int sink1;
protected static int sink2;
/**
* These tests assume all code paths in called routines are reachable so disable removal of dead
* code based on method profiles.
*/
@Override
protected HighTierContext getDefaultHighTierContext() {
return new HighTierContext(getProviders(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL.remove(Optimization.RemoveNeverExecutedCode));
}
protected void testConditionalElimination(String snippet, String referenceSnippet) {
testConditionalElimination(snippet, referenceSnippet, false, false);
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.util.EconomicMap;
import org.junit.Test;
/**
* Check that setting the dump path results in files ending up in the right directory with matching
* names.
*/
public class DumpPathTest extends GraalCompilerTest {
public static Object snippet() {
return new String("snippet");
}
@Test
public void testDump() throws IOException {
Path dumpDirectoryPath = Files.createTempDirectory("DumpPathTest");
String[] extensions = new String[]{".cfg", ".bgv", ".graph-strings"};
EconomicMap<OptionKey<?>, Object> overrides = OptionValues.newOptionMap();
overrides.put(DebugOptions.DumpPath, dumpDirectoryPath.toString());
overrides.put(DebugOptions.PrintGraphFile, true);
overrides.put(DebugOptions.PrintCanonicalGraphStrings, true);
overrides.put(DebugOptions.Dump, "*");
// Generate dump files.
test(new OptionValues(getInitialOptions(), overrides), "snippet");
// Check that Ideal files got created, in the right place.
checkForFiles(dumpDirectoryPath, extensions);
// Clean up the generated files.
scrubDirectory(dumpDirectoryPath);
}
/**
* Check that the given directory contains file or directory names with all the given
* extensions.
*/
private static void checkForFiles(Path directoryPath, String[] extensions) throws IOException {
String[] paths = new String[extensions.length];
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
for (Path filePath : stream) {
String fileName = filePath.getFileName().toString();
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
if (fileName.endsWith(extensions[i])) {
assertTrue(paths[i] == null, "multiple files found for %s in %s", extension, directoryPath);
paths[i] = fileName.replace(extensions[i], "");
}
}
}
}
for (int i = 0; i < paths.length; i++) {
assertTrue(paths[i] != null, "missing file for extension %s in %s", extensions[i], directoryPath);
}
// Ensure that all file names are the same.
for (int i = 1; i < paths.length; i++) {
assertTrue(paths[0].equals(paths[i]), paths[0] + " != " + paths[i]);
}
}
/**
* Remove the temporary directory.
*/
private static void scrubDirectory(Path directoryPath) {
try {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(directoryPath)) {
for (Path filePath : stream) {
if (Files.isRegularFile(filePath)) {
Files.delete(filePath);
} else if (Files.isDirectory(filePath)) {
scrubDirectory(filePath);
}
}
}
Files.delete(directoryPath);
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}

View File

@ -72,7 +72,7 @@ public class FinalizableSubclassTest extends GraalCompilerTest {
Assert.assertTrue(constructors.length == 1);
final ResolvedJavaMethod javaMethod = getMetaAccess().lookupJavaMethod(constructors[0]);
OptionValues options = getInitialOptions();
StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options), allowAssumptions).method(javaMethod).build();
StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, javaMethod), allowAssumptions).method(javaMethod).build();
GraphBuilderConfiguration conf = GraphBuilderConfiguration.getSnippetDefault(getDefaultGraphBuilderPlugins());
new GraphBuilderPhase.Instance(getMetaAccess(), getProviders().getStampProvider(), getProviders().getConstantReflection(), getProviders().getConstantFieldProvider(), conf,

View File

@ -389,7 +389,7 @@ public abstract class GraalCompilerTest extends GraalTest {
* {@link DebugDumpHandler}s closed in {@link #afterTest()}.
*/
protected DebugContext getDebugContext() {
return getDebugContext(getInitialOptions());
return getDebugContext(getInitialOptions(), null, null);
}
@Override
@ -862,7 +862,7 @@ public abstract class GraalCompilerTest extends GraalTest {
Result actual = executeActual(options, method, receiver, args);
profile = method.getProfilingInfo(); // profile can change after execution
for (DeoptimizationReason reason : shouldNotDeopt) {
Assert.assertEquals((int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
Assert.assertEquals("wrong number of deopt counts for " + reason, (int) deoptCounts.get(reason), profile.getDeoptimizationCount(reason));
}
return actual;
}
@ -1216,15 +1216,15 @@ public abstract class GraalCompilerTest extends GraalTest {
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions) {
OptionValues options = getInitialOptions();
return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(getCompilationId(method));
return new Builder(options, getDebugContext(options, null, method), allowAssumptions).method(method).compilationId(getCompilationId(method));
}
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, CompilationIdentifier compilationId, OptionValues options) {
return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(compilationId);
return new Builder(options, getDebugContext(options, compilationId.toString(CompilationIdentifier.Verbosity.ID), method), allowAssumptions).method(method).compilationId(compilationId);
}
protected final Builder builder(ResolvedJavaMethod method, AllowAssumptions allowAssumptions, OptionValues options) {
return new Builder(options, getDebugContext(options), allowAssumptions).method(method).compilationId(getCompilationId(method));
return new Builder(options, getDebugContext(options, null, method), allowAssumptions).method(method).compilationId(getCompilationId(method));
}
protected PhaseSuite<HighTierContext> getDebugGraphBuilderSuite() {
@ -1234,6 +1234,7 @@ public abstract class GraalCompilerTest extends GraalTest {
@SuppressWarnings("try")
protected StructuredGraph parse(StructuredGraph.Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
ResolvedJavaMethod javaMethod = builder.getMethod();
builder.speculationLog(getSpeculationLog());
if (builder.getCancellable() == null) {
builder.cancellable(getCancellable(javaMethod));
}

View File

@ -31,8 +31,12 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Comparator;
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
import org.graalvm.compiler.debug.DebugOptions;
import org.graalvm.compiler.debug.PathUtilities;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.test.AddExports;
import org.junit.Assume;
import org.junit.Test;
@AddExports("jdk.internal.vm.compiler/org.graalvm.compiler.printer")
@ -40,23 +44,28 @@ public class GraalDebugHandlersFactoryTest extends GraalCompilerTest {
@Test
public void createUniqueTest() throws Exception {
Field maxFileNameLengthField = GraalDebugHandlersFactory.class.getDeclaredField("MAX_FILE_NAME_LENGTH");
maxFileNameLengthField.setAccessible(true);
Field maxFileNameLengthField = PathUtilities.class.getDeclaredField("MAX_FILE_NAME_LENGTH");
try {
maxFileNameLengthField.setAccessible(true);
} catch (RuntimeException ex) {
Assume.assumeFalse("If InaccessibleObjectException is thrown, skip the test, we are on JDK9", ex.getClass().getSimpleName().equals("InaccessibleObjectException"));
}
int maxFileNameLength = maxFileNameLengthField.getInt(null);
Method createUniqueMethod = GraalDebugHandlersFactory.class.getDeclaredMethod("createUnique", Path.class, String.class, String.class, String.class, boolean.class);
Method createUniqueMethod = PathUtilities.class.getDeclaredMethod("createUnique", OptionValues.class, OptionKey.class, String.class, String.class, String.class, boolean.class);
createUniqueMethod.setAccessible(true);
Path tmpDir = Files.createTempDirectory(Paths.get("."), "createUniqueTest");
OptionValues options = new OptionValues(OptionValues.asMap(DebugOptions.DumpPath, tmpDir.toString()));
try {
for (boolean createDirectory : new boolean[]{true, false}) {
for (String ext : new String[]{"", ".bgv", ".graph-strings"}) {
for (int i = 0; i < maxFileNameLength + 5; i++) {
String id = new String(new char[i]).replace('\0', 'i');
String label = "";
createUniqueMethod.invoke(null, tmpDir, id, label, ext, createDirectory);
createUniqueMethod.invoke(null, options, null, id, label, ext, createDirectory);
id = "";
label = new String(new char[i]).replace('\0', 'l');
createUniqueMethod.invoke(null, tmpDir, id, label, ext, createDirectory);
createUniqueMethod.invoke(null, options, null, id, label, ext, createDirectory);
}
}
}

View File

@ -144,6 +144,11 @@ public class GuardedIntrinsicTest extends GraalCompilerTest {
public void test01() {
Super inheritsHC = new Super();
Person overridesHC = new Person(0);
// Ensure the profile for getSuperAge includes both receiver types
getSuperAge(inheritsHC);
getSuperAge(overridesHC);
test("getSuperAge", inheritsHC);
test("getSuperAge", overridesHC);

View File

@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.core.test;
import java.util.HashMap;
import org.graalvm.compiler.core.phases.HighTier;
import org.graalvm.compiler.core.phases.MidTier;
import org.graalvm.compiler.nodes.InvokeNode;
@ -139,6 +141,10 @@ public class HashCodeTest extends GraalCompilerTest {
public void test08() {
initialize(Appendable.class);
checkForGuardedIntrinsicPattern("hashCodeInterface");
// Ensure the profile for the dispatch in hashCodeSnippet01
// has a receiver type that does not select Object.hashCode intrinsic
hashCodeSnippet01(new HashMap<>());
checkForGuardedIntrinsicPattern("hashCodeSnippet01");
}

View File

@ -25,6 +25,7 @@ package org.graalvm.compiler.core.test;
import static java.nio.file.StandardOpenOption.READ;
import static java.nio.file.StandardOpenOption.WRITE;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
@ -33,22 +34,20 @@ import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Files;
import java.nio.file.Path;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.code.InvalidInstalledCodeException;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import sun.misc.Unsafe;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.common.inlining.InliningPhase;
import org.graalvm.compiler.phases.common.inlining.policy.InlineEverythingPolicy;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.code.InvalidInstalledCodeException;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import sun.misc.Unsafe;
public class MarkUnsafeAccessTest extends GraalCompilerTest {
@ -170,7 +169,9 @@ public class MarkUnsafeAccessTest extends GraalCompilerTest {
try {
mbb.position(BLOCK_SIZE);
getter.get(mbb);
System.currentTimeMillis(); // materialize async exception
// Make a call that goes into native code to materialize async exception
new File("").exists();
} catch (InternalError e) {
return;
}

View File

@ -26,12 +26,23 @@ import org.graalvm.compiler.debug.DebugContext;
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.common.CanonicalizerPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.junit.Test;
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));
}
public static int staticField;
private int field;

View File

@ -24,15 +24,17 @@ package org.graalvm.compiler.core.test;
import java.io.Serializable;
import org.graalvm.compiler.test.SubprocessUtil;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.TriState;
import org.junit.Assert;
import org.junit.Test;
/**
* Tests profiling information provided by the runtime.
* <p>
@ -40,7 +42,7 @@ import org.junit.Test;
* information may be gathered for any given method. For example, HotSpot's advanced compilation
* policy can decide to only gather partial profiles in a first level compilation (see
* AdvancedThresholdPolicy::common(...) in advancedThresholdPolicy.cpp). Because of this,
* occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only set's
* occasionally tests for {@link ProfilingInfo#getNullSeen(int)} can fail since HotSpot only sets
* the null_seen bit when doing full profiling.
*/
public class ProfilingInfoTest extends GraalCompilerTest {
@ -182,6 +184,14 @@ public class ProfilingInfoTest extends GraalCompilerTest {
Assert.assertNull(typeProfile);
}
public ProfilingInfoTest() {
// These tests are explicitly testing the profiling behavior of the
// interpreter. C1-based profiling differs slightly and when -Xcomp
// is present, profiles will be created by C1 compiled code, not the
// interpreter.
Assume.assumeTrue(!SubprocessUtil.getVMCommandLine().contains("-Xcomp"));
}
@Test
public void testExceptionSeen() {
// NullPointerException

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.core.test;
import java.util.ArrayList;
import java.util.List;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@RunWith(Parameterized.class)
public class SubWordReturnTest extends GraalCompilerTest {
private final JavaKind kind;
private final int value;
private final String generatedClassName;
private final String generatedClassNameInternal;
private final String testMethodName;
/**
* The {@link AsmLoader} generates a class looking like this for the types byte, short, int and
* char.
*/
static class ByteGetter {
// private static int intField = 1000000;
private static byte get() {
// GETSTATIC intField
// IRETURN
return 0;
}
public static int testByteSnippet() {
return get();
}
}
@Parameters(name = "{0}, {1}")
public static List<Object[]> data() {
ArrayList<Object[]> ret = new ArrayList<>();
for (int i : new int[]{1000000, 1000001, -1000000, -1}) {
ret.add(new Object[]{JavaKind.Boolean, i});
ret.add(new Object[]{JavaKind.Byte, i});
ret.add(new Object[]{JavaKind.Short, i});
ret.add(new Object[]{JavaKind.Char, i});
}
return ret;
}
public SubWordReturnTest(JavaKind kind, int value) {
this.kind = kind;
this.value = value;
this.generatedClassName = SubWordReturnTest.class.getName() + "$" + kind.toString() + "Getter";
this.generatedClassNameInternal = generatedClassName.replace('.', '/');
this.testMethodName = "test" + kind.name() + "Snippet";
}
@Test
public void test() throws ClassNotFoundException {
Class<?> testClass = new AsmLoader(SubWordReturnTest.class.getClassLoader()).findClass(generatedClassName);
ResolvedJavaMethod method = getResolvedJavaMethod(testClass, testMethodName);
test(method, null);
}
class AsmLoader extends ClassLoader implements Opcodes {
Class<?> loaded;
AsmLoader(ClassLoader parent) {
super(parent);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (name.equals(generatedClassName)) {
if (loaded == null) {
byte[] gen = generateClass();
loaded = defineClass(name, gen, 0, gen.length);
}
return loaded;
} else {
return super.findClass(name);
}
}
private byte[] generateClass() {
ClassWriter cw = new ClassWriter(0);
cw.visit(52, ACC_SUPER | ACC_PUBLIC, generatedClassNameInternal, null, "java/lang/Object", null);
FieldVisitor intField = cw.visitField(ACC_PRIVATE | ACC_STATIC, "intField", "I", null, value);
intField.visitEnd();
MethodVisitor get = cw.visitMethod(ACC_PRIVATE | ACC_STATIC, "get", "()" + kind.getTypeChar(), null, null);
get.visitCode();
get.visitFieldInsn(GETSTATIC, generatedClassNameInternal, "intField", "I");
get.visitInsn(IRETURN);
get.visitMaxs(1, 0);
get.visitEnd();
MethodVisitor snippet = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, testMethodName, "()I", null, null);
snippet.visitCode();
snippet.visitMethodInsn(INVOKESTATIC, generatedClassNameInternal, "get", "()" + kind.getTypeChar(), false);
snippet.visitInsn(IRETURN);
snippet.visitMaxs(1, 0);
snippet.visitEnd();
cw.visitEnd();
return cw.toByteArray();
}
}
}

View File

@ -87,7 +87,7 @@ public class UnbalancedMonitorsTest extends GraalCompilerTest {
ResolvedJavaMethod method = getResolvedJavaMethod(LOADER.findClass(INNER_CLASS_NAME), name);
try {
OptionValues options = getInitialOptions();
StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options)).method(method).build();
StructuredGraph graph = new StructuredGraph.Builder(options, getDebugContext(options, null, method)).method(method).build();
Plugins plugins = new Plugins(new InvocationPlugins());
GraphBuilderConfiguration graphBuilderConfig = GraphBuilderConfiguration.getDefault(plugins).withEagerResolving(true).withUnresolvedIsError(true);
OptimisticOptimizations optimisticOpts = OptimisticOptimizations.NONE;

View File

@ -32,9 +32,20 @@ import org.graalvm.compiler.phases.tiers.PhaseContext;
import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class UnsafeVirtualizationTest extends GraalCompilerTest {
public static class A {
public static class Base {
/*
* This padding ensure that the size of the Base class ends up as a multiple of 8, which
* makes the first field of the subclass 8-byte aligned.
*/
double padding;
}
public static class A extends Base {
int f1;
int f2;
}
@ -56,39 +67,96 @@ public class UnsafeVirtualizationTest extends GraalCompilerTest {
AF2Offset = o2;
}
public static int unsafeSnippet0(int i1, int i2) {
public static int unsafeSnippet1(double i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1 + i2);
UNSAFE.putDouble(a, AF1Offset, i1);
return UNSAFE.getInt(a, AF1Offset) + UNSAFE.getInt(a, AF2Offset);
}
public static int unsafeSnippet1(int i1, int i2) {
public static long unsafeSnippet2a(int i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1 + i2);
UNSAFE.putDouble(a, AF1Offset, i1);
a.f1 = i1;
return UNSAFE.getLong(a, AF1Offset);
}
public static long unsafeSnippet2b(int i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1);
a.f2 = i1;
return (int) UNSAFE.getDouble(a, AF1Offset);
return UNSAFE.getLong(a, AF1Offset);
}
public static long unsafeSnippet3a(int i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1);
UNSAFE.putInt(a, AF1Offset, i1);
return UNSAFE.getLong(a, AF1Offset);
}
public static long unsafeSnippet3b(int i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1);
UNSAFE.putInt(a, AF2Offset, i1);
return UNSAFE.getLong(a, AF1Offset);
}
public static int unsafeSnippet4(double i1) {
A a = new A();
UNSAFE.putDouble(a, AF1Offset, i1);
UNSAFE.putDouble(a, AF1Offset, i1);
return UNSAFE.getInt(a, AF1Offset) + UNSAFE.getInt(a, AF2Offset);
}
@Test
public void testUnsafePEA01() {
testPartialEscapeReadElimination(parseEager("unsafeSnippet0", AllowAssumptions.NO), false);
testPartialEscapeReadElimination(parseEager("unsafeSnippet0", AllowAssumptions.NO), true);
testPartialEscapeReadElimination("unsafeSnippet1", false, 1.0);
testPartialEscapeReadElimination("unsafeSnippet1", true, 1.0);
}
@Test
public void testUnsafePEA02() {
testPartialEscapeReadElimination(parseEager("unsafeSnippet1", AllowAssumptions.NO), false);
testPartialEscapeReadElimination(parseEager("unsafeSnippet1", AllowAssumptions.NO), true);
testPartialEscapeReadElimination("unsafeSnippet2a", false, 1);
testPartialEscapeReadElimination("unsafeSnippet2a", true, 1);
testPartialEscapeReadElimination("unsafeSnippet2b", false, 1);
testPartialEscapeReadElimination("unsafeSnippet2b", true, 1);
}
public void testPartialEscapeReadElimination(StructuredGraph graph, boolean canonicalizeBefore) {
@Test
public void testUnsafePEA03() {
testPartialEscapeReadElimination("unsafeSnippet3a", false, 1);
testPartialEscapeReadElimination("unsafeSnippet3a", true, 1);
testPartialEscapeReadElimination("unsafeSnippet3b", false, 1);
testPartialEscapeReadElimination("unsafeSnippet3b", true, 1);
}
@Test
public void testUnsafePEA04() {
testPartialEscapeReadElimination("unsafeSnippet4", false, 1.0);
testPartialEscapeReadElimination("unsafeSnippet4", true, 1.0);
}
public void testPartialEscapeReadElimination(String snippet, boolean canonicalizeBefore, Object... args) {
assert AF1Offset % 8 == 0 : "First of the two int-fields must be 8-byte aligned";
ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
StructuredGraph graph = parseEager(snippet, AllowAssumptions.NO);
OptionValues options = graph.getOptions();
PhaseContext context = getDefaultHighTierContext();
CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
if (canonicalizeBefore) {
canonicalizer.apply(graph, context);
}
Result r = executeExpected(method, null, args);
new PartialEscapePhase(true, true, canonicalizer, null, options).apply(graph, context);
try {
InstalledCode code = getCode(method, graph);
Object result = code.executeVarargs(args);
assertEquals(r, new Result(result, null));
} catch (Throwable e) {
assertFalse(true, e.toString());
}
}
}

View File

@ -77,7 +77,7 @@ public class EATestBase extends GraalCompilerTest {
@Override
public String toString() {
return "{" + x + "," + y + "}";
return "{" + x + "," + y + "," + z + "}";
}
@Override
@ -158,11 +158,19 @@ public class EATestBase extends GraalCompilerTest {
context = getDefaultHighTierContext();
new InliningPhase(new CanonicalizerPhase()).apply(graph, context);
new DeadCodeEliminationPhase().apply(graph);
new CanonicalizerPhase().apply(graph, context);
canonicalizeGraph();
new PartialEscapePhase(iterativeEscapeAnalysis, false, new CanonicalizerPhase(), null, graph.getOptions()).apply(graph, context);
postEACanonicalizeGraph();
returnNodes = graph.getNodes(ReturnNode.TYPE).snapshot();
} catch (Throwable e) {
throw debug.handle(e);
}
}
protected void postEACanonicalizeGraph() {
}
protected void canonicalizeGraph() {
new CanonicalizerPhase().apply(graph, context);
}
}

View File

@ -27,9 +27,20 @@ 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;
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));
}
public static Object field;
public static void snippet1(int i) {

View File

@ -22,6 +22,8 @@
*/
package org.graalvm.compiler.core.test.ea;
import java.lang.reflect.Field;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.StructuredGraph;
@ -33,9 +35,8 @@ import org.graalvm.compiler.phases.common.inlining.InliningPhase;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
import org.junit.Test;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class TrufflePEATest extends GraalCompilerTest {
@ -56,6 +57,7 @@ public class TrufflePEATest extends GraalCompilerTest {
static class DynamicObject {
int primitiveField0;
int primitiveField1;
int primitiveField2;
}
private static final long offsetLong1 = Unsafe.ARRAY_LONG_BASE_OFFSET + Unsafe.ARRAY_LONG_INDEX_SCALE * 1;
@ -66,7 +68,15 @@ public class TrufflePEATest extends GraalCompilerTest {
static {
try {
Field primitiveField0 = DynamicObject.class.getDeclaredField("primitiveField0");
primitiveField0Offset = UNSAFE.objectFieldOffset(primitiveField0);
long offset = UNSAFE.objectFieldOffset(primitiveField0);
if (offset % 8 == 0) {
primitiveField0Offset = offset;
} else {
Field primitiveField1 = DynamicObject.class.getDeclaredField("primitiveField1");
offset = UNSAFE.objectFieldOffset(primitiveField1);
assert offset % 8 == 0;
primitiveField0Offset = offset;
}
} catch (NoSuchFieldException | SecurityException e) {
throw new AssertionError(e);
}

View File

@ -22,14 +22,26 @@
*/
package org.graalvm.compiler.core.test.ea;
import jdk.vm.ci.meta.JavaConstant;
import java.nio.ByteBuffer;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.graph.Graph;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.PhiNode;
import org.graalvm.compiler.nodes.ValuePhiNode;
import org.graalvm.compiler.nodes.calc.UnpackEndianHalfNode;
import org.graalvm.compiler.nodes.extended.RawLoadNode;
import org.graalvm.compiler.nodes.extended.RawStoreNode;
import org.graalvm.compiler.nodes.extended.UnsafeAccessNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
import org.junit.Assert;
import org.junit.Test;
import org.graalvm.compiler.nodes.PhiNode;
import org.graalvm.compiler.nodes.ValuePhiNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class UnsafeEATest extends EATestBase {
@ -56,6 +68,64 @@ public class UnsafeEATest extends EATestBase {
}
}
@Override
protected void testEscapeAnalysis(String snippet, JavaConstant expectedConstantResult, boolean iterativeEscapeAnalysis) {
// Exercise both a graph containing UnsafeAccessNodes and one which has been possibly been
// canonicalized into AccessFieldNodes.
testingUnsafe = true;
super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis);
testingUnsafe = false;
super.testEscapeAnalysis(snippet, expectedConstantResult, iterativeEscapeAnalysis);
if (expectedConstantResult != null) {
// Check that a compiled version of this method returns the same value if we expect a
// constant result.
ResolvedJavaMethod method = getResolvedJavaMethod(snippet);
JavaKind[] javaKinds = method.getSignature().toParameterKinds(false);
Object[] args = new Object[javaKinds.length];
int i = 0;
for (JavaKind k : javaKinds) {
args[i++] = JavaConstant.defaultForKind(k).asBoxedPrimitive();
}
Result result = executeExpected(method, null, args);
assertTrue(result.returnValue.equals(expectedConstantResult.asBoxedPrimitive()));
}
}
@Override
protected void canonicalizeGraph() {
if (testingUnsafe) {
// For testing purposes we'd like to ensure that our raw unsafe operations stay as
// unsafe nodes, so force them to appear to have LocationIdentity.any to disable
// transformation into field access nodes.
for (Node node : graph.getNodes().filter(x -> x instanceof UnsafeAccessNode).snapshot()) {
if (node instanceof RawStoreNode) {
RawStoreNode store = (RawStoreNode) node;
RawStoreNode newStore = graph.add(new RawStoreNode(store.object(), store.offset(), store.value(), store.accessKind(), NamedLocationIdentity.any(),
store.needsBarrier(), store.stateAfter(), true));
graph.replaceFixedWithFixed(store, newStore);
} else if (node instanceof RawLoadNode) {
RawLoadNode load = (RawLoadNode) node;
RawLoadNode newLoad = graph.add(new RawLoadNode(load.object(), load.offset(), load.accessKind(), NamedLocationIdentity.any(),
true));
graph.replaceFixedWithFixed(load, newLoad);
}
}
}
super.canonicalizeGraph();
}
@Override
protected void postEACanonicalizeGraph() {
// Simplify any UnpackEndianHalfNode so we end up with constants.
Graph.Mark mark = graph.getMark();
for (UnpackEndianHalfNode node : graph.getNodes().filter(UnpackEndianHalfNode.class)) {
node.lower(getTarget().arch.getByteOrder());
}
new CanonicalizerPhase().applyIncremental(graph, context, mark);
}
private boolean testingUnsafe;
@Test
public void testSimpleInt() {
testEscapeAnalysis("testSimpleIntSnippet", JavaConstant.forInt(101), false);
@ -89,6 +159,82 @@ public class UnsafeEATest extends EATestBase {
return UNSAFE.getDouble(x, fieldOffset1);
}
@Test
public void testSimpleDoubleOverwriteWithInt() {
testEscapeAnalysis("testSimpleDoubleOverwriteWithIntSnippet", JavaConstant.forInt(10), false);
}
public static int testSimpleDoubleOverwriteWithIntSnippet() {
TestClassInt x = new TestClassInt();
UNSAFE.putDouble(x, fieldOffset1, 10.1);
UNSAFE.putInt(x, fieldOffset1, 10);
return UNSAFE.getInt(x, fieldOffset1);
}
@Test
public void testSimpleDoubleOverwriteWithSecondInt() {
ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
bb.putDouble(10.1);
int value = bb.getInt(4);
testEscapeAnalysis("testSimpleDoubleOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false);
}
public static int testSimpleDoubleOverwriteWithSecondIntSnippet() {
TestClassInt x = new TestClassInt();
UNSAFE.putDouble(x, fieldOffset1, 10.1);
UNSAFE.putInt(x, fieldOffset1, 10);
return UNSAFE.getInt(x, fieldOffset2);
}
@Test
public void testSimpleDoubleOverwriteWithFirstInt() {
ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
bb.putDouble(10.1);
int value = bb.getInt(0);
testEscapeAnalysis("testSimpleDoubleOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false);
}
public static int testSimpleDoubleOverwriteWithFirstIntSnippet() {
TestClassInt x = new TestClassInt();
UNSAFE.putDouble(x, fieldOffset1, 10.1);
UNSAFE.putInt(x, fieldOffset2, 10);
return UNSAFE.getInt(x, fieldOffset1);
}
@Test
public void testSimpleLongOverwriteWithSecondInt() {
ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
bb.putLong(0, 0x1122334455667788L);
int value = bb.getInt(4);
testEscapeAnalysis("testSimpleLongOverwriteWithSecondIntSnippet", JavaConstant.forInt(value), false);
}
public static int testSimpleLongOverwriteWithSecondIntSnippet() {
TestClassInt x = new TestClassInt();
UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L);
UNSAFE.putInt(x, fieldOffset1, 10);
return UNSAFE.getInt(x, fieldOffset2);
}
@Test
public void testSimpleLongOverwriteWithFirstInt() {
ByteBuffer bb = ByteBuffer.allocate(8).order(getTarget().arch.getByteOrder());
bb.putLong(0, 0x1122334455667788L);
int value = bb.getInt(0);
testEscapeAnalysis("testSimpleLongOverwriteWithFirstIntSnippet", JavaConstant.forInt(value), false);
}
public static int testSimpleLongOverwriteWithFirstIntSnippet() {
TestClassInt x = new TestClassInt();
UNSAFE.putLong(x, fieldOffset1, 0x1122334455667788L);
UNSAFE.putInt(x, fieldOffset2, 10);
return UNSAFE.getInt(x, fieldOffset1);
}
@Test
public void testMergedDouble() {
testEscapeAnalysis("testMergedDoubleSnippet", null, false);
@ -111,6 +257,32 @@ public class UnsafeEATest extends EATestBase {
return UNSAFE.getDouble(x, fieldOffset1);
}
static class ExtendedTestClassInt extends TestClassInt {
public long l;
}
@Test
public void testMergedVirtualObjects() {
testEscapeAnalysis("testMergedVirtualObjectsSnippet", null, false);
}
public static TestClassInt testMergedVirtualObjectsSnippet(int value) {
TestClassInt x;
if (value == 1) {
x = new TestClassInt();
UNSAFE.putDouble(x, fieldOffset1, 10);
} else {
x = new TestClassInt();
UNSAFE.putInt(x, fieldOffset1, 0);
}
UNSAFE.putInt(x, fieldOffset1, 0);
if (value == 2) {
UNSAFE.putInt(x, fieldOffset2, 0);
}
GraalDirectives.deoptimizeAndInvalidate();
return x;
}
@Test
public void testMaterializedDouble() {
test("testMaterializedDoubleSnippet");

View File

@ -146,7 +146,7 @@ public class NestedLoopEffectsPhaseComplexityTest extends GraalCompilerTest {
private StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTierContext context, CanonicalizerPhase canonicalizer) {
OptionValues options = getInitialOptions();
StructuredGraph newGraph = new StructuredGraph.Builder(options, getDebugContext(options), AllowAssumptions.NO).method(method).build();
StructuredGraph newGraph = new StructuredGraph.Builder(options, getDebugContext(options, null, method), AllowAssumptions.NO).method(method).build();
context.getGraphBuilderSuite().apply(newGraph, context);
new DeadCodeEliminationPhase(Optional).apply(newGraph);
canonicalizer.apply(newGraph, context);

View File

@ -47,7 +47,7 @@ public class GraalCompilerOptions {
public static final EnumOptionKey<ExceptionAction> CompilationFailureAction = new EnumOptionKey<>(ExceptionAction.Diagnose);
@Option(help = "The maximum number of compilation failures or bailouts to handle with the action specified " +
"by CompilationFailureAction or CompilationBailoutAction before changing to a less verbose action.", type = OptionType.User)
public static final OptionKey<Integer> MaxCompilationProblemsPerAction = new OptionKey<>(5);
public static final OptionKey<Integer> MaxCompilationProblemsPerAction = new OptionKey<>(2);
@Option(help = "Alias for CompilationFailureAction=ExitVM.", type = OptionType.User)
public static final OptionKey<Boolean> ExitVMOnException = new OptionKey<>(false);
// @formatter:on

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -132,8 +132,17 @@ public class DebugInfoBuilder {
slotKinds[pos] = toSlotKind(value);
pos++;
} else {
assert currentField.values().get(i - 1).getStackKind() == JavaKind.Double || currentField.values().get(i - 1).getStackKind() == JavaKind.Long : vobjNode + " " + i + " " +
currentField.values().get(i - 1);
assert value.getStackKind() == JavaKind.Illegal;
ValueNode previousValue = currentField.values().get(i - 1);
assert (previousValue != null && previousValue.getStackKind().needsTwoSlots()) : vobjNode + " " + i +
" " + previousValue + " " + currentField.values().snapshot();
if (previousValue == null || !previousValue.getStackKind().needsTwoSlots()) {
// Don't allow the IllegalConstant to leak into the debug info
JavaKind entryKind = vobjNode.entryKind(i);
values[pos] = JavaConstant.defaultForKind(entryKind.getStackKind());
slotKinds[pos] = entryKind.getStackKind();
pos++;
}
}
}
if (pos != entryCount) {
@ -164,19 +173,19 @@ public class DebugInfoBuilder {
if (!type.isArray()) {
ResolvedJavaField[] fields = type.getInstanceFields(true);
int fieldIndex = 0;
for (int i = 0; i < values.length; i++) {
ResolvedJavaField field = fields[fieldIndex++];
JavaKind valKind = slotKinds[i].getStackKind();
for (int valueIndex = 0; valueIndex < values.length; valueIndex++, fieldIndex++) {
ResolvedJavaField field = fields[fieldIndex];
JavaKind valKind = slotKinds[valueIndex].getStackKind();
JavaKind fieldKind = storageKind(field.getType());
if (fieldKind == JavaKind.Object) {
assert valKind.isObject() : field + ": " + valKind + " != " + fieldKind;
if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
assert fieldIndex + 1 < fields.length : String.format("Not enough fields for fieldIndex = %d valueIndex = %d %s %s", fieldIndex, valueIndex, Arrays.toString(fields),
Arrays.toString(values));
assert storageKind(fields[fieldIndex + 1].getType()) == JavaKind.Int : String.format("fieldIndex = %d valueIndex = %d %s %s %s", fieldIndex, valueIndex,
storageKind(fields[fieldIndex + 1].getType()), Arrays.toString(fields),
Arrays.toString(values));
fieldIndex++;
} else {
if ((valKind == JavaKind.Double || valKind == JavaKind.Long) && fieldKind == JavaKind.Int) {
assert storageKind(fields[fieldIndex].getType()) == JavaKind.Int;
fieldIndex++;
} else {
assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
}
assert valKind == fieldKind.getStackKind() : field + ": " + valKind + " != " + fieldKind;
}
}
assert fields.length == fieldIndex : type + ": fields=" + Arrays.toString(fields) + ", field values=" + Arrays.toString(values);

View File

@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.StandardOp.LabelOp;
import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.debug.LIRGenerationDebugContext;
import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
import org.graalvm.compiler.lir.gen.LIRGenerator;
import org.graalvm.compiler.lir.gen.LIRGenerator.Options;
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
@ -577,9 +578,9 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
@Override
public void emitInvoke(Invoke x) {
LoweredCallTargetNode callTarget = (LoweredCallTargetNode) x.callTarget();
CallingConvention invokeCc = gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()),
callTarget.signature(), gen);
gen.getResult().getFrameMapBuilder().callsMethod(invokeCc);
FrameMapBuilder frameMapBuilder = gen.getResult().getFrameMapBuilder();
CallingConvention invokeCc = frameMapBuilder.getRegisterConfig().getCallingConvention(callTarget.callType(), x.asNode().stamp().javaType(gen.getMetaAccess()), callTarget.signature(), gen);
frameMapBuilder.callsMethod(invokeCc);
Value[] parameters = visitInvokeArguments(invokeCc, callTarget.arguments());

View File

@ -195,9 +195,12 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
public InstalledCode createInstalledCode(DebugContext debug, ResolvedJavaMethod method, CompilationRequest compilationRequest, CompilationResult compilationResult,
SpeculationLog speculationLog, InstalledCode predefinedInstalledCode, boolean isDefault, Object[] context) {
Object[] debugContext = context != null ? context : new Object[]{getProviders().getCodeCache(), method, compilationResult};
CodeInstallationTask[] tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()];
for (int i = 0; i < codeInstallationTaskFactories.size(); i++) {
tasks[i] = codeInstallationTaskFactories.get(i).create();
CodeInstallationTask[] tasks;
synchronized (this) {
tasks = new CodeInstallationTask[codeInstallationTaskFactories.size()];
for (int i = 0; i < codeInstallationTaskFactories.size(); i++) {
tasks[i] = codeInstallationTaskFactories.get(i).create();
}
}
try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
DebugContext.Activation a = debug.activate()) {

View File

@ -29,9 +29,11 @@ import static org.graalvm.compiler.debug.DebugOptions.Counters;
import static org.graalvm.compiler.debug.DebugOptions.Dump;
import static org.graalvm.compiler.debug.DebugOptions.DumpOnError;
import static org.graalvm.compiler.debug.DebugOptions.DumpOnPhaseChange;
import static org.graalvm.compiler.debug.DebugOptions.DumpPath;
import static org.graalvm.compiler.debug.DebugOptions.ListMetrics;
import static org.graalvm.compiler.debug.DebugOptions.Log;
import static org.graalvm.compiler.debug.DebugOptions.MemUseTrackers;
import static org.graalvm.compiler.debug.DebugOptions.ShowDumpFiles;
import static org.graalvm.compiler.debug.DebugOptions.Time;
import static org.graalvm.compiler.debug.DebugOptions.Timers;
import static org.graalvm.compiler.debug.DebugOptions.TrackMemUse;
@ -56,6 +58,7 @@ import java.util.TreeMap;
import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.graphio.GraphOutput;
import org.graalvm.util.EconomicMap;
import org.graalvm.util.EconomicSet;
import org.graalvm.util.Pair;
@ -98,6 +101,8 @@ public final class DebugContext implements AutoCloseable {
CloseableCounter currentMemUseTracker;
Scope lastClosedScope;
Throwable lastExceptionThrown;
private IgvDumpChannel sharedChannel;
private GraphOutput<?, ?> parentOutput;
/**
* Stores the {@link MetricKey} values.
@ -111,6 +116,19 @@ public final class DebugContext implements AutoCloseable {
return immutable.scopesEnabled;
}
public <G, N, M> GraphOutput<G, M> buildOutput(GraphOutput.Builder<G, N, M> builder) throws IOException {
if (parentOutput != null) {
return builder.build(parentOutput);
} else {
if (sharedChannel == null) {
sharedChannel = new IgvDumpChannel(() -> getDumpPath(".bgv", false), immutable.options);
}
final GraphOutput<G, M> output = builder.build(sharedChannel);
parentOutput = output;
return output;
}
}
/**
* The immutable configuration that can be shared between {@link DebugContext} objects.
*/
@ -323,6 +341,14 @@ public final class DebugContext implements AutoCloseable {
String compilableName = compilable instanceof JavaMethod ? ((JavaMethod) compilable).format("%H.%n(%p)%R") : String.valueOf(compilable);
return identifier + ":" + compilableName;
}
final String getLabel() {
if (compilable instanceof JavaMethod) {
JavaMethod method = (JavaMethod) compilable;
return method.format("%h.%n(%p)%r");
}
return String.valueOf(compilable);
}
}
private final Description description;
@ -394,6 +420,20 @@ public final class DebugContext implements AutoCloseable {
}
}
public Path getDumpPath(String extension, boolean directory) {
try {
String id = description == null ? null : description.identifier;
String label = description == null ? null : description.getLabel();
Path result = PathUtilities.createUnique(immutable.options, DumpPath, id, label, extension, directory);
if (ShowDumpFiles.getValue(immutable.options)) {
TTY.println("Dumping debug output to %s", result.toAbsolutePath().toString());
}
return result;
} catch (IOException ex) {
throw rethrowSilently(RuntimeException.class, ex);
}
}
/**
* A special dump level that indicates the dumping machinery is enabled but no dumps will be
* produced except through other options.
@ -2043,4 +2083,9 @@ public final class DebugContext implements AutoCloseable {
}
out.println();
}
@SuppressWarnings({"unused", "unchecked"})
private static <E extends Exception> E rethrowSilently(Class<E> type, Throwable ex) throws E {
throw (E) ex;
}
}

View File

@ -35,6 +35,9 @@ public interface DebugHandlersFactory {
/**
* Creates {@link DebugHandler}s based on {@code options}.
*
* @param options options to control type and name of the channel
* @return list of debug handers that have been created
*/
List<DebugHandler> createHandlers(OptionValues options);

View File

@ -128,8 +128,6 @@ public class DebugOptions {
public static final OptionKey<Boolean> PrintGraphProbabilities = new OptionKey<>(false);
@Option(help = "Enable dumping to the IdealGraphVisualizer.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintGraph = new OptionKey<>(true);
@Option(help = "Dump graphs in binary format instead of XML format.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintBinaryGraphs = new OptionKey<>(true);
@Option(help = "Print graphs to files instead of sending them over the network.", type = OptionType.Debug)
public static final OptionKey<Boolean> PrintGraphFile = new OptionKey<>(false);

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.debug;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.function.Supplier;
import static org.graalvm.compiler.debug.DebugOptions.PrintBinaryGraphPort;
import static org.graalvm.compiler.debug.DebugOptions.PrintGraphHost;
import org.graalvm.compiler.options.OptionValues;
final class IgvDumpChannel implements WritableByteChannel {
private final Supplier<Path> pathProvider;
private final OptionValues options;
private WritableByteChannel sharedChannel;
private boolean closed;
IgvDumpChannel(Supplier<Path> pathProvider, OptionValues options) {
this.pathProvider = pathProvider;
this.options = options;
}
@Override
public int write(ByteBuffer src) throws IOException {
return channel().write(src);
}
@Override
public boolean isOpen() {
return !closed;
}
@Override
public void close() throws IOException {
}
void realClose() throws IOException {
closed = true;
if (sharedChannel != null) {
sharedChannel.close();
sharedChannel = null;
}
}
WritableByteChannel channel() throws IOException {
if (closed) {
throw new IOException();
}
if (sharedChannel == null) {
if (DebugOptions.PrintGraphFile.getValue(options)) {
sharedChannel = createFileChannel(pathProvider);
} else {
sharedChannel = createNetworkChannel(pathProvider, options);
}
}
return sharedChannel;
}
private static WritableByteChannel createNetworkChannel(Supplier<Path> pathProvider, OptionValues options) throws IOException {
String host = PrintGraphHost.getValue(options);
int port = PrintBinaryGraphPort.getValue(options);
try {
WritableByteChannel channel = SocketChannel.open(new InetSocketAddress(host, port));
TTY.println("Connected to the IGV on %s:%d", host, port);
return channel;
} catch (ClosedByInterruptException | InterruptedIOException e) {
/*
* Interrupts should not count as errors because they may be caused by a cancelled Graal
* compilation. ClosedByInterruptException occurs if the SocketChannel could not be
* opened. InterruptedIOException occurs if new Socket(..) was interrupted.
*/
return null;
} catch (IOException e) {
if (!DebugOptions.PrintGraphFile.hasBeenSet(options)) {
return createFileChannel(pathProvider);
} else {
throw new IOException(String.format("Could not connect to the IGV on %s:%d", host, port), e);
}
}
}
private static WritableByteChannel createFileChannel(Supplier<Path> pathProvider) throws IOException {
Path path = pathProvider.get();
try {
return FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
} catch (IOException e) {
throw new IOException(String.format("Failed to open %s to dump IGV graphs", path), e);
}
}
}

View File

@ -22,12 +22,13 @@
*/
package org.graalvm.compiler.debug;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.graalvm.compiler.options.OptionKey;
@ -39,54 +40,6 @@ import org.graalvm.compiler.options.OptionValues;
public class PathUtilities {
private static final AtomicLong globalTimeStamp = new AtomicLong();
/**
* This generates a per thread persistent id to aid mapping related dump files with each other.
*/
private static final ThreadLocal<PerThreadSequence> threadDumpId = new ThreadLocal<>();
private static final AtomicInteger dumpId = new AtomicInteger();
static class PerThreadSequence {
final int threadID;
HashMap<String, Integer> sequences = new HashMap<>(2);
PerThreadSequence(int threadID) {
this.threadID = threadID;
}
String generateID(String extension) {
Integer box = sequences.get(extension);
if (box == null) {
sequences.put(extension, 1);
return Integer.toString(threadID);
} else {
sequences.put(extension, box + 1);
return Integer.toString(threadID) + '-' + box;
}
}
}
private static String getThreadDumpId(String extension) {
PerThreadSequence id = threadDumpId.get();
if (id == null) {
id = new PerThreadSequence(dumpId.incrementAndGet());
threadDumpId.set(id);
}
return id.generateID(extension);
}
/**
* Prepends a period (i.e., {@code '.'}) to an non-null, non-empty string representation a file
* extension if the string does not already start with a period.
*
* @return {@code ext} unmodified if it is null, empty or already starts with a period other
* {@code "." + ext}
*/
public static String formatExtension(String ext) {
if (ext == null || ext.length() == 0) {
return "";
}
return "." + ext;
}
/**
* Gets a time stamp for the current process. This method will always return the same value for
@ -99,43 +52,6 @@ public class PathUtilities {
return globalTimeStamp.get();
}
/**
* Generates a {@link Path} using the format "%s-%d_%d%s" with the {@code baseNameOption}, a
* {@link #getGlobalTimeStamp() global timestamp} , {@link #getThreadDumpId a per thread unique
* id} and an optional {@code extension}.
*
* @return the output file path or null if the flag is null
*/
public static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException {
return getPath(options, baseNameOption, extension, true);
}
/**
* Generate a {@link Path} using the format "%s-%d_%s" with the {@code baseNameOption}, a
* {@link #getGlobalTimeStamp() global timestamp} and an optional {@code extension} .
*
* @return the output file path or null if the flag is null
*/
public static Path getPathGlobal(OptionValues options, OptionKey<String> baseNameOption, String extension) throws IOException {
return getPath(options, baseNameOption, extension, false);
}
private static Path getPath(OptionValues options, OptionKey<String> baseNameOption, String extension, boolean includeThreadId) throws IOException {
if (baseNameOption.getValue(options) == null) {
return null;
}
String ext = formatExtension(extension);
final String name = includeThreadId
? String.format("%s-%d_%s%s", baseNameOption.getValue(options), getGlobalTimeStamp(), getThreadDumpId(ext), ext)
: String.format("%s-%d%s", baseNameOption.getValue(options), getGlobalTimeStamp(), ext);
Path result = Paths.get(name);
if (result.isAbsolute()) {
return result;
}
Path dumpDir = DebugOptions.getDumpDirectory(options);
return dumpDir.resolve(name).normalize();
}
/**
* Gets a value based on {@code name} that can be passed to {@link Paths#get(String, String...)}
* without causing an {@link InvalidPathException}.
@ -145,21 +61,80 @@ public class PathUtilities {
*/
public static String sanitizeFileName(String name) {
try {
Paths.get(name);
return name;
Path path = Paths.get(name);
if (path.getNameCount() == 0) {
return name;
}
} catch (InvalidPathException e) {
// fall through
}
StringBuilder buf = new StringBuilder(name.length());
for (int i = 0; i < name.length(); i++) {
char c = name.charAt(i);
try {
Paths.get(String.valueOf(c));
} catch (InvalidPathException e) {
buf.append('_');
if (c != File.separatorChar && c != ' ' && !Character.isISOControl(c)) {
try {
Paths.get(String.valueOf(c));
buf.append(c);
continue;
} catch (InvalidPathException e) {
}
}
buf.append(c);
buf.append('_');
}
return buf.toString();
}
/**
* A maximum file name length supported by most file systems. There is no platform independent
* way to get this in Java.
*/
private static final int MAX_FILE_NAME_LENGTH = 255;
private static final String ELLIPSIS = "...";
static Path createUnique(OptionValues options, OptionKey<String> baseNameOption, String id, String label, String ext, boolean createDirectory) throws IOException {
String uniqueTag = "";
int dumpCounter = 1;
String prefix;
if (id == null) {
prefix = baseNameOption.getValue(options);
int slash = prefix.lastIndexOf(File.separatorChar);
prefix = prefix.substring(slash + 1);
} else {
prefix = id;
}
for (;;) {
int fileNameLengthWithoutLabel = uniqueTag.length() + ext.length() + prefix.length() + "[]".length();
int labelLengthLimit = MAX_FILE_NAME_LENGTH - fileNameLengthWithoutLabel;
String fileName;
if (labelLengthLimit < ELLIPSIS.length()) {
// This means `id` is very long
String suffix = uniqueTag + ext;
int idLengthLimit = Math.min(MAX_FILE_NAME_LENGTH - suffix.length(), prefix.length());
fileName = sanitizeFileName(prefix.substring(0, idLengthLimit) + suffix);
} else {
if (label == null) {
fileName = sanitizeFileName(prefix + uniqueTag + ext);
} else {
String adjustedLabel = label;
if (label.length() > labelLengthLimit) {
adjustedLabel = label.substring(0, labelLengthLimit - ELLIPSIS.length()) + ELLIPSIS;
}
fileName = sanitizeFileName(prefix + '[' + adjustedLabel + ']' + uniqueTag + ext);
}
}
Path dumpDir = DebugOptions.getDumpDirectory(options);
Path result = Paths.get(dumpDir.toString(), fileName);
try {
if (createDirectory) {
return Files.createDirectory(result);
} else {
return Files.createFile(result);
}
} catch (FileAlreadyExistsException e) {
uniqueTag = "_" + dumpCounter++;
}
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.graph.test.graphio;
import java.io.File;
import java.lang.reflect.Method;
import static org.junit.Assert.assertTrue;
import org.junit.Assume;
import org.junit.Test;
public class GraphSnippetTest {
@Test
public void dumpTheFile() throws Exception {
Class<?> snippets = null;
try {
snippets = Class.forName("org.graalvm.graphio.GraphSnippets");
} catch (ClassNotFoundException notFound) {
Assume.assumeNoException("The snippets class has to be around", notFound);
}
Method dump = null;
try {
dump = snippets.getDeclaredMethod("dump", File.class);
dump.setAccessible(true);
} catch (RuntimeException ex) {
Assume.assumeTrue("Only run the test, if the method is accessible", dump != null && dump.isAccessible());
}
File diamond = File.createTempFile("diamond", ".bgv");
dump.invoke(null, diamond);
assertTrue("File .bgv created: " + diamond, diamond.length() > 50);
}
}

View File

@ -0,0 +1,311 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.graph.test.graphio;
import java.io.ByteArrayOutputStream;
import java.nio.channels.Channels;
import java.nio.channels.WritableByteChannel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.graalvm.graphio.GraphOutput;
import org.graalvm.graphio.GraphStructure;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
public final class NodeEncodingTest {
private ByteArrayOutputStream out;
@Before
public void initOutput() {
out = new ByteArrayOutputStream();
}
@Test
public void version40TheNodeIsntDumpedWithItsID() throws Exception {
runTheNodeIsntDumpedWithItsID(true);
}
@Test
public void defaultVersionTheNodeIsntDumpedWithItsID() throws Exception {
runTheNodeIsntDumpedWithItsID(false);
}
private void runTheNodeIsntDumpedWithItsID(boolean explicitVersion) throws Exception {
WritableByteChannel w = Channels.newChannel(out);
MockGraph graph = new MockGraph();
MockNodeClass clazz = new MockNodeClass("clazz");
MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
dump.endGroup();
}
assertEquals("Node is always requested", 1, node.nodeRequested);
assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested);
assertByte(false, out.toByteArray(), 33);
assertEquals("Node class of the node has been requested", 1, node.nodeClassRequested);
assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried);
assertFalse("No to string ops", node.toStringRequested);
}
@Test
public void dumpingNodeInVersion10() throws Exception {
runTheNodeIsTreatedAsString(true);
}
private void runTheNodeIsTreatedAsString(boolean explicitVersion) throws Exception {
WritableByteChannel w = Channels.newChannel(out);
MockGraph graph = new MockGraph();
MockNodeClass clazz = new MockNodeClass("clazz");
MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(1, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
dump.endGroup();
}
assertEquals("Node is always requested", 1, node.nodeRequested);
assertEquals("Nobody asks for id of a node in version 1.0", 0, node.idTested);
assertByte(false, out.toByteArray(), 33);
assertEquals("Node class was needed to find out it is not a NodeClass instance", 1, node.nodeClassRequested);
assertEquals("Node class template name wasn't needed however", 0, clazz.nameTemplateQueried);
assertTrue("Node sent as a string version 1.0", node.toStringRequested);
}
@Test
public void dumpingNodeInVersion15() throws Exception {
runTheNodeIsTreatedPoolEntry(true);
}
private void runTheNodeIsTreatedPoolEntry(boolean explicitVersion) throws Exception {
WritableByteChannel w = Channels.newChannel(out);
MockGraph graph = new MockGraph();
MockNodeClass clazz = new MockNodeClass("clazz");
MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
try (GraphOutput<MockGraph, ?> dump = explicitVersion ? GraphOutput.newBuilder(new MockStructure()).protocolVersion(5, 0).build(w) : GraphOutput.newBuilder(new MockStructure()).build(w)) {
dump.beginGroup(graph, "test1", "t1", null, 0, Collections.singletonMap("node", node));
dump.endGroup();
}
assertEquals("Node is always requested", 1, node.nodeRequested);
assertEquals("Id of our node is requested in version 5.0", 1, node.idTested);
assertByte(true, out.toByteArray(), 33);
assertTrue("Node class was needed at least once", 1 <= node.nodeClassRequested);
assertEquals("Node class template name sent to server", 1, clazz.nameTemplateQueried);
assertFalse("Node.toString() isn't needed", node.toStringRequested);
}
@Test
public void dumpingNodeTwiceInVersion4() throws Exception {
WritableByteChannel w = Channels.newChannel(out);
MockGraph graph = new MockGraph();
MockNodeClass clazz = new MockNodeClass("clazz");
MockNode node = new MockNode(clazz, 33); // random value otherwise not found in the stream
try (GraphOutput<MockGraph, ?> dump = GraphOutput.newBuilder(new MockStructure()).protocolVersion(4, 0).build(w)) {
Map<String, Object> props = new LinkedHashMap<>();
props.put("node1", node);
props.put("node2", node);
props.put("node3", node);
dump.beginGroup(graph, "test1", "t1", null, 0, props);
dump.endGroup();
}
assertEquals("Node requested three times", 3, node.nodeRequested);
assertEquals("Nobody asks for id of a node in version 4.0", 0, node.idTested);
// check there is no encoded string for object #3
assertByte(false, out.toByteArray(), 1, 0, 3);
assertEquals("Node class of the node has been requested three times", 3, node.nodeClassRequested);
assertEquals("Node class template name stored", 1, clazz.nameTemplateQueried);
assertFalse("No to string ops", node.toStringRequested);
}
private static void assertByte(boolean shouldBeFound, byte[] arr, int... value) {
boolean found = false;
int at = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == value[at]) {
if (++at == value.length) {
found = true;
break;
}
} else {
at = 0;
}
}
if (shouldBeFound == found) {
return;
}
if (shouldBeFound) {
fail("Value " + value + " not found in\n" + Arrays.toString(arr));
} else {
fail("Value " + value + " surprisingly found in\n" + Arrays.toString(arr));
}
}
private static final class MockStructure implements GraphStructure<MockGraph, MockNode, MockNodeClass, MockNodeClass> {
@Override
public MockGraph graph(MockGraph currentGraph, Object obj) {
return obj instanceof MockGraph ? (MockGraph) obj : null;
}
@Override
public Iterable<? extends MockNode> nodes(MockGraph graph) {
return Collections.emptyList();
}
@Override
public int nodesCount(MockGraph graph) {
return 0;
}
@Override
public int nodeId(MockNode node) {
node.idTested++;
return node.id;
}
@Override
public boolean nodeHasPredecessor(MockNode node) {
return false;
}
@Override
public void nodeProperties(MockGraph graph, MockNode node, Map<String, ? super Object> properties) {
}
@Override
public MockNode node(Object obj) {
if (obj instanceof MockNode) {
((MockNode) obj).nodeRequested++;
return (MockNode) obj;
}
return null;
}
@Override
public MockNodeClass nodeClass(Object obj) {
if (obj instanceof MockNode) {
((MockNode) obj).nodeClassRequested++;
}
return obj instanceof MockNodeClass ? (MockNodeClass) obj : null;
}
@Override
public MockNodeClass classForNode(MockNode n) {
n.nodeClassRequested++;
return n.clazz;
}
@Override
public String nameTemplate(MockNodeClass nodeClass) {
nodeClass.nameTemplateQueried++;
return "";
}
@Override
public Object nodeClassType(MockNodeClass nodeClass) {
return nodeClass.getClass();
}
@Override
public MockNodeClass portInputs(MockNodeClass nodeClass) {
return nodeClass;
}
@Override
public MockNodeClass portOutputs(MockNodeClass nodeClass) {
return nodeClass;
}
@Override
public int portSize(MockNodeClass port) {
return 0;
}
@Override
public boolean edgeDirect(MockNodeClass port, int index) {
return false;
}
@Override
public String edgeName(MockNodeClass port, int index) {
return null;
}
@Override
public Object edgeType(MockNodeClass port, int index) {
return null;
}
@Override
public Collection<? extends MockNode> edgeNodes(MockGraph graph, MockNode node, MockNodeClass port, int index) {
return null;
}
}
private static final class MockGraph {
}
private static final class MockNode {
final MockNodeClass clazz;
final int id;
int idTested;
int nodeClassRequested;
int nodeRequested;
boolean toStringRequested;
MockNode(MockNodeClass clazz, int id) {
this.clazz = clazz;
this.id = id;
}
@Override
public String toString() {
this.toStringRequested = true;
return "MockNode{" + "id=" + id + ", class=" + clazz + '}';
}
}
private static final class MockNodeClass {
final String name;
int nameTemplateQueried;
MockNodeClass(String name) {
this.name = name;
}
@Override
public String toString() {
return "MockNodeClass{" + "name=" + name + '}';
}
}
}

View File

@ -514,30 +514,61 @@ public class Graph {
/**
* A node was added to a graph.
*/
NODE_ADDED;
NODE_ADDED,
/**
* A node was removed from the graph.
*/
NODE_REMOVED;
}
/**
* Client interested in one or more node related events.
*/
public interface NodeEventListener {
public abstract static class NodeEventListener {
/**
* Default handler for events.
* A method called when a change event occurs.
*
* This method dispatches the event to user-defined triggers. The methods that change the
* graph (typically in Graph and Node) must call this method to dispatch the event.
*
* @param e an event
* @param node the node related to {@code e}
*/
default void event(NodeEvent e, Node node) {
final void event(NodeEvent e, Node node) {
switch (e) {
case INPUT_CHANGED:
inputChanged(node);
break;
case ZERO_USAGES:
usagesDroppedToZero(node);
break;
case NODE_ADDED:
nodeAdded(node);
break;
case NODE_REMOVED:
nodeRemoved(node);
break;
}
changed(e, node);
}
/**
* Notifies this listener of a change in a node's inputs.
* Notifies this listener about any change event in the graph.
*
* @param e an event
* @param node the node related to {@code e}
*/
public void changed(NodeEvent e, Node node) {
}
/**
* Notifies this listener about a change in a node's inputs.
*
* @param node a node who has had one of its inputs changed
*/
default void inputChanged(Node node) {
event(NodeEvent.INPUT_CHANGED, node);
public void inputChanged(Node node) {
}
/**
@ -545,8 +576,7 @@ public class Graph {
*
* @param node a node whose {@link Node#usages()} just became empty
*/
default void usagesDroppedToZero(Node node) {
event(NodeEvent.ZERO_USAGES, node);
public void usagesDroppedToZero(Node node) {
}
/**
@ -554,8 +584,15 @@ public class Graph {
*
* @param node a node that was just added to the graph
*/
default void nodeAdded(Node node) {
event(NodeEvent.NODE_ADDED, node);
public void nodeAdded(Node node) {
}
/**
* Notifies this listener of a removed node.
*
* @param node
*/
public void nodeRemoved(Node node) {
}
}
@ -583,7 +620,7 @@ public class Graph {
}
}
private static class ChainedNodeEventListener implements NodeEventListener {
private static class ChainedNodeEventListener extends NodeEventListener {
NodeEventListener head;
NodeEventListener next;
@ -595,20 +632,32 @@ public class Graph {
@Override
public void nodeAdded(Node node) {
head.nodeAdded(node);
next.nodeAdded(node);
head.event(NodeEvent.NODE_ADDED, node);
next.event(NodeEvent.NODE_ADDED, node);
}
@Override
public void inputChanged(Node node) {
head.inputChanged(node);
next.inputChanged(node);
head.event(NodeEvent.INPUT_CHANGED, node);
next.event(NodeEvent.INPUT_CHANGED, node);
}
@Override
public void usagesDroppedToZero(Node node) {
head.usagesDroppedToZero(node);
next.usagesDroppedToZero(node);
head.event(NodeEvent.ZERO_USAGES, node);
next.event(NodeEvent.ZERO_USAGES, node);
}
@Override
public void nodeRemoved(Node node) {
head.event(NodeEvent.NODE_REMOVED, node);
next.event(NodeEvent.NODE_REMOVED, node);
}
@Override
public void changed(NodeEvent e, Node node) {
head.event(e, node);
next.event(e, node);
}
}
@ -1023,7 +1072,7 @@ public class Graph {
updateNodeCaches(node);
if (nodeEventListener != null) {
nodeEventListener.nodeAdded(node);
nodeEventListener.event(NodeEvent.NODE_ADDED, node);
}
afterRegister(node);
}
@ -1085,6 +1134,10 @@ public class Graph {
nodes[node.id] = null;
nodesDeletedSinceLastCompression++;
if (nodeEventListener != null) {
nodeEventListener.event(NodeEvent.NODE_ADDED, node);
}
// nodes aren't removed from the type cache here - they will be removed during iteration
}

View File

@ -752,7 +752,7 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
assert !graph.isFrozen();
NodeEventListener listener = graph.nodeEventListener;
if (listener != null) {
listener.inputChanged(node);
listener.event(Graph.NodeEvent.INPUT_CHANGED, node);
}
}
}
@ -762,7 +762,7 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
assert !graph.isFrozen();
NodeEventListener listener = graph.nodeEventListener;
if (listener != null && node.isAlive()) {
listener.usagesDroppedToZero(node);
listener.event(Graph.NodeEvent.ZERO_USAGES, node);
}
}
}

View File

@ -183,8 +183,7 @@ public class AArch64HotSpotNodeLIRBuilder extends AArch64NodeLIRBuilder implemen
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
node.arguments());
Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new AArch64BreakpointOp(parameters));
}
}

View File

@ -32,7 +32,6 @@ import org.graalvm.compiler.core.amd64.AMD64AddressLowering;
import org.graalvm.compiler.core.amd64.AMD64AddressNode;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.CounterKey;
@ -44,6 +43,7 @@ import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.CompressionNode;
import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
@ -93,76 +93,76 @@ public class AMD64HotSpotAddressLowering extends AMD64AddressLowering {
}
@Override
protected boolean improve(DebugContext debug, AMD64AddressNode addr) {
boolean result = false;
while (super.improve(debug, addr)) {
result = true;
protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) {
if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) {
return true;
}
if (addr.getScale() == Scale.Times1) {
if (addr.getIndex() instanceof CompressionNode) {
if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase())) {
if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase(), isBaseNegated, isIndexNegated)) {
counterFoldedUncompressDuringAddressLowering.increment(debug);
return true;
}
}
if (addr.getBase() instanceof CompressionNode) {
if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex())) {
if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex(), isBaseNegated, isIndexNegated)) {
counterFoldedUncompressDuringAddressLowering.increment(debug);
return true;
}
}
}
return result;
return false;
}
private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other) {
if (compression.getOp() == CompressionOp.Uncompress) {
CompressEncoding encoding = compression.getEncoding();
Scale scale = Scale.fromShift(encoding.getShift());
if (scale == null) {
@Override
protected boolean mightBeOptimized(ValueNode value) {
return super.mightBeOptimized(value) || value instanceof CompressionNode;
}
private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other, boolean isBaseNegated, boolean isIndexNegated) {
if (isBaseNegated || isIndexNegated || compression.getOp() != CompressionOp.Uncompress) {
return false;
}
CompressEncoding encoding = compression.getEncoding();
Scale scale = Scale.fromShift(encoding.getShift());
if (scale == null) {
return false;
}
if (heapBaseRegister != null && encoding.getBase() == heapBase) {
if ((!generatePIC || compression.stamp() instanceof ObjectStamp) && other == null) {
// With PIC it is only legal to do for oops since the base value may be
// different at runtime.
ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister));
addr.setBase(base);
} else {
return false;
}
if (heapBaseRegister != null && encoding.getBase() == heapBase) {
if ((!generatePIC || compression.stamp() instanceof ObjectStamp) && other == null) {
// With PIC it is only legal to do for oops since the base value may be
// different at runtime.
ValueNode base = compression.graph().unique(new HeapBaseNode(heapBaseRegister));
} else if (encoding.getBase() != 0 || (generatePIC && compression.stamp() instanceof KlassPointerStamp)) {
if (generatePIC) {
if (other == null) {
ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long));
addr.setBase(base);
} else {
return false;
}
} else if (encoding.getBase() != 0 || (generatePIC && compression.stamp() instanceof KlassPointerStamp)) {
if (generatePIC) {
if (other == null) {
ValueNode base = compression.graph().unique(new GraalHotSpotVMConfigNode(config, config.MARKID_NARROW_KLASS_BASE_ADDRESS, JavaKind.Long));
addr.setBase(base);
} else {
return false;
}
} else {
long disp = addr.getDisplacement() + encoding.getBase();
if (NumUtil.isInt(disp)) {
addr.setDisplacement((int) disp);
addr.setBase(other);
} else {
return false;
}
}
} else {
addr.setBase(other);
if (updateDisplacement(addr, encoding.getBase(), isBaseNegated)) {
addr.setBase(other);
} else {
return false;
}
}
addr.setScale(scale);
addr.setIndex(compression.getValue());
return true;
} else {
return false;
addr.setBase(other);
}
addr.setScale(scale);
addr.setIndex(compression.getValue());
return true;
}
}

View File

@ -39,7 +39,6 @@ import java.util.List;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
import org.graalvm.compiler.core.amd64.AMD64LIRGenerator;
import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
import org.graalvm.compiler.core.amd64.AMD64MoveFactoryBase.BackupSlotProvider;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
@ -116,7 +115,7 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
}
private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
this(new AMD64LIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
}
protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
@ -363,7 +362,7 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
Stub stub = getStub();
if (destroysRegisters) {
if (stub != null && stub.preservesRegisters()) {
Register[] savedRegisters = getResult().getFrameMapBuilder().getRegisterConfig().getAllocatableRegisters().toArray();
Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
save = emitSaveAllRegisters(savedRegisters, true);
}
}
@ -567,28 +566,29 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
@Override
public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
LIRKind inputKind = pointer.getValueKind(LIRKind.class);
assert inputKind.getPlatformKind() == AMD64Kind.QWORD;
LIRKindTool lirKindTool = getLIRKindTool();
assert inputKind.getPlatformKind() == lirKindTool.getObjectKind().getPlatformKind();
if (inputKind.isReference(0)) {
// oop
Variable result = newVariable(LIRKind.reference(AMD64Kind.DWORD));
append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
Variable result = newVariable(lirKindTool.getNarrowOopKind());
append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool()));
return result;
} else {
// metaspace pointer
Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
Variable result = newVariable(lirKindTool.getNarrowPointerKind());
AllocatableValue base = Value.ILLEGAL;
OptionValues options = getResult().getLIR().getOptions();
if (encoding.hasBase() || GeneratePIC.getValue(options)) {
if (GeneratePIC.getValue(options)) {
Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
Variable baseAddress = newVariable(lirKindTool.getWordKind());
AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
append(move);
base = baseAddress;
} else {
base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase()));
}
}
append(new AMD64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool()));
return result;
}
}
@ -596,35 +596,37 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
@Override
public Value emitUncompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
LIRKind inputKind = pointer.getValueKind(LIRKind.class);
assert inputKind.getPlatformKind() == AMD64Kind.DWORD;
LIRKindTool lirKindTool = getLIRKindTool();
assert inputKind.getPlatformKind() == lirKindTool.getNarrowOopKind().getPlatformKind();
if (inputKind.isReference(0)) {
// oop
Variable result = newVariable(LIRKind.reference(AMD64Kind.QWORD));
append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull));
Variable result = newVariable(lirKindTool.getObjectKind());
append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool));
return result;
} else {
// metaspace pointer
Variable result = newVariable(LIRKind.value(AMD64Kind.QWORD));
LIRKind uncompressedKind = lirKindTool.getWordKind();
Variable result = newVariable(uncompressedKind);
AllocatableValue base = Value.ILLEGAL;
OptionValues options = getResult().getLIR().getOptions();
if (encoding.hasBase() || GeneratePIC.getValue(options)) {
if (GeneratePIC.getValue(options)) {
Variable baseAddress = newVariable(LIRKind.value(AMD64Kind.QWORD));
Variable baseAddress = newVariable(uncompressedKind);
AMD64HotSpotMove.BaseMove move = new AMD64HotSpotMove.BaseMove(baseAddress, config);
append(move);
base = baseAddress;
} else {
base = emitLoadConstant(LIRKind.value(AMD64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase()));
}
}
append(new AMD64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool));
return result;
}
}
@Override
public void emitNullCheck(Value address, LIRFrameState state) {
if (address.getValueKind().getPlatformKind() == AMD64Kind.DWORD) {
if (address.getValueKind().getPlatformKind() == getLIRKindTool().getNarrowOopKind().getPlatformKind()) {
CompressEncoding encoding = config.getOopEncoding();
Value uncompressed;
if (encoding.getShift() <= 3) {
@ -635,9 +637,9 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
uncompressed = emitUncompress(address, encoding, false);
}
append(new AMD64Move.NullCheckOp(asAddressValue(uncompressed), state));
} else {
super.emitNullCheck(address, state);
return;
}
super.emitNullCheck(address, state);
}
@Override

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.amd64;
import jdk.vm.ci.amd64.AMD64Kind;
import org.graalvm.compiler.core.amd64.AMD64LIRKindTool;
import org.graalvm.compiler.core.common.LIRKind;
public class AMD64HotSpotLIRKindTool extends AMD64LIRKindTool {
@Override
public LIRKind getNarrowOopKind() {
return LIRKind.reference(AMD64Kind.DWORD);
}
@Override
public LIRKind getNarrowPointerKind() {
return LIRKind.value(AMD64Kind.DWORD);
}
}

View File

@ -24,16 +24,13 @@ package org.graalvm.compiler.hotspot.amd64;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isRegister;
import static jdk.vm.ci.code.ValueUtil.isStackSlot;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.amd64.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
import org.graalvm.compiler.debug.GraalError;
@ -41,10 +38,8 @@ import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
import org.graalvm.compiler.lir.amd64.AMD64Move;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import jdk.vm.ci.amd64.AMD64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
@ -180,91 +175,6 @@ public class AMD64HotSpotMove {
}
}
public static final class CompressPointer extends AMD64LIRInstruction {
public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
private final CompressEncoding encoding;
private final boolean nonNull;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue input;
@Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
super(TYPE);
this.result = result;
this.input = input;
this.baseRegister = baseRegister;
this.encoding = encoding;
this.nonNull = nonNull;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(AMD64Kind.QWORD, crb, masm, result, input);
Register resReg = asRegister(result);
if (encoding.hasBase() || GeneratePIC.getValue(crb.getOptions())) {
Register baseReg = asRegister(baseRegister);
if (!nonNull) {
masm.testq(resReg, resReg);
masm.cmovq(ConditionFlag.Equal, resReg, baseReg);
}
masm.subq(resReg, baseReg);
}
if (encoding.hasShift()) {
masm.shrq(resReg, encoding.getShift());
}
}
}
public static final class UncompressPointer extends AMD64LIRInstruction {
public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
private final CompressEncoding encoding;
private final boolean nonNull;
@Def({REG, HINT}) protected AllocatableValue result;
@Use({REG}) protected AllocatableValue input;
@Alive({REG, ILLEGAL}) protected AllocatableValue baseRegister;
public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull) {
super(TYPE);
this.result = result;
this.input = input;
this.baseRegister = baseRegister;
this.encoding = encoding;
this.nonNull = nonNull;
}
@Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
AMD64Move.move(AMD64Kind.DWORD, crb, masm, result, input);
Register resReg = asRegister(result);
if (encoding.getShift() != 0) {
masm.shlq(resReg, encoding.getShift());
}
if (encoding.hasBase() || GeneratePIC.getValue(crb.getOptions())) {
if (nonNull) {
masm.addq(resReg, asRegister(baseRegister));
} else {
if (!encoding.hasShift()) {
// if encoding.shift != 0, the flags are already set by the shlq
masm.testq(resReg, resReg);
}
Label done = new Label();
masm.jccb(ConditionFlag.Equal, done);
masm.addq(resReg, asRegister(baseRegister));
masm.bind(done);
}
}
}
}
public static void decodeKlassPointer(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register register, Register scratch, AMD64Address address, GraalHotSpotVMConfig config) {
CompressEncoding encoding = config.getKlassEncoding();
masm.movl(register, address);

View File

@ -189,8 +189,7 @@ public class AMD64HotSpotNodeLIRBuilder extends AMD64NodeLIRBuilder implements H
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
node.arguments());
Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new AMD64BreakpointOp(parameters));
}
}

View File

@ -113,8 +113,7 @@ public class SPARCHotSpotMove {
} else {
register = asRegister(result);
}
int bytes = result.getPlatformKind().getSizeInBytes();
loadFromConstantTable(crb, masm, bytes, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY);
int bytes = loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, register, SPARCDelayedControlTransfer.DUMMY);
if (isStack) {
masm.st(register, (SPARCAddress) crb.asAddress(result), bytes);
}

View File

@ -162,8 +162,7 @@ public class SPARCHotSpotNodeLIRBuilder extends SPARCNodeLIRBuilder implements H
sig[i] = node.arguments().get(i).stamp().javaType(gen.getMetaAccess());
}
Value[] parameters = visitInvokeArguments(gen.getResult().getFrameMapBuilder().getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen),
node.arguments());
Value[] parameters = visitInvokeArguments(gen.getRegisterConfig().getCallingConvention(HotSpotCallingConventionType.JavaCall, null, sig, gen), node.arguments());
append(new SPARCBreakpointOp(parameters));
}
}

View File

@ -77,8 +77,7 @@ final class SPARCHotSpotStrategySwitchOp extends SPARCControlFlow.StrategySwitch
boolean canUseShortBranch = masm.hasFeature(CPUFeature.CBCOND) && SPARCControlFlow.isShortBranch(masm, cbCondPosition, hint, target);
Register scratchRegister = asRegister(scratch);
final int byteCount = constant.isCompressed() ? 4 : 8;
loadFromConstantTable(crb, masm, byteCount, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY);
loadFromConstantTable(crb, masm, asRegister(constantTableBase), constant, scratchRegister, SPARCDelayedControlTransfer.DUMMY);
if (canUseShortBranch) {
CBCOND.emit(masm, conditionFlag, conditionCode == CC.Xcc, keyRegister, scratchRegister, target);

View File

@ -160,7 +160,7 @@ public class ArrayCopyIntrinsificationTest extends GraalCompilerTest {
}
/**
* Tests {@link ArrayCopySnippets#checkcastArraycopyWork}.
* Tests {@link ArrayCopySnippets#arraycopyCheckcastSnippet}.
*/
@Test
public void testArrayStoreException() {

View File

@ -122,7 +122,7 @@ public class CompilationWrapperTest extends GraalCompilerTest {
* Tests compilation requested by Truffle.
*/
@Test
public void testTruffleCompilation() throws IOException, InterruptedException {
public void testTruffleCompilation1() throws IOException, InterruptedException {
testHelper(Collections.emptyList(),
Arrays.asList(
"-Dgraal.CompilationFailureAction=ExitVM",
@ -130,6 +130,22 @@ public class CompilationWrapperTest extends GraalCompilerTest {
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
}
/**
* Tests that TruffleCompilationExceptionsAreFatal works as expected.
*/
@Test
public void testTruffleCompilation2() throws IOException, InterruptedException {
Probe[] probes = {
new Probe("Exiting VM due to TruffleCompilationExceptionsAreFatal=true", 1),
};
testHelper(Arrays.asList(probes),
Arrays.asList(
"-Dgraal.CompilationFailureAction=Silent",
"-Dgraal.TruffleCompilationExceptionsAreFatal=true",
"-Dgraal.CrashAt=root test1"),
"org.graalvm.compiler.truffle.test.SLTruffleGraalTestSuite", "test");
}
private static final boolean VERBOSE = Boolean.getBoolean(CompilationWrapperTest.class.getSimpleName() + ".verbose");
private static void testHelper(List<Probe> initialProbes, List<String> extraVmArgs, String... mainClassAndArgs) throws IOException, InterruptedException {
@ -149,14 +165,17 @@ public class CompilationWrapperTest extends GraalCompilerTest {
}
List<Probe> probes = new ArrayList<>(initialProbes);
Probe diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
probes.add(diagnosticProbe);
probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) {
@Override
String test() {
return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
}
});
Probe diagnosticProbe = null;
if (!extraVmArgs.contains("-Dgraal.TruffleCompilationExceptionsAreFatal=true")) {
diagnosticProbe = new Probe("Graal diagnostic output saved in ", 1);
probes.add(diagnosticProbe);
probes.add(new Probe("Forced crash after compiling", Integer.MAX_VALUE) {
@Override
String test() {
return actualOccurrences > 0 ? null : "expected at least 1 occurrence";
}
});
}
for (String line : proc.output) {
for (Probe probe : probes) {
@ -171,38 +190,42 @@ public class CompilationWrapperTest extends GraalCompilerTest {
Assert.fail(String.format("Did not find expected occurences of '%s' in output of command: %s%n%s", probe.substring, error, proc));
}
}
if (diagnosticProbe != null) {
String line = diagnosticProbe.lastMatchingLine;
int substringStart = line.indexOf(diagnosticProbe.substring);
int substringLength = diagnosticProbe.substring.length();
String diagnosticOutputZip = line.substring(substringStart + substringLength).trim();
String diagnosticOutputZip = diagnosticProbe.lastMatchingLine.substring(diagnosticProbe.substring.length()).trim();
List<String> dumpPathEntries = Arrays.asList(dumpPath.list());
List<String> dumpPathEntries = Arrays.asList(dumpPath.list());
File zip = new File(diagnosticOutputZip).getAbsoluteFile();
Assert.assertTrue(zip.toString(), zip.exists());
Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
try {
int bgv = 0;
int cfg = 0;
ZipFile dd = new ZipFile(diagnosticOutputZip);
List<String> entries = new ArrayList<>();
for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
ZipEntry ze = e.nextElement();
String name = ze.getName();
entries.add(name);
if (name.endsWith(".bgv")) {
bgv++;
} else if (name.endsWith(".cfg")) {
cfg++;
File zip = new File(diagnosticOutputZip).getAbsoluteFile();
Assert.assertTrue(zip.toString(), zip.exists());
Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
try {
int bgv = 0;
int cfg = 0;
ZipFile dd = new ZipFile(diagnosticOutputZip);
List<String> entries = new ArrayList<>();
for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
ZipEntry ze = e.nextElement();
String name = ze.getName();
entries.add(name);
if (name.endsWith(".bgv")) {
bgv++;
} else if (name.endsWith(".cfg")) {
cfg++;
}
}
if (bgv == 0) {
Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
}
if (cfg == 0) {
Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
}
} finally {
zip.delete();
dumpPath.delete();
}
if (bgv == 0) {
Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
}
if (cfg == 0) {
Assert.fail(String.format("Expected at least one .cfg file in %s: %s", diagnosticOutputZip, entries));
}
} finally {
zip.delete();
dumpPath.delete();
}
}
}

View File

@ -22,23 +22,44 @@
*/
package org.graalvm.compiler.hotspot.test;
import org.junit.Test;
import org.graalvm.compiler.core.test.GraalCompilerTest;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Assume;
import org.junit.Test;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.ProfilingInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.TriState;
public class ExplicitExceptionTest extends GraalCompilerTest {
private int expectedForeignCallCount;
/**
* Determines if profiling info for {@code method} indicates an exception was thrown somewhere
* in the method. In the case of the {@code -Xcomp} VM option, interpreter execution can be
* skipped altogether and other execution engines (e.g., C1) may not record seen exceptions in a
* method profile.
*/
private static boolean exceptionWasSeen(ResolvedJavaMethod method) {
ProfilingInfo profilingInfo = method.getProfilingInfo();
if (profilingInfo != null) {
for (int i = 0; i < profilingInfo.getCodeSize(); i++) {
if (profilingInfo.getExceptionSeen(i) == TriState.TRUE) {
return true;
}
}
}
return false;
}
@Override
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
InstalledCode installedCode = super.getCode(method, graph, forceCompile, installAsDefault, options);
Assume.assumeTrue(exceptionWasSeen(method));
assertDeepEquals(expectedForeignCallCount, lastCompiledGraph.getNodes().filter(ForeignCallNode.class).count());
return installedCode;
}

View File

@ -24,11 +24,13 @@ package org.graalvm.compiler.hotspot.test;
import java.lang.management.ManagementFactory;
import java.lang.management.MonitorInfo;
import java.lang.management.RuntimeMXBean;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.phases.HighTier;
@ -44,6 +46,7 @@ import org.junit.Test;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import org.junit.Assume;
import org.junit.BeforeClass;
/**
* Test on-stack-replacement with locks.
@ -51,13 +54,28 @@ import org.junit.Assume;
public class GraalOSRLockTest extends GraalOSRTestBase {
private static boolean TestInSeparateThread = false;
private static final String COMPILE_ONLY_FLAG = "-Xcomp";
public GraalOSRLockTest() {
@BeforeClass
public static void checkVMArguments() {
try {
Class.forName("java.lang.management.ManagementFactory");
} catch (ClassNotFoundException ex) {
Assume.assumeNoException("cannot check for monitors without java.management JDK9 module", ex);
}
/*
* Note: The -Xcomp execution mode of the VM will stop most of the OSR test cases from
* working as every method is compiled at level3 (followed by level4 on the second
* invocation). The tests in this class are written in a way that they expect a method to be
* executed at the invocation BCI with the interpreter and then perform an OSR to an
* installed nmethod at a given BCI.
*
*/
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
for (String arg : arguments) {
Assume.assumeFalse(arg.equals(COMPILE_ONLY_FLAG));
}
}
// testing only
@ -438,7 +456,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
return ret;
}
@ -449,11 +467,11 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
ReturnValue ret = ReturnValue.FAILURE;
synchronized (lock) {
synchronized (lock1) {
for (int i = 1; i < limit; i++) {
for (int i = 1; i < 10 * limit; i++) {
GraalDirectives.blackhole(i);
if (i % 1001 == 0) {
if (i % 33 == 0) {
ret = ReturnValue.SUCCESS;
if (GraalDirectives.inCompiledCode() && i + 33 > (limit)) {
if (GraalDirectives.inCompiledCode() && i + 33 > (10 * limit)) {
GraalDirectives.blackhole(ret);
System.gc();
}
@ -462,7 +480,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code already hereeeeee");
} else {
// lock 1 must be free
if (isMonitorLockHeld(lock1)) {
@ -519,7 +537,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
return ret;
}
@ -543,7 +561,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
return ret;
}
@ -568,7 +586,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
return ret;
}
@ -646,7 +664,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
synchronized (monitor) {
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
}
return ret;
@ -670,7 +688,7 @@ public class GraalOSRLockTest extends GraalOSRTestBase {
}
GraalDirectives.controlFlowAnchor();
if (!GraalDirectives.inCompiledCode()) {
throw new Error("Must part of compiled code");
throw new Error("Must be part of compiled code");
}
return ret;
}

View File

@ -35,7 +35,9 @@ import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.hotspot.CompilationTask;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.java.BciBlockMapping;
import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
import org.graalvm.compiler.nodes.StructuredGraph;
@ -76,6 +78,13 @@ public abstract class GraalOSRTestBase extends GraalCompilerTest {
HotSpotCompilationRequest request = new HotSpotCompilationRequest((HotSpotResolvedJavaMethod) method, bci, jvmciEnv);
HotSpotGraalCompiler compiler = (HotSpotGraalCompiler) runtime.getCompiler();
CompilationTask task = new CompilationTask(runtime, compiler, request, true, true, debug.getOptions());
if (method instanceof HotSpotResolvedJavaMethod) {
HotSpotGraalRuntimeProvider graalRuntime = compiler.getGraalRuntime();
GraalHotSpotVMConfig config = graalRuntime.getVMConfig();
if (((HotSpotResolvedJavaMethod) method).hasCodeAtLevel(bci, config.compilationLevelFullOptimization)) {
return;
}
}
HotSpotCompilationRequestResult result = task.runCompilation(debug);
if (result.getFailure() != null) {
throw new GraalError(result.getFailureMessage());

View File

@ -37,7 +37,6 @@ import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
import org.graalvm.compiler.hotspot.phases.WriteBarrierVerificationPhase;
import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopyNode;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.FieldLocationIdentity;
@ -629,12 +628,6 @@ public class WriteBarrierVerificationTest extends HotSpotGraalCompilerTest {
System.arraycopy(a, 0, b, 0, a.length);
}
@Test
public void test61() {
GraphPredicate checkForUnsafeArrayCopy = graph -> graph.getNodes().filter(UnsafeArrayCopyNode.class).count() > 0 ? 1 : 0;
testPredicate("test13Snippet", checkForUnsafeArrayCopy, new int[]{});
}
private interface GraphPredicate {
int apply(StructuredGraph graph);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2016, 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
@ -280,14 +280,19 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
}
if (offset == -1) {
try {
offset = getFieldOffset(name, Integer.class, "OopHandle");
offset = getFieldOffset(name, Integer.class, "jobject");
isHandle = true;
} catch (JVMCIError e) {
try {
// JDK-8186777
offset = getFieldOffset(name, Integer.class, "OopHandle");
isHandle = true;
} catch (JVMCIError e2) {
}
}
}
if (offset == -1) {
throw new JVMCIError("cannot get offset of field " + name + " with type oop or OopHandle");
throw new JVMCIError("cannot get offset of field " + name + " with type oop, jobject or OopHandle");
}
classMirrorOffset = offset;
classMirrorIsHandle = isHandle;
@ -648,6 +653,8 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
public final long heapEndAddress = getFieldValue("CompilerToVM::Data::_heap_end_addr", Long.class, "HeapWord**");
public final long heapTopAddress = getFieldValue("CompilerToVM::Data::_heap_top_addr", Long.class, isJDK8 ? "HeapWord**" : "HeapWord* volatile*");
public final boolean cmsIncrementalMode = getFlag("CMSIncrementalMode", Boolean.class, false);
public final long inlineCacheMissStub = getFieldValue("CompilerToVM::Data::SharedRuntime_ic_miss_stub", Long.class, "address");
public final long handleWrongMethodStub = getFieldValue("CompilerToVM::Data::SharedRuntime_handle_wrong_method_stub", Long.class, "address");

View File

@ -266,6 +266,8 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
unsafeArraycopyStub(HotSpotBackend.UNSAFE_ARRAYCOPY, srcAddr, dstAddr, size);
}
public static final ForeignCallDescriptor GENERIC_ARRAYCOPY = new ForeignCallDescriptor("generic_arraycopy", int.class, Word.class, int.class, Word.class, int.class, int.class);
@NodeIntrinsic(ForeignCallNode.class)
private static native void unsafeArraycopyStub(@ConstantNodeParameter ForeignCallDescriptor descriptor, Word srcAddr, Word dstAddr, Word size);

View File

@ -284,7 +284,7 @@ public class HotSpotGraalCompiler implements GraalJVMCICompiler {
public Object mbean() {
if (graalRuntime instanceof HotSpotGraalRuntime) {
return ((HotSpotGraalRuntime)graalRuntime).mbean();
return ((HotSpotGraalRuntime) graalRuntime).getMBean();
}
return null;
}

View File

@ -26,6 +26,8 @@ import static jdk.vm.ci.common.InitTimer.timer;
import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
import java.io.PrintStream;
import java.util.Map;
import java.util.Collections;
import org.graalvm.compiler.debug.MethodFilter;
import org.graalvm.compiler.options.Option;
@ -190,4 +192,11 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
}
return level;
}
public Map<String, Object> mbeans() {
HotSpotGraalCompiler compiler = createCompiler(HotSpotJVMCIRuntime.runtime());
String name = "org.graalvm.compiler.hotspot:type=Options";
Object bean = ((HotSpotGraalRuntime) compiler.getGraalRuntime()).getMBean();
return Collections.singletonMap(name, bean);
}
}

View File

@ -283,10 +283,8 @@ public final class HotSpotGraalMBean implements javax.management.DynamicMBean {
@Override
public javax.management.MBeanInfo getMBeanInfo() {
List<javax.management.MBeanAttributeInfo> attrs = new ArrayList<>();
if (registered != null) {
for (OptionDescriptor descr : allOptionDescriptors()) {
attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
}
for (OptionDescriptor descr : allOptionDescriptors()) {
attrs.add(new javax.management.MBeanAttributeInfo(descr.getName(), descr.getType().getName(), descr.getHelp(), true, true, false));
}
javax.management.MBeanOperationInfo[] ops = {
new javax.management.MBeanOperationInfo("dumpMethod", "Enable IGV dumps for provided method", new javax.management.MBeanParameterInfo[]{

View File

@ -317,7 +317,7 @@ public final class HotSpotGraalRuntime implements HotSpotGraalRuntimeProvider {
return compilationProblemsPerAction;
}
final Object mbean() {
Object getMBean() {
return mBean;
}
}

View File

@ -28,8 +28,8 @@ import static org.graalvm.compiler.core.common.GraalOptions.InlineVTableStubs;
import static org.graalvm.compiler.core.common.GraalOptions.OmitHotExceptionStacktrace;
import static org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProviderImpl.OSR_MIGRATION_END;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_KLASS_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_HANDLE_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_MIRROR_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.COMPRESSED_HUB_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.DISPLACED_MARK_WORD_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.HUB_LOCATION;
@ -41,6 +41,7 @@ import static org.graalvm.word.LocationIdentity.any;
import java.lang.ref.Reference;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
@ -90,10 +91,8 @@ import org.graalvm.compiler.hotspot.replacements.UnsafeLoadSnippets;
import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySlowPathNode;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyWithSlowPathNode;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyUnrollNode;
import org.graalvm.compiler.hotspot.replacements.arraycopy.UnsafeArrayCopySnippets;
import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.AbstractBeginNode;
@ -193,7 +192,7 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
public DefaultHotSpotLoweringProvider(HotSpotGraalRuntimeProvider runtime, MetaAccessProvider metaAccess, ForeignCallsProvider foreignCalls, HotSpotRegistersProvider registers,
HotSpotConstantReflectionProvider constantReflection, TargetDescription target) {
super(metaAccess, foreignCalls, target);
super(metaAccess, foreignCalls, target, runtime.getVMConfig().useCompressedOops);
this.runtime = runtime;
this.registers = registers;
this.constantReflection = constantReflection;
@ -216,7 +215,6 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
hashCodeSnippets = new HashCodeSnippets.Templates(options, factories, providers, target);
resolveConstantSnippets = new ResolveConstantSnippets.Templates(options, factories, providers, target);
profileSnippets = new ProfileSnippets.Templates(options, factories, providers, target);
providers.getReplacements().registerSnippetTemplateCache(new UnsafeArrayCopySnippets.Templates(options, factories, providers, target));
}
public MonitorSnippets.Templates getMonitorSnippets() {
@ -315,10 +313,8 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
}
} else if (n instanceof ArrayCopyNode) {
arraycopySnippets.lower((ArrayCopyNode) n, tool);
} else if (n instanceof ArrayCopySlowPathNode) {
arraycopySnippets.lower((ArrayCopySlowPathNode) n, tool);
} else if (n instanceof ArrayCopyUnrollNode) {
arraycopySnippets.lower((ArrayCopyUnrollNode) n, tool);
} else if (n instanceof ArrayCopyWithSlowPathNode) {
arraycopySnippets.lower((ArrayCopyWithSlowPathNode) n, tool);
} else if (n instanceof G1PreWriteBarrier) {
writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
} else if (n instanceof G1PostWriteBarrier) {
@ -495,20 +491,18 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
}
}
@Override
protected Stamp loadStamp(Stamp stamp, JavaKind kind, boolean compressible) {
if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
return HotSpotNarrowOopStamp.compressed((ObjectStamp) stamp, runtime.getVMConfig().getOopEncoding());
}
return super.loadStamp(stamp, kind, compressible);
private CompressEncoding getOopEncoding() {
return runtime.getVMConfig().getOopEncoding();
}
@Override
protected ValueNode implicitLoadConvert(JavaKind kind, ValueNode value, boolean compressible) {
if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
return new HotSpotCompressionNode(CompressionOp.Uncompress, value, runtime.getVMConfig().getOopEncoding());
}
return super.implicitLoadConvert(kind, value, compressible);
protected Stamp loadCompressedStamp(ObjectStamp stamp) {
return HotSpotNarrowOopStamp.compressed(stamp, getOopEncoding());
}
@Override
protected ValueNode newCompressionNode(CompressionOp op, ValueNode value) {
return new HotSpotCompressionNode(op, value, getOopEncoding());
}
@Override
@ -518,14 +512,6 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
return ConstantNode.forConstant(base, metaAccess, graph);
}
@Override
protected ValueNode implicitStoreConvert(JavaKind kind, ValueNode value, boolean compressible) {
if (kind == JavaKind.Object && compressible && runtime.getVMConfig().useCompressedOops) {
return new HotSpotCompressionNode(CompressionOp.Compress, value, runtime.getVMConfig().getOopEncoding());
}
return super.implicitStoreConvert(kind, value, compressible);
}
@Override
protected ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor) {
/*
@ -800,4 +786,9 @@ public class DefaultHotSpotLoweringProvider extends DefaultJavaLoweringProvider
public int arrayLengthOffset() {
return runtime.getVMConfig().arrayOopDescLengthOffset();
}
@Override
protected final JavaKind getStorageKind(ResolvedJavaField field) {
return field.getJavaKind();
}
}

View File

@ -39,6 +39,7 @@ import java.util.zip.CRC32;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
@ -68,6 +69,7 @@ import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
import org.graalvm.compiler.nodes.calc.LeftShiftNode;
import org.graalvm.compiler.nodes.graphbuilderconf.ForeignCallPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
@ -316,8 +318,8 @@ public class HotSpotGraphBuilderPlugins {
private static boolean readMetaspaceConstantPoolElement(GraphBuilderContext b, ValueNode constantPoolOop, ValueNode index, JavaKind elementKind, WordTypes wordTypes, GraalHotSpotVMConfig config) {
ValueNode constants = getMetaspaceConstantPool(b, constantPoolOop, wordTypes, config);
int shift = CodeUtil.log2(wordTypes.getWordKind().getByteCount());
ValueNode scaledIndex = b.add(new LeftShiftNode(index, b.add(ConstantNode.forInt(shift))));
ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forInt(config.constantPoolSize))));
ValueNode scaledIndex = b.add(new LeftShiftNode(IntegerConvertNode.convert(index, StampFactory.forKind(JavaKind.Long)), b.add(ConstantNode.forInt(shift))));
ValueNode offset = b.add(new AddNode(scaledIndex, b.add(ConstantNode.forLong(config.constantPoolSize))));
AddressNode elementAddress = b.add(new OffsetAddressNode(constants, offset));
boolean notCompressible = false;
ValueNode elementValue = WordOperationPlugin.readOp(b, elementKind, elementAddress, NamedLocationIdentity.getArrayLocation(elementKind), BarrierType.NONE, notCompressible);

View File

@ -34,6 +34,7 @@ import static org.graalvm.compiler.hotspot.HotSpotBackend.DECRYPT_WITH_ORIGINAL_
import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT;
import static org.graalvm.compiler.hotspot.HotSpotBackend.ENCRYPT_BLOCK;
import static org.graalvm.compiler.hotspot.HotSpotBackend.EXCEPTION_HANDLER;
import static org.graalvm.compiler.hotspot.HotSpotBackend.GENERIC_ARRAYCOPY;
import static org.graalvm.compiler.hotspot.HotSpotBackend.IC_MISS_HANDLER;
import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
import static org.graalvm.compiler.hotspot.HotSpotBackend.INVOCATION_EVENT;
@ -85,7 +86,6 @@ import static org.graalvm.compiler.hotspot.stubs.NewArrayStub.NEW_ARRAY_C;
import static org.graalvm.compiler.hotspot.stubs.NewInstanceStub.NEW_INSTANCE_C;
import static org.graalvm.compiler.hotspot.stubs.StubUtil.VM_MESSAGE_C;
import static org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub.EXCEPTION_HANDLER_FOR_RETURN_ADDRESS;
import static org.graalvm.compiler.nodes.NamedLocationIdentity.any;
import static org.graalvm.compiler.nodes.java.ForeignCallDescriptors.REGISTER_FINALIZER;
import static org.graalvm.compiler.replacements.Log.LOG_OBJECT;
import static org.graalvm.compiler.replacements.Log.LOG_PRIMITIVE;
@ -97,6 +97,7 @@ import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.Una
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.LOG10;
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
import static org.graalvm.word.LocationIdentity.any;
import java.util.EnumMap;
@ -213,7 +214,7 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
// c_rarg4 - oop ckval (super_klass)
// return: 0 = success, n = number of copied elements xor'd with -1.
ForeignCallDescriptor desc = new ForeignCallDescriptor(name, int.class, Word.class, Word.class, Word.class, Word.class, Word.class);
LocationIdentity killed = NamedLocationIdentity.getArrayLocation(JavaKind.Object);
LocationIdentity killed = NamedLocationIdentity.any();
registerForeignCall(desc, routine, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, killed);
checkcastArraycopyDescriptors[uninit ? 1 : 0] = desc;
}
@ -333,6 +334,7 @@ public abstract class HotSpotHostForeignCallsProvider extends HotSpotForeignCall
registerCheckcastArraycopyDescriptor(true, c.checkcastArraycopyUninit);
registerCheckcastArraycopyDescriptor(false, c.checkcastArraycopy);
registerForeignCall(GENERIC_ARRAYCOPY, c.genericArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
registerForeignCall(UNSAFE_ARRAYCOPY, c.unsafeArraycopy, NativeCall, DESTROYS_REGISTERS, LEAF_NOFP, NOT_REEXECUTABLE, NamedLocationIdentity.any());
if (c.useMultiplyToLenIntrinsic()) {

View File

@ -28,6 +28,7 @@ import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_16;
import org.graalvm.word.LocationIdentity;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
@ -35,7 +36,7 @@ import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
@NodeInfo(cycles = CYCLES_4, size = SIZE_16)
@NodeInfo(cycles = CYCLES_4, size = SIZE_16, allowedUsageTypes = {InputType.Memory})
public class ResolveDynamicConstantNode extends DeoptimizingFixedWithNextNode implements Lowerable, MemoryCheckpoint.Single {
public static final NodeClass<ResolveDynamicConstantNode> TYPE = NodeClass.create(ResolveDynamicConstantNode.class);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -71,6 +71,15 @@ public class ProfileBranchNode extends ProfileWithNotificationNode {
return branchCondition != null;
}
@Override
protected boolean canBeMergedWith(ProfileNode p) {
if (p instanceof ProfileBranchNode) {
ProfileBranchNode that = (ProfileBranchNode) p;
return this.method.equals(that.method) && this.bci == that.bci;
}
return false;
}
/**
* Gathers all the {@link ProfileBranchNode}s that are inputs to the
* {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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
@ -37,6 +37,15 @@ public class ProfileInvokeNode extends ProfileWithNotificationNode {
super(TYPE, method, freqLog, probabilityLog);
}
@Override
protected boolean canBeMergedWith(ProfileNode p) {
if (p instanceof ProfileInvokeNode) {
ProfileInvokeNode that = (ProfileInvokeNode) p;
return this.method.equals(that.method);
}
return false;
}
/**
* Gathers all the {@link ProfileInvokeNode}s that are inputs to the
* {@linkplain StructuredGraph#getNodes() live nodes} in a given graph.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, 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,11 +24,17 @@ package org.graalvm.compiler.hotspot.nodes.profiling;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
import static org.graalvm.compiler.nodes.util.GraphUtil.removeFixedWithUnusedInputs;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.graph.spi.Simplifiable;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.ControlSplitNode;
import org.graalvm.compiler.nodes.DeoptimizingFixedWithNextNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
@ -41,7 +47,7 @@ import org.graalvm.compiler.options.OptionType;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@NodeInfo(cycles = CYCLES_IGNORED, cyclesRationale = "profiling should be ignored", size = SIZE_IGNORED, sizeRationale = "profiling should be ignored")
public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowerable {
public abstract class ProfileNode extends DeoptimizingFixedWithNextNode implements Simplifiable, Lowerable {
public static class Options {
@Option(help = "Control probabilistic profiling on AMD64", type = OptionType.Expert)//
public static final OptionKey<Boolean> ProbabilisticProfiling = new OptionKey<>(true);
@ -54,19 +60,21 @@ public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowera
// Only used if ProbabilisticProfiling == true and may be ignored by lowerer.
@OptionalInput protected ValueNode random;
// logarithm base 2 of the profile probability
// Logarithm base 2 of the profile probability.
protected int probabilityLog;
// Step value to add to the profile counter.
protected int step;
protected ProfileNode(NodeClass<? extends DeoptimizingFixedWithNextNode> c, ResolvedJavaMethod method, int probabilityLog) {
super(c, StampFactory.forVoid());
this.method = method;
this.probabilityLog = probabilityLog;
this.step = 1;
}
public ProfileNode(ResolvedJavaMethod method, int probabilityLog) {
super(TYPE, StampFactory.forVoid());
this.method = method;
this.probabilityLog = probabilityLog;
this(TYPE, method, probabilityLog);
}
@Override
@ -92,6 +100,14 @@ public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowera
this.random = r;
}
public int getStep() {
return step;
}
public void setStep(int s) {
step = s;
}
/**
* Get the logarithm base 2 of the profile probability.
*/
@ -106,4 +122,25 @@ public class ProfileNode extends DeoptimizingFixedWithNextNode implements Lowera
public static NodeIterable<ProfileNode> getProfileNodes(StructuredGraph graph) {
return graph.getNodes().filter(ProfileNode.class);
}
protected abstract boolean canBeMergedWith(ProfileNode p);
@Override
public void simplify(SimplifierTool tool) {
for (Node p = predecessor(); p != null; p = p.predecessor()) {
// Terminate search when we hit a control split or merge.
if (p instanceof ControlSplitNode || p instanceof AbstractMergeNode) {
break;
}
if (p instanceof ProfileNode) {
ProfileNode that = (ProfileNode) p;
if (this.canBeMergedWith(that)) {
that.setStep(this.getStep() + that.getStep());
removeFixedWithUnusedInputs(this);
tool.addToWorkList(that);
break;
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,7 +28,7 @@ import org.graalvm.compiler.nodeinfo.NodeInfo;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@NodeInfo
public class ProfileWithNotificationNode extends ProfileNode {
public abstract class ProfileWithNotificationNode extends ProfileNode {
public static final NodeClass<ProfileWithNotificationNode> TYPE = NodeClass.create(ProfileWithNotificationNode.class);
protected int freqLog;

View File

@ -22,10 +22,16 @@
*/
package org.graalvm.compiler.hotspot.phases;
import static jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import org.graalvm.compiler.core.common.PermanentBailoutException;
import org.graalvm.compiler.core.common.cfg.Loop;
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugContext;
@ -37,13 +43,15 @@ import org.graalvm.compiler.loop.phases.LoopTransformations;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.AbstractBeginNode;
import org.graalvm.compiler.nodes.AbstractLocalNode;
import org.graalvm.compiler.nodes.EntryMarkerNode;
import org.graalvm.compiler.nodes.EntryProxyNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.LogicNode;
import org.graalvm.compiler.nodes.LoopBeginNode;
import org.graalvm.compiler.nodes.ParameterNode;
import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.StartNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
@ -53,6 +61,7 @@ import org.graalvm.compiler.nodes.extended.OSRLockNode;
import org.graalvm.compiler.nodes.extended.OSRMonitorEnterNode;
import org.graalvm.compiler.nodes.extended.OSRStartNode;
import org.graalvm.compiler.nodes.java.AccessMonitorNode;
import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.java.MonitorEnterNode;
import org.graalvm.compiler.nodes.java.MonitorExitNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
@ -172,15 +181,32 @@ public class OnStackReplacementPhase extends Phase {
if (value instanceof EntryProxyNode) {
EntryProxyNode proxy = (EntryProxyNode) value;
/*
* we need to drop the stamp since the types we see during OSR may be too precise
* (if a branch was not parsed for example).
* We need to drop the stamp since the types we see during OSR may be too precise
* (if a branch was not parsed for example). In cases when this is possible, we
* insert a guard and narrow the OSRLocal stamp at its usages.
*/
Stamp s = proxy.stamp().unrestricted();
AbstractLocalNode osrLocal = null;
Stamp narrowedStamp = proxy.value().stamp();
Stamp unrestrictedStamp = proxy.stamp().unrestricted();
ValueNode osrLocal;
if (i >= localsSize) {
osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, s));
osrLocal = graph.addOrUnique(new OSRLockNode(i - localsSize, unrestrictedStamp));
} else {
osrLocal = graph.addOrUnique(new OSRLocalNode(i, s));
osrLocal = graph.addOrUnique(new OSRLocalNode(i, unrestrictedStamp));
}
// Speculate on the OSRLocal stamps that could be more precise.
OSRLocalSpeculationReason reason = new OSRLocalSpeculationReason(osrState.bci, narrowedStamp, i);
if (graph.getSpeculationLog().maySpeculate(reason) && osrLocal instanceof OSRLocalNode && value.getStackKind().equals(JavaKind.Object) && !narrowedStamp.isUnrestricted()) {
// Add guard.
LogicNode check = graph.addOrUniqueWithInputs(InstanceOfNode.createHelper((ObjectStamp) narrowedStamp, osrLocal, null, null));
JavaConstant constant = graph.getSpeculationLog().speculate(reason);
FixedGuardNode guard = graph.add(new FixedGuardNode(check, DeoptimizationReason.OptimizedTypeCheckViolated, DeoptimizationAction.InvalidateRecompile, constant, false));
graph.addAfterFixed(osrStart, guard);
// Replace with a more specific type at usages.
// We know that we are at the root,
// so we need to replace the proxy in the state.
proxy.replaceAtMatchingUsages(osrLocal, n -> n == osrState);
osrLocal = graph.addOrUnique(new PiNode(osrLocal, narrowedStamp, guard));
}
proxy.replaceAndDelete(osrLocal);
} else {
@ -268,4 +294,30 @@ public class OnStackReplacementPhase extends Phase {
public float codeSizeIncrease() {
return 5.0f;
}
private static class OSRLocalSpeculationReason implements SpeculationReason {
private int bci;
private Stamp speculatedStamp;
private int localIndex;
OSRLocalSpeculationReason(int bci, Stamp speculatedStamp, int localIndex) {
this.bci = bci;
this.speculatedStamp = speculatedStamp;
this.localIndex = localIndex;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof OSRLocalSpeculationReason) {
OSRLocalSpeculationReason that = (OSRLocalSpeculationReason) obj;
return this.bci == that.bci && this.speculatedStamp.equals(that.speculatedStamp) && this.localIndex == that.localIndex;
}
return false;
}
@Override
public int hashCode() {
return (bci << 16) ^ speculatedStamp.hashCode() ^ localIndex;
}
}
}

View File

@ -669,6 +669,11 @@ public class HotSpotReplacementsUtil {
return config.useG1GC;
}
@Fold
public static boolean useCMSIncrementalMode(@InjectedParameter GraalHotSpotVMConfig config) {
return config.cmsIncrementalMode;
}
@Fold
public static boolean useCompressedOops(@InjectedParameter GraalHotSpotVMConfig config) {
return config.useCompressedOops;

View File

@ -71,7 +71,7 @@ public final class HubGetClassNode extends FloatingNode implements Lowerable, Ca
return null;
} else {
MetaAccessProvider metaAccess = tool.getMetaAccess();
if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(graph().getOptions())) {
if (metaAccess != null && hub.isConstant() && !GraalOptions.ImmutableCode.getValue(tool.getOptions())) {
ResolvedJavaType exactType = tool.getConstantReflection().asJavaType(hub.asConstant());
if (exactType != null) {
return ConstantNode.forConstant(tool.getConstantReflection().asJavaClass(exactType), metaAccess);

View File

@ -67,7 +67,7 @@ public class IdentityHashCodeNode extends FixedWithNextNode implements Canonical
if (object.isConstant()) {
assert object.stamp() instanceof AbstractObjectStamp;
JavaConstant c = (JavaConstant) object.asConstant();
if (ImmutableCode.getValue(getOptions())) {
if (ImmutableCode.getValue(tool.getOptions())) {
return this;
}
JavaConstant identityHashCode = null;

View File

@ -28,11 +28,12 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayClassElementOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperElementTypePrimitiveInPlace;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHub;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.superCheckOffsetOffset;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FAST_PATH_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.FREQUENT_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.LIKELY_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
@ -47,10 +48,8 @@ import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.CallTargetNode;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.DeoptimizeNode;
import org.graalvm.compiler.nodes.Invoke;
import org.graalvm.compiler.nodes.InvokeNode;
@ -65,8 +64,10 @@ import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.replacements.ReplacementsUtil;
import org.graalvm.compiler.replacements.SnippetCounter;
import org.graalvm.compiler.replacements.SnippetCounter.Group;
import org.graalvm.compiler.replacements.SnippetIntegerHistogram;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
@ -79,16 +80,208 @@ import org.graalvm.word.LocationIdentity;
import org.graalvm.word.WordFactory;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
public class ArrayCopySnippets implements Snippets {
private enum ArrayCopyTypeCheck {
UNDEFINED_ARRAY_TYPE_CHECK,
// we know that both objects are arrays and have the same type
NO_ARRAY_TYPE_CHECK,
// can be used when we know that one of the objects is a primitive array
HUB_BASED_ARRAY_TYPE_CHECK,
// must be used when we don't have sufficient information to use one of the others
LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK
}
@Snippet
public static void arraycopyZeroLengthSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
@ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
counters.zeroLengthStaticCounter.inc();
}
@Snippet
public static void arraycopyExactSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
@ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter elementKindCounter, @ConstantParameter SnippetCounter elementKindCopiedCounter,
@ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
incrementLengthCounter(length, counters);
elementKindCounter.inc();
elementKindCopiedCounter.add(length);
ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
}
@Snippet
public static void arraycopyUnrolledSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
@ConstantParameter JavaKind elementKind, @ConstantParameter int unrolledLength, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
incrementLengthCounter(length, counters);
unrolledArraycopyWork(nonNullSrc, srcPos, nonNullDest, destPos, unrolledLength, elementKind);
}
@Snippet
public static void arraycopyCheckcastSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck,
@ConstantParameter Counters counters, @ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
incrementLengthCounter(length, counters);
ArrayCopyWithSlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind);
}
@Snippet
public static void arraycopyGenericSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter ArrayCopyTypeCheck arrayTypeCheck, @ConstantParameter Counters counters,
@ConstantParameter SnippetInfo workSnippet, @ConstantParameter JavaKind elementKind) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkArrayTypes(nonNullSrc, nonNullDest, arrayTypeCheck);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
incrementLengthCounter(length, counters);
ArrayCopyWithSlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, workSnippet, elementKind);
}
@Snippet
public static void arraycopyNativeSnippet(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
// all checks are done in the native method, so no need to emit additional checks here
incrementLengthCounter(length, counters);
counters.systemArraycopyCounter.inc();
counters.systemArraycopyCopiedCounter.add(length);
System.arraycopy(src, srcPos, dest, destPos, length);
}
@Fold
static LocationIdentity getArrayLocation(JavaKind kind) {
return NamedLocationIdentity.getArrayLocation(kind);
}
private static void unrolledArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, JavaKind elementKind) {
int scale = arrayIndexScale(elementKind);
int arrayBaseOffset = arrayBaseOffset(elementKind);
LocationIdentity arrayLocation = getArrayLocation(elementKind);
long sourceOffset = arrayBaseOffset + (long) srcPos * scale;
long destOffset = arrayBaseOffset + (long) destPos * scale;
long position = 0;
long delta = scale;
if (probability(NOT_FREQUENT_PROBABILITY, nonNullSrc == nonNullDest && srcPos < destPos)) {
// bad aliased case so we need to copy the array from back to front
position = (long) (length - 1) * scale;
delta = -delta;
}
// the length was already checked before - we can emit unconditional instructions
ExplodeLoopNode.explodeLoop();
for (int iteration = 0; iteration < length; iteration++) {
Object value = RawLoadNode.load(nonNullSrc, sourceOffset + position, elementKind, arrayLocation);
RawStoreNode.storeObject(nonNullDest, destOffset + position, value, elementKind, arrayLocation, false);
position += delta;
}
}
@Snippet(allowPartialIntrinsicArgumentMismatch = true)
public static void checkcastArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
if (probability(FREQUENT_PROBABILITY, length > 0)) {
Object nonNullSrc = PiNode.asNonNullObject(src);
Object nonNullDest = PiNode.asNonNullObject(dest);
KlassPointer srcKlass = loadHub(nonNullSrc);
KlassPointer destKlass = loadHub(nonNullDest);
if (probability(LIKELY_PROBABILITY, srcKlass == destKlass)) {
// no storecheck required.
counters.objectCheckcastSameTypeCounter.inc();
counters.objectCheckcastSameTypeCopiedCounter.add(length);
ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
} else {
KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
Word superCheckOffset = WordFactory.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
counters.objectCheckcastDifferentTypeCounter.inc();
counters.objectCheckcastDifferentTypeCopiedCounter.add(length);
int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) {
/*
* the stub doesn't throw the ArrayStoreException, but returns the number of
* copied elements (xor'd with -1).
*/
copiedElements ^= -1;
System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
}
}
}
}
@Snippet(allowPartialIntrinsicArgumentMismatch = true)
public static void genericArraycopyWithSlowPathWork(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
if (probability(FREQUENT_PROBABILITY, length > 0)) {
counters.genericArraycopyDifferentTypeCounter.inc();
counters.genericArraycopyDifferentTypeCopiedCounter.add(length);
int copiedElements = GenericArrayCopyCallNode.genericArraycopy(src, srcPos, dest, destPos, length);
if (probability(SLOW_PATH_PROBABILITY, copiedElements != 0)) {
/*
* the stub doesn't throw the ArrayStoreException, but returns the number of copied
* elements (xor'd with -1).
*/
copiedElements ^= -1;
System.arraycopy(src, srcPos + copiedElements, dest, destPos + copiedElements, length - copiedElements);
}
}
}
private static void incrementLengthCounter(int length, Counters counters) {
counters.lengthHistogram.inc(length);
}
private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length, Counters counters) {
if (probability(SLOW_PATH_PROBABILITY, srcPos < 0) ||
probability(SLOW_PATH_PROBABILITY, destPos < 0) ||
probability(SLOW_PATH_PROBABILITY, length < 0) ||
probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length) ||
probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
counters.checkSuccessCounter.inc();
}
private static void checkArrayTypes(Object nonNullSrc, Object nonNullDest, ArrayCopyTypeCheck arrayTypeCheck) {
if (arrayTypeCheck == ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK) {
// nothing to do
} else if (arrayTypeCheck == ArrayCopyTypeCheck.HUB_BASED_ARRAY_TYPE_CHECK) {
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
} else if (arrayTypeCheck == ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK) {
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
checkArrayType(srcHub);
checkArrayType(destHub);
} else {
ReplacementsUtil.staticAssert(false, "unknown array type check");
}
}
private static int checkArrayType(KlassPointer nonNullHub) {
int layoutHelper = readLayoutHelper(nonNullHub);
if (probability(SLOW_PATH_PROBABILITY, layoutHelper >= 0)) {
@ -97,528 +290,228 @@ public class ArrayCopySnippets implements Snippets {
return layoutHelper;
}
private static void checkLimits(Object src, int srcPos, Object dest, int destPos, int length, Counters counters) {
if (probability(SLOW_PATH_PROBABILITY, srcPos < 0)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
if (probability(SLOW_PATH_PROBABILITY, destPos < 0)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
if (probability(SLOW_PATH_PROBABILITY, length < 0)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
if (probability(SLOW_PATH_PROBABILITY, srcPos > ArrayLengthNode.arrayLength(src) - length)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
if (probability(SLOW_PATH_PROBABILITY, destPos > ArrayLengthNode.arrayLength(dest) - length)) {
counters.checkAIOOBECounter.inc();
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
counters.checkSuccessCounter.inc();
}
@Snippet
public static void arraycopyZeroLengthIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
checkArrayType(srcHub);
checkArrayType(destHub);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
counters.zeroLengthStaticCounter.inc();
}
@Snippet
public static void arraycopyExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind, @ConstantParameter SnippetCounter counter,
@ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
counter.inc();
copiedCounter.add(length);
ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
if (length == 0) {
counters.zeroLengthDynamicCounter.inc();
} else {
counters.nonZeroLengthDynamicCounter.inc();
counters.nonZeroLengthDynamicCopiedCounter.add(length);
}
}
/**
* This intrinsic is useful for the case where we know something statically about one of the
* inputs but not the other.
*/
@Snippet
public static void arraycopyPredictedExactIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter JavaKind elementKind,
@ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
if (probability(SLOW_PATH_PROBABILITY, srcHub != destHub)) {
DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
}
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
counter.inc();
copiedCounter.add(length);
ArrayCopyCallNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, elementKind);
if (length == 0) {
counters.zeroLengthDynamicCounter.inc();
} else {
counters.nonZeroLengthDynamicCounter.inc();
counters.nonZeroLengthDynamicCopiedCounter.add(length);
}
}
@Snippet
public static void arraycopyPredictedObjectWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer objectArrayKlass,
@ConstantParameter SnippetCounter counter, @ConstantParameter SnippetCounter copiedCounter, @ConstantParameter Counters counters) {
if (length > 0) {
KlassPointer srcHub = loadHub(PiNode.asNonNullObject(nonNullSrc));
KlassPointer destHub = loadHub(PiNode.asNonNullObject(nonNullDest));
if (probability(FAST_PATH_PROBABILITY, srcHub == destHub || destHub == objectArrayKlass)) {
counter.inc();
copiedCounter.add(length);
counters.predictedObjectArrayCopyFastPathCounter.inc();
counters.predictedObjectArrayCopyFastPathCopiedCounter.add(length);
ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
} else {
counters.predictedObjectArrayCopySlowPathCounter.inc();
counters.predictedObjectArrayCopySlowPathCopiedCounter.add(length);
System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
}
}
}
/**
* This is the basic template for the full arraycopy checks, including a check that the
* underlying type is really an array type.
*/
@Snippet
public static void arraycopySlowPathIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, KlassPointer predictedKlass, @ConstantParameter JavaKind elementKind,
@ConstantParameter SnippetInfo slowPath, @ConstantParameter Object slowPathArgument, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
checkArrayType(srcHub);
checkArrayType(destHub);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
if (length == 0) {
counters.zeroLengthDynamicCounter.inc();
} else {
counters.nonZeroLengthDynamicCounter.inc();
counters.nonZeroLengthDynamicCopiedCounter.add(length);
}
ArrayCopySlowPathNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, predictedKlass, elementKind, slowPath, slowPathArgument);
}
/**
* Snippet for unrolled arraycopy.
*/
@Snippet
public static void arraycopyUnrolledIntrinsic(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter int unrolledLength, @ConstantParameter JavaKind elementKind,
@ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
if (length == 0) {
counters.zeroLengthDynamicCounter.inc();
} else {
counters.nonZeroLengthDynamicCounter.inc();
counters.nonZeroLengthDynamicCopiedCounter.add(length);
}
ArrayCopyUnrollNode.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, unrolledLength, elementKind);
}
@Snippet
public static void checkcastArraycopyWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantParameter Counters counters) {
if (length > 0) {
KlassPointer destKlass = loadHub(nonNullDest);
KlassPointer srcKlass = loadHub(nonNullSrc);
if (probability(SLOW_PATH_PROBABILITY, srcKlass == destKlass)) {
// no storecheck required.
counters.objectCheckcastSameTypeCounter.inc();
counters.objectCheckcastSameTypeCopiedCounter.add(length);
ArrayCopyCallNode.arraycopyObjectKillsAny(nonNullSrc, srcPos, nonNullDest, destPos, length);
} else {
KlassPointer destElemKlass = destKlass.readKlassPointer(arrayClassElementOffset(INJECTED_VMCONFIG), OBJ_ARRAY_KLASS_ELEMENT_KLASS_LOCATION);
Word superCheckOffset = WordFactory.signed(destElemKlass.readInt(superCheckOffsetOffset(INJECTED_VMCONFIG), KLASS_SUPER_CHECK_OFFSET_LOCATION));
counters.objectCheckcastCounter.inc();
counters.objectCheckcastCopiedCounter.add(length);
int copiedElements = CheckcastArrayCopyCallNode.checkcastArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, superCheckOffset, destElemKlass, false);
if (copiedElements != 0) {
/*
* the checkcast stub doesn't throw the ArrayStoreException, but returns the
* number of copied elements (xor'd with -1).
*/
copiedElements ^= -1;
System.arraycopy(nonNullSrc, srcPos + copiedElements, nonNullDest, destPos + copiedElements, length - copiedElements);
}
}
}
}
@Snippet
public static void arraycopyGeneric(Object src, int srcPos, Object dest, int destPos, int length, @ConstantParameter Counters counters) {
Object nonNullSrc = GraalDirectives.guardingNonNull(src);
Object nonNullDest = GraalDirectives.guardingNonNull(dest);
KlassPointer srcHub = loadHub(nonNullSrc);
KlassPointer destHub = loadHub(nonNullDest);
if (probability(FAST_PATH_PROBABILITY, srcHub.equal(destHub)) && probability(FAST_PATH_PROBABILITY, nonNullSrc != nonNullDest)) {
int layoutHelper = checkArrayType(srcHub);
final boolean isObjectArray = ((layoutHelper & layoutHelperElementTypePrimitiveInPlace(INJECTED_VMCONFIG)) == 0);
checkLimits(nonNullSrc, srcPos, nonNullDest, destPos, length, counters);
if (probability(FAST_PATH_PROBABILITY, isObjectArray)) {
counters.genericObjectExactCallCounter.inc();
counters.genericObjectExactCallCopiedCounter.add(length);
ArrayCopyCallNode.disjointArraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length, JavaKind.Object);
} else {
counters.genericPrimitiveCallCounter.inc();
counters.genericPrimitiveCallCopiedCounter.add(length);
UnsafeArrayCopyNode.arraycopyPrimitive(nonNullSrc, srcPos, nonNullDest, destPos, length, layoutHelper);
}
} else {
counters.systemArraycopyCounter.inc();
counters.systemArraycopyCopiedCounter.add(length);
System.arraycopy(nonNullSrc, srcPos, nonNullDest, destPos, length);
}
}
@Fold
static LocationIdentity getArrayLocation(JavaKind kind) {
return NamedLocationIdentity.getArrayLocation(kind);
}
@Snippet
public static void arraycopyUnrolledWork(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, @ConstantParameter int length, @ConstantParameter JavaKind elementKind) {
final int scale = arrayIndexScale(elementKind);
int arrayBaseOffset = arrayBaseOffset(elementKind);
LocationIdentity arrayLocation = getArrayLocation(elementKind);
if (nonNullSrc == nonNullDest && srcPos < destPos) { // bad aliased case
long start = (long) (length - 1) * scale;
long i = start;
ExplodeLoopNode.explodeLoop();
for (int iteration = 0; iteration < length; iteration++) {
if (i >= 0) {
Object a = RawLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
RawStoreNode.storeObject(nonNullDest, arrayBaseOffset + i + (long) destPos * scale, a, elementKind, arrayLocation, false);
i -= scale;
}
}
} else {
long end = (long) length * scale;
long i = 0;
ExplodeLoopNode.explodeLoop();
for (int iteration = 0; iteration < length; iteration++) {
if (i < end) {
Object a = RawLoadNode.load(nonNullSrc, arrayBaseOffset + i + (long) srcPos * scale, elementKind, arrayLocation);
RawStoreNode.storeObject(nonNullDest, arrayBaseOffset + i + (long) destPos * scale, a, elementKind, arrayLocation, false);
i += scale;
}
}
}
}
static class Counters {
final SnippetCounter checkSuccessCounter;
final SnippetCounter checkAIOOBECounter;
final SnippetCounter objectCheckcastCounter;
final SnippetCounter objectCheckcastSameTypeCounter;
final SnippetCounter predictedObjectArrayCopySlowPathCounter;
final SnippetCounter predictedObjectArrayCopyFastPathCounter;
final SnippetCounter genericPrimitiveCallCounter;
final SnippetCounter genericObjectExactCallCounter;
final SnippetCounter systemArraycopyCounter;
final SnippetCounter zeroLengthStaticCounter;
final SnippetCounter zeroLengthDynamicCounter;
final SnippetCounter nonZeroLengthDynamicCounter;
final SnippetIntegerHistogram lengthHistogram;
final SnippetCounter nonZeroLengthDynamicCopiedCounter;
final SnippetCounter genericPrimitiveCallCopiedCounter;
final SnippetCounter genericObjectExactCallCopiedCounter;
final SnippetCounter systemArraycopyCounter;
final SnippetCounter systemArraycopyCopiedCounter;
final SnippetCounter objectCheckcastCopiedCounter;
final SnippetCounter genericArraycopyDifferentTypeCopiedCounter;
final SnippetCounter genericArraycopyDifferentTypeCounter;
final SnippetCounter objectCheckcastSameTypeCopiedCounter;
final SnippetCounter predictedObjectArrayCopySlowPathCopiedCounter;
final SnippetCounter predictedObjectArrayCopyFastPathCopiedCounter;
final SnippetCounter objectCheckcastSameTypeCounter;
final SnippetCounter objectCheckcastDifferentTypeCopiedCounter;
final SnippetCounter objectCheckcastDifferentTypeCounter;
final EnumMap<JavaKind, SnippetCounter> arraycopyCallCounters = new EnumMap<>(JavaKind.class);
final EnumMap<JavaKind, SnippetCounter> arraycopyCounters = new EnumMap<>(JavaKind.class);
final EnumMap<JavaKind, SnippetCounter> arraycopyCallCopiedCounters = new EnumMap<>(JavaKind.class);
final EnumMap<JavaKind, SnippetCounter> arraycopyCopiedCounters = new EnumMap<>(JavaKind.class);
Counters(SnippetCounter.Group.Factory factory) {
final Group checkCounters = factory.createSnippetCounterGroup("System.arraycopy checkInputs");
final Group counters = factory.createSnippetCounterGroup("System.arraycopy");
final Group copiedCounters = factory.createSnippetCounterGroup("System.arraycopy copied elements");
final Group lengthCounters = factory.createSnippetCounterGroup("System.arraycopy 0-length checks");
final Group callCounters = factory.createSnippetCounterGroup("System.arraycopy calls");
final Group copiedElementsCounters = factory.createSnippetCounterGroup("System.arraycopy copied elements");
final Group lengthCounters = factory.createSnippetCounterGroup("System.arraycopy with 0-length");
checkSuccessCounter = new SnippetCounter(checkCounters, "checkSuccess", "checkSuccess");
checkAIOOBECounter = new SnippetCounter(checkCounters, "checkAIOOBE", "checkAIOOBE");
objectCheckcastCounter = new SnippetCounter(counters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
objectCheckcastSameTypeCounter = new SnippetCounter(counters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
predictedObjectArrayCopySlowPathCounter = new SnippetCounter(counters, "Object[]{slow-path}", "used System.arraycopy slow path for predicted Object[] arrays");
predictedObjectArrayCopyFastPathCounter = new SnippetCounter(counters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
genericPrimitiveCallCounter = new SnippetCounter(counters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
genericObjectExactCallCounter = new SnippetCounter(counters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
systemArraycopyCounter = new SnippetCounter(counters, "genericObject", "call to System.arraycopy");
zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-length copy static", "calls where the length is statically 0");
lengthHistogram = new SnippetIntegerHistogram(lengthCounters, 2, "length", "length");
zeroLengthStaticCounter = new SnippetCounter(lengthCounters, "0-lengthcopy static", "arraycopy where the length is statically 0");
zeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "0-lengthcopy dynamically", "arraycopy where the length is dynamically 0");
nonZeroLengthDynamicCounter = new SnippetCounter(lengthCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
systemArraycopyCounter = new SnippetCounter(callCounters, "native System.arraycopy", "JNI-based System.arraycopy call");
systemArraycopyCopiedCounter = new SnippetCounter(copiedElementsCounters, "native System.arraycopy", "JNI-based System.arraycopy call");
nonZeroLengthDynamicCopiedCounter = new SnippetCounter(copiedCounters, "non-0-lengthcopy dynamically", "arraycopy where the length is dynamically not zero");
genericPrimitiveCallCopiedCounter = new SnippetCounter(copiedCounters, "genericPrimitive", "generic arraycopy snippet for primitive arrays");
genericObjectExactCallCopiedCounter = new SnippetCounter(copiedCounters, "genericObjectExact", "generic arraycopy snippet for special object arrays");
systemArraycopyCopiedCounter = new SnippetCounter(copiedCounters, "genericObject", "call to System.arraycopy");
genericArraycopyDifferentTypeCounter = new SnippetCounter(callCounters, "generic[] stub", "generic arraycopy stub");
genericArraycopyDifferentTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "generic[] stub", "generic arraycopy stub");
objectCheckcastCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{non-exact}", "arraycopy for non-exact Object[] arrays");
objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{same-type}", "arraycopy call for src.klass == dest.klass Object[] arrays");
predictedObjectArrayCopySlowPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{slow-path}",
"used System.arraycopy slow path for predicted Object[] arrays");
predictedObjectArrayCopyFastPathCopiedCounter = new SnippetCounter(copiedCounters, "Object[]{fast-path}", "used oop_arraycopy for predicted Object[] arrays");
createArraycopyCounter(JavaKind.Byte, counters, copiedCounters);
createArraycopyCounter(JavaKind.Boolean, counters, copiedCounters);
createArraycopyCounter(JavaKind.Char, counters, copiedCounters);
createArraycopyCounter(JavaKind.Short, counters, copiedCounters);
createArraycopyCounter(JavaKind.Int, counters, copiedCounters);
createArraycopyCounter(JavaKind.Long, counters, copiedCounters);
createArraycopyCounter(JavaKind.Float, counters, copiedCounters);
createArraycopyCounter(JavaKind.Double, counters, copiedCounters);
createArraycopyCounter(JavaKind.Object, counters, copiedCounters);
objectCheckcastSameTypeCounter = new SnippetCounter(callCounters, "checkcast object[] (same-type)", "checkcast object[] stub but src.klass == dest.klass Object[] arrays");
objectCheckcastSameTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "checkcast object[] (same-type)", "checkcast object[] stub but src.klass == dest.klass Object[] arrays");
objectCheckcastDifferentTypeCounter = new SnippetCounter(callCounters, "checkcast object[] (store-check)", "checkcast object[] stub with store check");
objectCheckcastDifferentTypeCopiedCounter = new SnippetCounter(copiedElementsCounters, "checkcast object[] (store-check)", "checkcast object[] stub with store check");
createArraycopyCounter(JavaKind.Byte, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Boolean, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Char, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Short, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Int, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Long, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Float, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Double, callCounters, copiedElementsCounters);
createArraycopyCounter(JavaKind.Object, callCounters, copiedElementsCounters);
}
void createArraycopyCounter(JavaKind kind, Group counters, Group copiedCounters) {
arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
arraycopyCounters.put(kind, new SnippetCounter(counters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{stub}", "arraycopy call for " + kind + "[] arrays"));
arraycopyCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[]{inline}", "inline arraycopy for " + kind + "[] arrays"));
arraycopyCallCounters.put(kind, new SnippetCounter(counters, kind + "[] stub", "arraycopy call for " + kind + "[] arrays"));
arraycopyCallCopiedCounters.put(kind, new SnippetCounter(copiedCounters, kind + "[] stub", "arraycopy call for " + kind + "[] arrays"));
}
}
public static class Templates extends SnippetTemplate.AbstractTemplates {
private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGenericSnippet");
private final SnippetInfo arraycopyUnrolledSnippet = snippet("arraycopyUnrolledSnippet");
private final SnippetInfo arraycopyExactSnippet = snippet("arraycopyExactSnippet");
private final SnippetInfo arraycopyZeroLengthSnippet = snippet("arraycopyZeroLengthSnippet");
private final SnippetInfo arraycopyCheckcastSnippet = snippet("arraycopyCheckcastSnippet");
private final SnippetInfo arraycopyNativeSnippet = snippet("arraycopyNativeSnippet");
private final SnippetInfo checkcastArraycopyWithSlowPathWork = snippet("checkcastArraycopyWithSlowPathWork");
private final SnippetInfo genericArraycopyWithSlowPathWork = snippet("genericArraycopyWithSlowPathWork");
private ResolvedJavaMethod originalArraycopy;
private final Counters counters;
public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, HotSpotProviders providers, TargetDescription target) {
super(options, factories, providers, providers.getSnippetReflection(), target);
this.counters = new Counters(factory);
}
private ResolvedJavaMethod originalArraycopy() throws GraalError {
if (originalArraycopy == null) {
Method method;
try {
method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
} catch (NoSuchMethodException | SecurityException e) {
throw new GraalError(e);
}
originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
}
return originalArraycopy;
}
private ResolvedJavaMethod originalArraycopy;
private final SnippetInfo checkcastArraycopyWorkSnippet = snippet("checkcastArraycopyWork");
private final SnippetInfo arraycopyGenericSnippet = snippet("arraycopyGeneric");
private final SnippetInfo arraycopySlowPathIntrinsicSnippet = snippet("arraycopySlowPathIntrinsic");
private final SnippetInfo arraycopyUnrolledIntrinsicSnippet = snippet("arraycopyUnrolledIntrinsic");
private final SnippetInfo arraycopyExactIntrinsicSnippet = snippet("arraycopyExactIntrinsic");
private final SnippetInfo arraycopyZeroLengthIntrinsicSnippet = snippet("arraycopyZeroLengthIntrinsic");
private final SnippetInfo arraycopyPredictedExactIntrinsicSnippet = snippet("arraycopyPredictedExactIntrinsic");
private final SnippetInfo arraycopyPredictedObjectWorkSnippet = snippet("arraycopyPredictedObjectWork");
private final SnippetInfo arraycopyUnrolledWorkSnippet = snippet("arraycopyUnrolledWork");
private final Counters counters;
protected SnippetInfo snippet(String methodName) {
SnippetInfo info = snippet(ArrayCopySnippets.class, methodName, LocationIdentity.any());
info.setOriginalMethod(originalArraycopy());
return info;
}
public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) {
return selectComponentKind(arraycopy, true);
}
public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
JavaKind elementKind = selectComponentKind(arraycopy);
SnippetInfo snippetInfo;
ArrayCopyTypeCheck arrayTypeCheck;
public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy, boolean exact) {
ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
if (!exact) {
JavaKind component = getComponentKind(srcType);
if (component != null) {
return component;
}
return getComponentKind(destType);
}
return null;
}
if (exact) {
if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
return null;
}
if (!arraycopy.isExact()) {
return null;
}
}
return srcType.getComponentType().getJavaKind();
}
private static JavaKind getComponentKind(ResolvedJavaType type) {
if (type != null && type.isArray()) {
return type.getComponentType().getJavaKind();
}
return null;
}
private static boolean shouldUnroll(ValueNode length) {
return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
}
public void lower(ArrayCopyNode arraycopy, LoweringTool tool) {
JavaKind componentKind = selectComponentKind(arraycopy);
SnippetInfo snippetInfo = null;
SnippetInfo slowPathSnippetInfo = null;
Object slowPathArgument = null;
if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
snippetInfo = arraycopyZeroLengthIntrinsicSnippet;
} else if (arraycopy.isExact()) {
snippetInfo = arraycopyExactIntrinsicSnippet;
if (shouldUnroll(arraycopy.getLength())) {
snippetInfo = arraycopyUnrolledIntrinsicSnippet;
}
if (!canBeArray(srcType) || !canBeArray(destType)) {
// at least one of the objects is definitely not an array - use the native call
// right away as the copying will fail anyways
snippetInfo = arraycopyNativeSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
} else {
if (componentKind == JavaKind.Object) {
ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
if (srcComponentType != null && destComponentType != null && !srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
snippetInfo = arraycopySlowPathIntrinsicSnippet;
slowPathSnippetInfo = checkcastArraycopyWorkSnippet;
slowPathArgument = LocationIdentity.any();
/*
* Because this snippet has to use Sysytem.arraycopy as a slow path, we must
* pretend to kill any() so clear the componentKind.
*/
componentKind = null;
}
}
if (componentKind == null && snippetInfo == null) {
JavaKind predictedKind = selectComponentKind(arraycopy, false);
if (predictedKind != null) {
/*
* At least one array is of a known type requiring no store checks, so
* assume the other is of the same type. Generally this is working around
* deficiencies in our propagation of type information.
*/
componentKind = predictedKind;
if (predictedKind == JavaKind.Object) {
snippetInfo = arraycopySlowPathIntrinsicSnippet;
slowPathSnippetInfo = arraycopyPredictedObjectWorkSnippet;
slowPathArgument = predictedKind;
componentKind = null;
} else {
snippetInfo = arraycopyPredictedExactIntrinsicSnippet;
}
}
}
if (snippetInfo == null) {
ResolvedJavaType srcComponentType = srcType == null ? null : srcType.getComponentType();
ResolvedJavaType destComponentType = destType == null ? null : destType.getComponentType();
if (arraycopy.isExact()) {
// there is a sufficient type match - we don't need any additional type checks
snippetInfo = arraycopyExactSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK;
} else if (srcComponentType == null && destComponentType == null) {
// we don't know anything about the types - use the generic copying
snippetInfo = arraycopyGenericSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK;
} else if (srcComponentType != null && destComponentType != null) {
if (!srcComponentType.isPrimitive() && !destComponentType.isPrimitive()) {
// it depends on the array content if the copy succeeds - we need
// a type check for every store
snippetInfo = arraycopyCheckcastSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.NO_ARRAY_TYPE_CHECK;
} else {
// one object is an object array, the other one is a primitive array.
// this copy will always fail - use the native call right away
assert !srcComponentType.equals(destComponentType) : "must be handled by arraycopy.isExact()";
snippetInfo = arraycopyNativeSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
}
} else {
ResolvedJavaType nonNullComponentType = srcComponentType != null ? srcComponentType : destComponentType;
if (nonNullComponentType.isPrimitive()) {
// one involved object is a primitive array - we can safely assume that we
// are copying primitive arrays
snippetInfo = arraycopyExactSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.HUB_BASED_ARRAY_TYPE_CHECK;
elementKind = nonNullComponentType.getJavaKind();
} else {
// one involved object is an object array - we can safely assume that we are
// copying object arrays that might require a store check
snippetInfo = arraycopyCheckcastSnippet;
arrayTypeCheck = ArrayCopyTypeCheck.LAYOUT_HELPER_BASED_ARRAY_TYPE_CHECK;
}
}
}
// a few special cases that are easier to handle when all other variables already have a
// value
if (arraycopy.getLength().isConstant() && arraycopy.getLength().asJavaConstant().asLong() == 0) {
snippetInfo = arraycopyZeroLengthSnippet;
} else if (snippetInfo == arraycopyExactSnippet && shouldUnroll(arraycopy.getLength())) {
snippetInfo = arraycopyUnrolledSnippet;
}
// create the snippet
Arguments args = new Arguments(snippetInfo, arraycopy.graph().getGuardsStage(), tool.getLoweringStage());
args.add("src", arraycopy.getSource());
args.add("srcPos", arraycopy.getSourcePosition());
args.add("dest", arraycopy.getDestination());
args.add("destPos", arraycopy.getDestinationPosition());
args.add("length", arraycopy.getLength());
if (snippetInfo == arraycopyUnrolledIntrinsicSnippet) {
args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt());
args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
} else if (snippetInfo == arraycopySlowPathIntrinsicSnippet) {
ValueNode predictedKlass = null;
if (slowPathArgument == arraycopyPredictedObjectWorkSnippet) {
HotSpotResolvedObjectType arrayClass = (HotSpotResolvedObjectType) tool.getMetaAccess().lookupJavaType(Object[].class);
predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassNonNull(), arrayClass.klass(), tool.getMetaAccess(), arraycopy.graph());
} else {
predictedKlass = ConstantNode.forConstant(KlassPointerStamp.klassAlwaysNull(), JavaConstant.NULL_POINTER, tool.getMetaAccess(), arraycopy.graph());
}
args.add("predictedKlass", predictedKlass);
args.addConst("elementKind", componentKind != null ? componentKind : JavaKind.Illegal);
args.addConst("slowPath", slowPathSnippetInfo);
assert slowPathArgument != null;
args.addConst("slowPathArgument", slowPathArgument);
} else if (snippetInfo == arraycopyExactIntrinsicSnippet || snippetInfo == arraycopyPredictedExactIntrinsicSnippet) {
assert componentKind != null;
args.addConst("elementKind", componentKind);
args.addConst("counter", counters.arraycopyCallCounters.get(componentKind));
args.addConst("copiedCounter", counters.arraycopyCallCopiedCounters.get(componentKind));
if (snippetInfo != arraycopyNativeSnippet) {
assert arrayTypeCheck != ArrayCopyTypeCheck.UNDEFINED_ARRAY_TYPE_CHECK;
args.addConst("arrayTypeCheck", arrayTypeCheck);
}
if (snippetInfo == arraycopyUnrolledSnippet) {
args.addConst("elementKind", elementKind != null ? elementKind : JavaKind.Illegal);
args.addConst("unrolledLength", arraycopy.getLength().asJavaConstant().asInt());
}
if (snippetInfo == arraycopyExactSnippet) {
assert elementKind != null;
args.addConst("elementKind", elementKind);
args.addConst("elementKindCounter", counters.arraycopyCallCounters.get(elementKind));
args.addConst("elementKindCopiedCounter", counters.arraycopyCallCopiedCounters.get(elementKind));
}
args.addConst("counters", counters);
if (snippetInfo == arraycopyCheckcastSnippet) {
args.addConst("workSnippet", checkcastArraycopyWithSlowPathWork);
args.addConst("elementKind", JavaKind.Illegal);
}
if (snippetInfo == arraycopyGenericSnippet) {
args.addConst("workSnippet", genericArraycopyWithSlowPathWork);
args.addConst("elementKind", JavaKind.Illegal);
}
instantiate(args, arraycopy);
}
public void lower(ArrayCopyWithSlowPathNode arraycopy, LoweringTool tool) {
StructuredGraph graph = arraycopy.graph();
if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
// if an arraycopy contains a slow path, we can't lower it right away
return;
}
SnippetInfo snippetInfo = arraycopy.getSnippet();
Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
args.add("src", arraycopy.getSource());
args.add("srcPos", arraycopy.getSourcePosition());
args.add("dest", arraycopy.getDestination());
args.add("destPos", arraycopy.getDestinationPosition());
args.add("length", arraycopy.getLength());
args.addConst("counters", counters);
instantiate(args, arraycopy);
}
public void lower(ArrayCopySlowPathNode arraycopy, LoweringTool tool) {
StructuredGraph graph = arraycopy.graph();
if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
// Can't be lowered yet
return;
}
SnippetInfo snippetInfo = arraycopy.getSnippet();
Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
args.add("nonNullSrc", arraycopy.getSource());
args.add("srcPos", arraycopy.getSourcePosition());
args.add("nonNullDest", arraycopy.getDestination());
args.add("destPos", arraycopy.getDestinationPosition());
if (snippetInfo == arraycopyUnrolledWorkSnippet) {
args.addConst("length", ((Integer) arraycopy.getArgument()).intValue());
args.addConst("elementKind", arraycopy.getElementKind());
} else {
args.add("length", arraycopy.getLength());
}
if (snippetInfo == arraycopyPredictedObjectWorkSnippet) {
args.add("objectArrayKlass", arraycopy.getPredictedKlass());
args.addConst("counter", counters.arraycopyCallCounters.get(JavaKind.Object));
args.addConst("copiedCounter", counters.arraycopyCallCopiedCounters.get(JavaKind.Object));
args.addConst("counters", counters);
}
instantiate(args, arraycopy);
private static boolean canBeArray(ResolvedJavaType type) {
return type == null || type.isJavaLangObject() || type.isArray();
}
public void lower(ArrayCopyUnrollNode arraycopy, LoweringTool tool) {
StructuredGraph graph = arraycopy.graph();
if (!graph.getGuardsStage().areFrameStatesAtDeopts()) {
// Can't be lowered yet
return;
public static JavaKind selectComponentKind(BasicArrayCopyNode arraycopy) {
ResolvedJavaType srcType = StampTool.typeOrNull(arraycopy.getSource().stamp());
ResolvedJavaType destType = StampTool.typeOrNull(arraycopy.getDestination().stamp());
if (srcType == null || !srcType.isArray() || destType == null || !destType.isArray()) {
return null;
}
SnippetInfo snippetInfo = arraycopyUnrolledWorkSnippet;
Arguments args = new Arguments(snippetInfo, graph.getGuardsStage(), tool.getLoweringStage());
args.add("nonNullSrc", arraycopy.getSource());
args.add("srcPos", arraycopy.getSourcePosition());
args.add("nonNullDest", arraycopy.getDestination());
args.add("destPos", arraycopy.getDestinationPosition());
args.addConst("length", arraycopy.getUnrollLength());
args.addConst("elementKind", arraycopy.getElementKind());
template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args);
if (!destType.getComponentType().isAssignableFrom(srcType.getComponentType())) {
return null;
}
if (!arraycopy.isExact()) {
return null;
}
return srcType.getComponentType().getJavaKind();
}
private static boolean shouldUnroll(ValueNode length) {
return length.isConstant() && length.asJavaConstant().asInt() <= 8 && length.asJavaConstant().asInt() != 0;
}
/**
@ -650,8 +543,8 @@ public class ArrayCopySnippets implements Snippets {
newInvoke.setStateAfter(arraycopy.stateAfter());
}
graph.replaceFixedWithFixed((InvokeNode) invoke.asNode(), newInvoke);
} else if (originalNode instanceof ArrayCopySlowPathNode) {
ArrayCopySlowPathNode slowPath = (ArrayCopySlowPathNode) replacements.get(originalNode);
} else if (originalNode instanceof ArrayCopyWithSlowPathNode) {
ArrayCopyWithSlowPathNode slowPath = (ArrayCopyWithSlowPathNode) replacements.get(originalNode);
assert arraycopy.stateAfter() != null : arraycopy;
assert slowPath.stateAfter() == arraycopy.stateAfter();
slowPath.setBci(arraycopy.getBci());
@ -659,5 +552,18 @@ public class ArrayCopySnippets implements Snippets {
}
GraphUtil.killCFG(arraycopy);
}
private ResolvedJavaMethod originalArraycopy() throws GraalError {
if (originalArraycopy == null) {
Method method;
try {
method = System.class.getDeclaredMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
} catch (NoSuchMethodException | SecurityException e) {
throw new GraalError(e);
}
originalArraycopy = providers.getMetaAccess().lookupJavaMethod(method);
}
return originalArraycopy;
}
}
}

View File

@ -1,148 +0,0 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import jdk.vm.ci.meta.JavaKind;
import static org.graalvm.word.LocationIdentity.any;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
import org.graalvm.compiler.nodes.memory.MemoryAccess;
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.memory.MemoryNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.word.LocationIdentity;
@NodeInfo(allowedUsageTypes = InputType.Memory)
public class ArrayCopyUnrollNode extends ArrayRangeWriteNode implements MemoryCheckpoint.Single, Lowerable, MemoryAccess {
public static final NodeClass<ArrayCopyUnrollNode> TYPE = NodeClass.create(ArrayCopyUnrollNode.class);
@Input protected ValueNode src;
@Input protected ValueNode srcPos;
@Input protected ValueNode dest;
@Input protected ValueNode destPos;
@Input protected ValueNode length;
private JavaKind elementKind;
private int unrolledLength;
@OptionalInput(InputType.Memory) private MemoryNode lastLocationAccess;
public ArrayCopyUnrollNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, int unrolledLength, JavaKind elementKind) {
super(TYPE, StampFactory.forKind(JavaKind.Void));
this.src = src;
this.srcPos = srcPos;
this.dest = dest;
this.destPos = destPos;
this.length = length;
this.unrolledLength = unrolledLength;
assert elementKind != null && elementKind != JavaKind.Illegal;
this.elementKind = elementKind;
}
public ValueNode getSource() {
return src;
}
public ValueNode getSourcePosition() {
return srcPos;
}
public ValueNode getDestination() {
return dest;
}
public ValueNode getDestinationPosition() {
return destPos;
}
@Override
public ValueNode getLength() {
return length;
}
@Override
public ValueNode getArray() {
return dest;
}
@Override
public ValueNode getIndex() {
return destPos;
}
@Override
public boolean isObjectArray() {
return elementKind == JavaKind.Object;
}
@Override
public boolean isInitialization() {
return false;
}
@NodeIntrinsic
public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter int unrolledLength,
@ConstantNodeParameter JavaKind elementKind);
public int getUnrollLength() {
return unrolledLength;
}
public JavaKind getElementKind() {
return elementKind;
}
@Override
public LocationIdentity getLocationIdentity() {
if (elementKind != null) {
return NamedLocationIdentity.getArrayLocation(elementKind);
}
return any();
}
@Override
public void lower(LoweringTool tool) {
tool.getLowerer().lower(this, tool);
}
@Override
public MemoryNode getLastLocationAccess() {
return lastLocationAccess;
}
@Override
public void setLastLocationAccess(MemoryNode lla) {
updateUsagesInterface(lastLocationAccess, lla);
lastLocationAccess = lla;
}
}

View File

@ -22,76 +22,39 @@
*/
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.meta.JavaKind;
import static org.graalvm.word.LocationIdentity.any;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
import org.graalvm.word.LocationIdentity;
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.meta.JavaKind;
@NodeInfo(allowedUsageTypes = InputType.Memory)
public final class ArrayCopySlowPathNode extends BasicArrayCopyNode {
public final class ArrayCopyWithSlowPathNode extends BasicArrayCopyNode {
public static final NodeClass<ArrayCopySlowPathNode> TYPE = NodeClass.create(ArrayCopySlowPathNode.class);
public static final NodeClass<ArrayCopyWithSlowPathNode> TYPE = NodeClass.create(ArrayCopyWithSlowPathNode.class);
private final SnippetTemplate.SnippetInfo snippet;
/**
* Extra context for the slow path snippet.
*/
private final Object argument;
/**
* AOT compilation requires klass constants to be exposed after the first lowering to be handled
* automatically. Lowering for {@link ArrayCopySlowPathNode}, with snippet ==
* {@link ArrayCopySnippets#arraycopyPredictedObjectWork}, requires a klass of Object[]. For
* other snippets {@link #predictedKlass} is a null constant.
*/
@Input protected ValueNode predictedKlass;
public ArrayCopySlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode predictedKlass, JavaKind elementKind,
SnippetTemplate.SnippetInfo snippet, Object argument) {
public ArrayCopyWithSlowPathNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, SnippetTemplate.SnippetInfo snippet, JavaKind elementKind) {
super(TYPE, src, srcPos, dest, destPos, length, elementKind, BytecodeFrame.INVALID_FRAMESTATE_BCI);
assert StampTool.isPointerNonNull(src) && StampTool.isPointerNonNull(dest) : "must have been null checked";
this.snippet = snippet;
this.argument = argument;
this.predictedKlass = predictedKlass;
}
@NodeIntrinsic
public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, KlassPointer predictedKlass,
@ConstantNodeParameter JavaKind elementKind, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet, @ConstantNodeParameter Object argument);
public static native void arraycopy(Object nonNullSrc, int srcPos, Object nonNullDest, int destPos, int length, @ConstantNodeParameter SnippetTemplate.SnippetInfo snippet,
@ConstantNodeParameter JavaKind elementKind);
public SnippetTemplate.SnippetInfo getSnippet() {
return snippet;
}
public Object getArgument() {
return argument;
}
@Override
public LocationIdentity getLocationIdentity() {
if (elementKind != null) {
return NamedLocationIdentity.getArrayLocation(elementKind);
}
return any();
}
public void setBci(int bci) {
this.bci = bci;
}
public ValueNode getPredictedKlass() {
return predictedKlass;
}
}

View File

@ -23,12 +23,13 @@
//JaCoCo Exclude
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.type.PrimitiveStamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@ -114,8 +115,9 @@ public final class CheckcastArrayCopyCallNode extends AbstractMemoryCheckpoint i
graph().addBeforeFixed(this, basePtr);
int shift = CodeUtil.log2(getArrayIndexScale(JavaKind.Object));
ValueNode scaledIndex = graph().unique(new LeftShiftNode(pos, ConstantNode.forInt(shift, graph())));
ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forInt(getArrayBaseOffset(JavaKind.Object), graph())));
ValueNode extendedPos = IntegerConvertNode.convert(pos, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph());
ValueNode scaledIndex = graph().unique(new LeftShiftNode(extendedPos, ConstantNode.forInt(shift, graph())));
ValueNode offset = graph().unique(new AddNode(scaledIndex, ConstantNode.forIntegerBits(PrimitiveStamp.getBits(scaledIndex.stamp()), getArrayBaseOffset(JavaKind.Object), graph())));
return graph().unique(new OffsetAddressNode(basePtr, offset));
}

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
//JaCoCo Exclude
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.word.LocationIdentity;
import jdk.vm.ci.meta.JavaKind;
@NodeInfo(allowedUsageTypes = {InputType.Memory, InputType.Value}, cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
public final class GenericArrayCopyCallNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
public static final NodeClass<GenericArrayCopyCallNode> TYPE = NodeClass.create(GenericArrayCopyCallNode.class);
@Input ValueNode src;
@Input ValueNode srcPos;
@Input ValueNode dest;
@Input ValueNode destPos;
@Input ValueNode length;
protected final HotSpotGraalRuntimeProvider runtime;
protected GenericArrayCopyCallNode(@InjectedNodeParameter HotSpotGraalRuntimeProvider runtime, ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length) {
super(TYPE, StampFactory.forKind(JavaKind.Int));
this.src = src;
this.srcPos = srcPos;
this.dest = dest;
this.destPos = destPos;
this.length = length;
this.runtime = runtime;
}
public ValueNode getSource() {
return src;
}
public ValueNode getSourcePosition() {
return srcPos;
}
public ValueNode getDestination() {
return dest;
}
public ValueNode getDestinationPosition() {
return destPos;
}
public ValueNode getLength() {
return length;
}
@Override
public void lower(LoweringTool tool) {
if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
StructuredGraph graph = graph();
ValueNode srcAddr = objectAddress(getSource());
ValueNode destAddr = objectAddress(getDestination());
ForeignCallNode call = graph.add(new ForeignCallNode(runtime.getHostBackend().getForeignCalls(), HotSpotBackend.GENERIC_ARRAYCOPY, srcAddr, srcPos, destAddr, destPos, length));
call.setStateAfter(stateAfter());
graph.replaceFixedWithFixed(this, call);
}
}
private ValueNode objectAddress(ValueNode obj) {
GetObjectAddressNode result = graph().add(new GetObjectAddressNode(obj));
graph().addBeforeFixed(this, result);
return result;
}
private ValueNode wordValue(ValueNode value) {
if (value.stamp().getStackKind() != runtime.getTarget().wordJavaKind) {
return IntegerConvertNode.convert(value, StampFactory.forKind(runtime.getTarget().wordJavaKind), graph());
}
return value;
}
@Override
public LocationIdentity getLocationIdentity() {
return LocationIdentity.any();
}
@NodeIntrinsic
public static native int genericArraycopy(Object src, int srcPos, Object dest, int destPos, int length);
}

View File

@ -1,153 +0,0 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_256;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_64;
import static org.graalvm.word.LocationIdentity.any;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
import org.graalvm.compiler.nodes.memory.MemoryAccess;
import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
import org.graalvm.compiler.nodes.memory.MemoryNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.word.LocationIdentity;
import jdk.vm.ci.meta.JavaKind;
@NodeInfo(allowedUsageTypes = {InputType.Memory}, cycles = CYCLES_256, size = SIZE_64)
public final class UnsafeArrayCopyNode extends ArrayRangeWriteNode implements Lowerable, MemoryCheckpoint.Single, MemoryAccess {
public static final NodeClass<UnsafeArrayCopyNode> TYPE = NodeClass.create(UnsafeArrayCopyNode.class);
@Input ValueNode src;
@Input ValueNode srcPos;
@Input ValueNode dest;
@Input ValueNode destPos;
@Input ValueNode length;
@OptionalInput ValueNode layoutHelper;
@OptionalInput(InputType.Memory) MemoryNode lastLocationAccess;
protected JavaKind elementKind;
public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper, JavaKind elementKind) {
super(TYPE, StampFactory.forVoid());
assert layoutHelper == null || elementKind == null;
this.src = src;
this.srcPos = srcPos;
this.dest = dest;
this.destPos = destPos;
this.length = length;
this.layoutHelper = layoutHelper;
this.elementKind = elementKind;
}
public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, JavaKind elementKind) {
this(src, srcPos, dest, destPos, length, null, elementKind);
}
public UnsafeArrayCopyNode(ValueNode src, ValueNode srcPos, ValueNode dest, ValueNode destPos, ValueNode length, ValueNode layoutHelper) {
this(src, srcPos, dest, destPos, length, layoutHelper, null);
}
@Override
public ValueNode getArray() {
return dest;
}
@Override
public ValueNode getIndex() {
return destPos;
}
@Override
public ValueNode getLength() {
return length;
}
@Override
public boolean isObjectArray() {
return elementKind == JavaKind.Object;
}
@Override
public boolean isInitialization() {
return false;
}
public JavaKind getElementKind() {
return elementKind;
}
@Override
public void lower(LoweringTool tool) {
if (graph().getGuardsStage().areFrameStatesAtDeopts()) {
UnsafeArrayCopySnippets.Templates templates = tool.getReplacements().getSnippetTemplateCache(UnsafeArrayCopySnippets.Templates.class);
templates.lower(this, tool);
}
}
public void addSnippetArguments(Arguments args) {
args.add("src", src);
args.add("srcPos", srcPos);
args.add("dest", dest);
args.add("destPos", destPos);
args.add("length", length);
if (layoutHelper != null) {
args.add("layoutHelper", layoutHelper);
}
}
@Override
public LocationIdentity getLocationIdentity() {
if (elementKind != null) {
return NamedLocationIdentity.getArrayLocation(elementKind);
}
return any();
}
@Override
public MemoryNode getLastLocationAccess() {
return lastLocationAccess;
}
@Override
public void setLastLocationAccess(MemoryNode lla) {
updateUsagesInterface(lastLocationAccess, lla);
lastLocationAccess = lla;
}
@NodeIntrinsic
public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length, @ConstantNodeParameter JavaKind elementKind);
@NodeIntrinsic
public static native void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper);
}

View File

@ -1,324 +0,0 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.hotspot.replacements.arraycopy;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeMask;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperHeaderSizeShift;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeMask;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.runtime;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.NOT_FREQUENT_PROBABILITY;
import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
import static org.graalvm.word.LocationIdentity.any;
import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.extended.RawLoadNode;
import org.graalvm.compiler.nodes.extended.RawStoreNode;
import org.graalvm.compiler.nodes.extended.UnsafeCopyNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.replacements.SnippetTemplate;
import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
import org.graalvm.compiler.word.ObjectAccess;
import org.graalvm.word.LocationIdentity;
import org.graalvm.word.UnsignedWord;
import org.graalvm.word.WordFactory;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.JavaKind;
/**
* As opposed to {@link ArrayCopySnippets}, these Snippets do <b>not</b> perform store checks.
*/
public class UnsafeArrayCopySnippets implements Snippets {
private static final boolean supportsUnalignedMemoryAccess = runtime().getHostJVMCIBackend().getTarget().arch.supportsUnalignedMemoryAccess();
private static final JavaKind VECTOR_KIND = JavaKind.Long;
private static final long VECTOR_SIZE = getArrayIndexScale(VECTOR_KIND);
private static void vectorizedCopy(Object src, int srcPos, Object dest, int destPos, int length, JavaKind baseKind, LocationIdentity locationIdentity) {
int arrayBaseOffset = arrayBaseOffset(baseKind);
int elementSize = arrayIndexScale(baseKind);
long byteLength = (long) length * elementSize;
long srcOffset = (long) srcPos * elementSize;
long destOffset = (long) destPos * elementSize;
long preLoopBytes;
long mainLoopBytes;
long postLoopBytes;
// We can easily vectorize the loop if both offsets have the same alignment.
if (byteLength >= VECTOR_SIZE && (srcOffset % VECTOR_SIZE) == (destOffset % VECTOR_SIZE)) {
preLoopBytes = NumUtil.roundUp(arrayBaseOffset + srcOffset, VECTOR_SIZE) - (arrayBaseOffset + srcOffset);
postLoopBytes = (byteLength - preLoopBytes) % VECTOR_SIZE;
mainLoopBytes = byteLength - preLoopBytes - postLoopBytes;
} else {
// Does the architecture support unaligned memory accesses?
if (supportsUnalignedMemoryAccess) {
preLoopBytes = byteLength % VECTOR_SIZE;
mainLoopBytes = byteLength - preLoopBytes;
postLoopBytes = 0;
} else {
// No. Let's do element-wise copying.
preLoopBytes = byteLength;
mainLoopBytes = 0;
postLoopBytes = 0;
}
}
if (probability(NOT_FREQUENT_PROBABILITY, src == dest) && probability(NOT_FREQUENT_PROBABILITY, srcPos < destPos)) {
// bad aliased case
srcOffset += byteLength;
destOffset += byteLength;
// Post-loop
for (long i = 0; i < postLoopBytes; i += elementSize) {
srcOffset -= elementSize;
destOffset -= elementSize;
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
}
// Main-loop
for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
srcOffset -= VECTOR_SIZE;
destOffset -= VECTOR_SIZE;
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
}
// Pre-loop
for (long i = 0; i < preLoopBytes; i += elementSize) {
srcOffset -= elementSize;
destOffset -= elementSize;
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
}
} else {
// Pre-loop
for (long i = 0; i < preLoopBytes; i += elementSize) {
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
srcOffset += elementSize;
destOffset += elementSize;
}
// Main-loop
for (long i = 0; i < mainLoopBytes; i += VECTOR_SIZE) {
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, VECTOR_KIND, locationIdentity);
srcOffset += VECTOR_SIZE;
destOffset += VECTOR_SIZE;
}
// Post-loop
for (long i = 0; i < postLoopBytes; i += elementSize) {
UnsafeCopyNode.copy(src, arrayBaseOffset + srcOffset, dest, arrayBaseOffset + destOffset, baseKind, locationIdentity);
srcOffset += elementSize;
destOffset += elementSize;
}
}
}
@Fold
static LocationIdentity getArrayLocation(JavaKind kind) {
return NamedLocationIdentity.getArrayLocation(kind);
}
@Snippet
public static void arraycopyByte(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Byte;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyBoolean(boolean[] src, int srcPos, boolean[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Boolean;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyChar(char[] src, int srcPos, char[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Char;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyShort(short[] src, int srcPos, short[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Short;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyInt(int[] src, int srcPos, int[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Int;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyFloat(float[] src, int srcPos, float[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Float;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyLong(long[] src, int srcPos, long[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Long;
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
@Snippet
public static void arraycopyDouble(double[] src, int srcPos, double[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Double;
/*
* TODO atomicity problem on 32-bit architectures: The JVM spec requires double values to be
* copied atomically, but not long values. For example, on Intel 32-bit this code is not
* atomic as long as the vector kind remains Kind.Long.
*/
vectorizedCopy(src, srcPos, dest, destPos, length, kind, getArrayLocation(kind));
}
/**
* For this kind, Object, we want to avoid write barriers between writes, but instead have them
* at the end of the snippet. This is done by using {@link RawStoreNode}, and rely on
* {@link WriteBarrierAdditionPhase} to put write barriers after the {@link UnsafeArrayCopyNode}
* with kind Object.
*/
@Snippet
public static void arraycopyObject(Object[] src, int srcPos, Object[] dest, int destPos, int length) {
JavaKind kind = JavaKind.Object;
final int scale = arrayIndexScale(kind);
int arrayBaseOffset = arrayBaseOffset(kind);
LocationIdentity arrayLocation = getArrayLocation(kind);
if (src == dest && srcPos < destPos) { // bad aliased case
long start = (long) (length - 1) * scale;
for (long i = start; i >= 0; i -= scale) {
Object a = RawLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
RawStoreNode.storeObject(dest, arrayBaseOffset + i + (long) destPos * scale, a, kind, getArrayLocation(kind), false);
}
} else {
long end = (long) length * scale;
for (long i = 0; i < end; i += scale) {
Object a = RawLoadNode.load(src, arrayBaseOffset + i + (long) srcPos * scale, kind, arrayLocation);
RawStoreNode.storeObject(dest, arrayBaseOffset + i + (long) destPos * scale, a, kind, getArrayLocation(kind), false);
}
}
}
@Snippet
public static void arraycopyPrimitive(Object src, int srcPos, Object dest, int destPos, int length, int layoutHelper) {
int log2ElementSize = (layoutHelper >> layoutHelperLog2ElementSizeShift(INJECTED_VMCONFIG)) & layoutHelperLog2ElementSizeMask(INJECTED_VMCONFIG);
int headerSize = (layoutHelper >> layoutHelperHeaderSizeShift(INJECTED_VMCONFIG)) & layoutHelperHeaderSizeMask(INJECTED_VMCONFIG);
UnsignedWord vectorSize = WordFactory.unsigned(VECTOR_SIZE);
UnsignedWord srcOffset = WordFactory.unsigned(srcPos).shiftLeft(log2ElementSize).add(headerSize);
UnsignedWord destOffset = WordFactory.unsigned(destPos).shiftLeft(log2ElementSize).add(headerSize);
UnsignedWord destStart = destOffset;
UnsignedWord destEnd = destOffset.add(WordFactory.unsigned(length).shiftLeft(log2ElementSize));
UnsignedWord destVectorEnd = null;
UnsignedWord nonVectorBytes = null;
UnsignedWord sizeInBytes = WordFactory.unsigned(length).shiftLeft(log2ElementSize);
if (supportsUnalignedMemoryAccess) {
nonVectorBytes = sizeInBytes.unsignedRemainder(vectorSize);
destVectorEnd = destEnd;
} else {
boolean inPhase = srcOffset.and((int) VECTOR_SIZE - 1).equal(destOffset.and((int) VECTOR_SIZE - 1));
boolean hasAtLeastOneVector = sizeInBytes.aboveOrEqual(vectorSize);
// We must have at least one full vector, otherwise we must copy each byte separately
if (hasAtLeastOneVector && inPhase) { // If in phase, we can vectorize
nonVectorBytes = vectorSize.subtract(destStart.unsignedRemainder(vectorSize));
} else { // fallback is byte-wise
nonVectorBytes = sizeInBytes;
}
destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(vectorSize));
}
UnsignedWord destNonVectorEnd = destStart.add(nonVectorBytes);
while (destOffset.belowThan(destNonVectorEnd)) {
ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
destOffset = destOffset.add(1);
srcOffset = srcOffset.add(1);
}
// Unsigned destVectorEnd = destEnd.subtract(destEnd.unsignedRemainder(8));
while (destOffset.belowThan(destVectorEnd)) {
ObjectAccess.writeWord(dest, destOffset, ObjectAccess.readWord(src, srcOffset, any()), any());
destOffset = destOffset.add(wordSize());
srcOffset = srcOffset.add(wordSize());
}
// Do the last bytes each when it is required to have absolute alignment.
while (!supportsUnalignedMemoryAccess && destOffset.belowThan(destEnd)) {
ObjectAccess.writeByte(dest, destOffset, ObjectAccess.readByte(src, srcOffset, any()), any());
destOffset = destOffset.add(1);
srcOffset = srcOffset.add(1);
}
}
public static class Templates extends AbstractTemplates {
private final SnippetInfo[] arraycopySnippets;
private final SnippetInfo genericPrimitiveSnippet;
public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, TargetDescription target) {
super(options, factories, providers, providers.getSnippetReflection(), target);
arraycopySnippets = new SnippetInfo[JavaKind.values().length];
arraycopySnippets[JavaKind.Boolean.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyBoolean");
arraycopySnippets[JavaKind.Byte.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyByte");
arraycopySnippets[JavaKind.Short.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyShort");
arraycopySnippets[JavaKind.Char.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyChar");
arraycopySnippets[JavaKind.Int.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyInt");
arraycopySnippets[JavaKind.Long.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyLong");
arraycopySnippets[JavaKind.Float.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyFloat");
arraycopySnippets[JavaKind.Double.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyDouble");
arraycopySnippets[JavaKind.Object.ordinal()] = snippet(UnsafeArrayCopySnippets.class, "arraycopyObject");
genericPrimitiveSnippet = snippet(UnsafeArrayCopySnippets.class, "arraycopyPrimitive");
}
public void lower(UnsafeArrayCopyNode node, LoweringTool tool) {
JavaKind elementKind = node.getElementKind();
SnippetInfo snippet;
if (elementKind == null) {
// primitive array of unknown kind
snippet = genericPrimitiveSnippet;
} else {
snippet = arraycopySnippets[elementKind.ordinal()];
assert snippet != null : "arraycopy snippet for " + elementKind.name() + " not found";
}
Arguments args = new Arguments(snippet, node.graph().getGuardsStage(), tool.getLoweringStage());
node.addSnippetArguments(args);
SnippetTemplate template = template(node.getDebug(), args);
template.instantiate(providers.getMetaAccess(), node, DEFAULT_REPLACER, args);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,6 +54,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.TargetDescription;
public class ProbabilisticProfileSnippets implements Snippets {
@ -64,22 +65,22 @@ public class ProbabilisticProfileSnippets implements Snippets {
}
@Snippet
public static int notificationMask(int freqLog, int probLog) {
int probabilityMask = (1 << probLog) - 1;
public static int notificationMask(int freqLog, int probLog, int stepLog) {
int frequencyMask = (1 << freqLog) - 1;
return frequencyMask & ~probabilityMask;
int stepMask = (1 << (stepLog + probLog)) - 1;
return frequencyMask & ~stepMask;
}
@NodeIntrinsic(ForeignCallNode.class)
public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
@Snippet
public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog) {
public static void profileMethodEntryWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog) {
if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + ((config(INJECTED_VMCONFIG).invocationCounterIncrement * step) << probLog);
counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
if (freqLog >= 0) {
int mask = notificationMask(freqLog, probLog);
int mask = notificationMask(freqLog, probLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
}
@ -91,11 +92,12 @@ public class ProbabilisticProfileSnippets implements Snippets {
public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
@Snippet
public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci, int targetBci) {
public static void profileBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog, @ConstantParameter int probLog, int bci,
int targetBci) {
if (probability(1.0 / (1 << probLog), shouldProfile(probLog, random))) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + (config(INJECTED_VMCONFIG).invocationCounterIncrement << probLog);
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + ((config(INJECTED_VMCONFIG).invocationCounterIncrement * step) << probLog);
counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
int mask = notificationMask(freqLog, probLog);
int mask = notificationMask(freqLog, probLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
}
@ -103,10 +105,11 @@ public class ProbabilisticProfileSnippets implements Snippets {
}
@Snippet
public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, @ConstantParameter int freqLog, @ConstantParameter int probLog, boolean branchCondition,
public static void profileConditionalBackedgeWithProbability(MethodCountersPointer counters, int random, int step, int stepLog, @ConstantParameter int freqLog,
@ConstantParameter int probLog, boolean branchCondition,
int bci, int targetBci) {
if (branchCondition) {
profileBackedgeWithProbability(counters, random, freqLog, probLog, bci, targetBci);
profileBackedgeWithProbability(counters, random, step, stepLog, freqLog, probLog, bci, targetBci);
}
}
@ -124,6 +127,8 @@ public class ProbabilisticProfileSnippets implements Snippets {
StructuredGraph graph = profileNode.graph();
LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph);
ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph);
if (profileNode instanceof ProfileBranchNode) {
// Backedge event
@ -132,8 +137,11 @@ public class ProbabilisticProfileSnippets implements Snippets {
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
args.add("counters", counters);
args.add("random", profileBranchNode.getRandom());
args.add("step", step);
args.add("stepLog", stepLog);
args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
args.addConst("probLog", profileBranchNode.getProbabilityLog());
if (profileBranchNode.hasCondition()) {
@ -148,8 +156,11 @@ public class ProbabilisticProfileSnippets implements Snippets {
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
// Method invocation event
Arguments args = new Arguments(profileMethodEntryWithProbability, graph.getGuardsStage(), tool.getLoweringStage());
args.add("counters", counters);
args.add("random", profileInvokeNode.getRandom());
args.add("step", step);
args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
args.addConst("probLog", profileInvokeNode.getProbabilityLog());
SnippetTemplate template = template(graph.getDebug(), args);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -54,6 +54,7 @@ import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.TargetDescription;
public class ProfileSnippets implements Snippets {
@ -61,12 +62,19 @@ public class ProfileSnippets implements Snippets {
public static native void methodInvocationEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters);
@Snippet
public static void profileMethodEntry(MethodCountersPointer counters, @ConstantParameter int freqLog) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
protected static int notificationMask(int freqLog, int stepLog) {
int stepMask = (1 << stepLog) - 1;
int frequencyMask = (1 << freqLog) - 1;
return frequencyMask & ~stepMask;
}
@Snippet
public static void profileMethodEntry(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).invocationCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement * step;
counters.writeInt(config(INJECTED_VMCONFIG).invocationCounterOffset, counterValue);
if (freqLog >= 0) {
final int frequencyMask = (1 << freqLog) - 1;
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
final int mask = notificationMask(freqLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodInvocationEvent(HotSpotBackend.INVOCATION_EVENT, counters);
}
}
@ -76,19 +84,19 @@ public class ProfileSnippets implements Snippets {
public static native void methodBackedgeEvent(@ConstantNodeParameter ForeignCallDescriptor descriptor, MethodCountersPointer counters, int bci, int targetBci);
@Snippet
public static void profileBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, int bci, int targetBci) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement;
public static void profileBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, int bci, int targetBci) {
int counterValue = counters.readInt(config(INJECTED_VMCONFIG).backedgeCounterOffset) + config(INJECTED_VMCONFIG).invocationCounterIncrement * step;
counters.writeInt(config(INJECTED_VMCONFIG).backedgeCounterOffset, counterValue);
final int frequencyMask = (1 << freqLog) - 1;
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (frequencyMask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
final int mask = notificationMask(freqLog, stepLog);
if (probability(SLOW_PATH_PROBABILITY, (counterValue & (mask << config(INJECTED_VMCONFIG).invocationCounterShift)) == 0)) {
methodBackedgeEvent(HotSpotBackend.BACKEDGE_EVENT, counters, bci, targetBci);
}
}
@Snippet
public static void profileConditionalBackedge(MethodCountersPointer counters, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) {
public static void profileConditionalBackedge(MethodCountersPointer counters, int step, int stepLog, @ConstantParameter int freqLog, boolean branchCondition, int bci, int targetBci) {
if (branchCondition) {
profileBackedge(counters, freqLog, bci, targetBci);
profileBackedge(counters, step, stepLog, freqLog, bci, targetBci);
}
}
@ -104,6 +112,8 @@ public class ProfileSnippets implements Snippets {
public void lower(ProfileNode profileNode, LoweringTool tool) {
StructuredGraph graph = profileNode.graph();
LoadMethodCountersNode counters = graph.unique(new LoadMethodCountersNode(profileNode.getProfiledMethod()));
ConstantNode step = ConstantNode.forInt(profileNode.getStep(), graph);
ConstantNode stepLog = ConstantNode.forInt(CodeUtil.log2(profileNode.getStep()), graph);
if (profileNode instanceof ProfileBranchNode) {
// Backedge event
@ -113,6 +123,8 @@ public class ProfileSnippets implements Snippets {
ConstantNode bci = ConstantNode.forInt(profileBranchNode.bci(), graph);
ConstantNode targetBci = ConstantNode.forInt(profileBranchNode.targetBci(), graph);
args.add("counters", counters);
args.add("step", step);
args.add("stepLog", stepLog);
args.addConst("freqLog", profileBranchNode.getNotificationFreqLog());
if (profileBranchNode.hasCondition()) {
args.add("branchCondition", profileBranchNode.branchCondition());
@ -127,6 +139,8 @@ public class ProfileSnippets implements Snippets {
// Method invocation event
Arguments args = new Arguments(profileMethodEntry, graph.getGuardsStage(), tool.getLoweringStage());
args.add("counters", counters);
args.add("step", step);
args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
SnippetTemplate template = template(graph.getDebug(), args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);

View File

@ -33,6 +33,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.layoutHelperLog2ElementSizeShift;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.readLayoutHelper;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.registerAsWord;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useCMSIncrementalMode;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH;
import static org.graalvm.compiler.hotspot.replacements.NewObjectSnippets.formatArray;
@ -122,7 +123,7 @@ public class NewArrayStub extends SnippetStub {
// check that array length is small enough for fast path.
Word thread = registerAsWord(threadRegister);
boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
if (inlineContiguousAllocationSupported && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
if (inlineContiguousAllocationSupported && !useCMSIncrementalMode(INJECTED_VMCONFIG) && length >= 0 && length <= MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH) {
Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging(options));
if (memory.notEqual(0)) {
if (logging(options)) {

View File

@ -53,6 +53,7 @@ import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabRefillWasteLimitOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabSlowAllocationsOffset;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.tlabStats;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useCMSIncrementalMode;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useG1GC;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.useTLAB;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.wordSize;
@ -147,7 +148,7 @@ public class NewInstanceStub extends SnippetStub {
*/
Word thread = registerAsWord(threadRegister);
boolean inlineContiguousAllocationSupported = GraalHotSpotVMConfigNode.inlineContiguousAllocationSupported();
if (!forceSlowPath(options) && inlineContiguousAllocationSupported) {
if (!forceSlowPath(options) && inlineContiguousAllocationSupported && !useCMSIncrementalMode(INJECTED_VMCONFIG)) {
if (isInstanceKlassFullyInitialized(hub)) {
int sizeInBytes = readLayoutHelper(hub);
Word memory = refillAllocate(thread, intArrayHub, sizeInBytes, logging(options));

View File

@ -342,7 +342,7 @@ import org.graalvm.compiler.nodes.calc.AddNode;
import org.graalvm.compiler.nodes.calc.AndNode;
import org.graalvm.compiler.nodes.calc.CompareNode;
import org.graalvm.compiler.nodes.calc.ConditionalNode;
import org.graalvm.compiler.nodes.calc.DivNode;
import org.graalvm.compiler.nodes.calc.FloatDivNode;
import org.graalvm.compiler.nodes.calc.FloatConvertNode;
import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
@ -374,7 +374,6 @@ import org.graalvm.compiler.nodes.extended.MembarNode;
import org.graalvm.compiler.nodes.extended.StateSplitProxyNode;
import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
import org.graalvm.compiler.nodes.graphbuilderconf.ClassInitializationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@ -383,6 +382,7 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo
import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
import org.graalvm.compiler.nodes.graphbuilderconf.InvokeDynamicPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.ProfilingPlugin;
import org.graalvm.compiler.nodes.java.ArrayLengthNode;
@ -435,6 +435,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.Signature;
import jdk.vm.ci.meta.TriState;
import org.graalvm.compiler.core.common.type.IntegerStamp;
/**
* The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
@ -1036,7 +1037,7 @@ public class BytecodeParser implements GraphBuilderContext {
deopt.updateNodeSourcePosition(() -> createBytecodePosition());
}
private AbstractBeginNode handleException(ValueNode exceptionObject, int bci) {
private AbstractBeginNode handleException(ValueNode exceptionObject, int bci, boolean deoptimizeOnly) {
assert bci == BytecodeFrame.BEFORE_BCI || bci == bci() : "invalid bci";
debug.log("Creating exception dispatch edges at %d, exception object=%s, exception seen=%s", bci, exceptionObject, (profilingInfo == null ? "" : profilingInfo.getExceptionSeen(bci)));
@ -1058,8 +1059,12 @@ public class BytecodeParser implements GraphBuilderContext {
this.controlFlowSplit = true;
FixedWithNextNode finishedDispatch = finishInstruction(dispatchBegin, dispatchState);
createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
if (deoptimizeOnly) {
DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.None, DeoptimizationReason.TransferToInterpreter));
dispatchBegin.setNext(BeginNode.begin(deoptimizeNode));
} else {
createHandleExceptionTarget(finishedDispatch, bci, dispatchState);
}
return dispatchBegin;
}
@ -1111,7 +1116,7 @@ public class BytecodeParser implements GraphBuilderContext {
}
protected ValueNode genFloatDiv(ValueNode x, ValueNode y) {
return DivNode.create(x, y);
return FloatDivNode.create(x, y);
}
protected ValueNode genFloatRem(ValueNode x, ValueNode y) {
@ -1215,7 +1220,7 @@ public class BytecodeParser implements GraphBuilderContext {
ValueNode exception = frameState.pop(JavaKind.Object);
FixedGuardNode nullCheck = append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
ValueNode nonNullException = graph.maybeAddOrUnique(PiNode.create(exception, exception.stamp().join(objectNonNull()), nullCheck));
lastInstr.setNext(handleException(nonNullException, bci()));
lastInstr.setNext(handleException(nonNullException, bci(), false));
}
protected LogicNode createInstanceOf(TypeReference type, ValueNode object) {
@ -1275,12 +1280,12 @@ public class BytecodeParser implements GraphBuilderContext {
}
BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
AbstractBeginNode falseSucc = graph.add(new BeginNode());
ValueNode nonNullReceiver = graph.addOrUnique(PiNode.create(receiver, objectNonNull(), falseSucc));
ValueNode nonNullReceiver = graph.addOrUniqueWithInputs(PiNode.create(receiver, objectNonNull(), falseSucc));
append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, SLOW_PATH_PROBABILITY));
lastInstr = falseSucc;
exception.setStateAfter(createFrameState(bci(), exception));
exception.setNext(handleException(exception, bci()));
exception.setNext(handleException(exception, bci(), false));
EXPLICIT_EXCEPTIONS.increment(debug);
return nonNullReceiver;
}
@ -1292,7 +1297,7 @@ public class BytecodeParser implements GraphBuilderContext {
lastInstr = trueSucc;
exception.setStateAfter(createFrameState(bci(), exception));
exception.setNext(handleException(exception, bci()));
exception.setNext(handleException(exception, bci(), false));
}
protected ValueNode genArrayLength(ValueNode x) {
@ -1532,8 +1537,8 @@ public class BytecodeParser implements GraphBuilderContext {
@Override
public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) {
BytecodeParser intrinsicCallSiteParser = getNonIntrinsicAncestor();
boolean withExceptionEdge = intrinsicCallSiteParser == null ? !omitInvokeExceptionEdge(null) : !intrinsicCallSiteParser.omitInvokeExceptionEdge(null);
createNonInlinedInvoke(withExceptionEdge, bci(), callTarget, resultType);
ExceptionEdgeAction exceptionEdgeAction = intrinsicCallSiteParser == null ? getActionForInvokeExceptionEdge(null) : intrinsicCallSiteParser.getActionForInvokeExceptionEdge(null);
createNonInlinedInvoke(exceptionEdgeAction, bci(), callTarget, resultType);
}
protected Invoke appendInvoke(InvokeKind initialInvokeKind, ResolvedJavaMethod initialTargetMethod, ValueNode[] args) {
@ -1603,7 +1608,7 @@ public class BytecodeParser implements GraphBuilderContext {
int invokeBci = bci();
JavaTypeProfile profile = getProfileForInvoke(invokeKind);
boolean withExceptionEdge = !omitInvokeExceptionEdge(inlineInfo);
ExceptionEdgeAction edgeAction = getActionForInvokeExceptionEdge(inlineInfo);
boolean partialIntrinsicExit = false;
if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
partialIntrinsicExit = true;
@ -1614,7 +1619,7 @@ public class BytecodeParser implements GraphBuilderContext {
// must use the same context as the call to the intrinsic.
invokeBci = intrinsicCallSiteParser.bci();
profile = intrinsicCallSiteParser.getProfileForInvoke(invokeKind);
withExceptionEdge = !intrinsicCallSiteParser.omitInvokeExceptionEdge(inlineInfo);
edgeAction = intrinsicCallSiteParser.getActionForInvokeExceptionEdge(inlineInfo);
} else {
// We are parsing the intrinsic for the root compilation or for inlining,
// This call is a partial intrinsic exit, and we do not have profile information
@ -1624,7 +1629,7 @@ public class BytecodeParser implements GraphBuilderContext {
assert intrinsicContext.isPostParseInlined();
invokeBci = BytecodeFrame.UNKNOWN_BCI;
profile = null;
withExceptionEdge = graph.method().getAnnotation(Snippet.class) == null;
edgeAction = graph.method().getAnnotation(Snippet.class) == null ? ExceptionEdgeAction.INCLUDE_AND_HANDLE : ExceptionEdgeAction.OMIT;
}
if (originalMethod.isStatic()) {
@ -1637,10 +1642,10 @@ public class BytecodeParser implements GraphBuilderContext {
Signature sig = originalMethod.getSignature();
returnType = sig.getReturnType(method.getDeclaringClass());
resultType = sig.getReturnKind();
assert checkPartialIntrinsicExit(intrinsicCallSiteParser == null ? null : intrinsicCallSiteParser.currentInvoke.args, args);
assert intrinsicContext.allowPartialIntrinsicArgumentMismatch() || checkPartialIntrinsicExit(intrinsicCallSiteParser == null ? null : intrinsicCallSiteParser.currentInvoke.args, args);
targetMethod = originalMethod;
}
Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile);
Invoke invoke = createNonInlinedInvoke(edgeAction, invokeBci, args, targetMethod, invokeKind, resultType, returnType, profile);
if (partialIntrinsicExit) {
// This invoke must never be later inlined as it might select the intrinsic graph.
// Until there is a mechanism to guarantee that any late inlining will not select
@ -1698,14 +1703,14 @@ public class BytecodeParser implements GraphBuilderContext {
} else {
for (int i = 0; i < recursiveArgs.length; i++) {
ValueNode arg = GraphUtil.unproxify(recursiveArgs[i]);
assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s", i,
ParameterNode.class.getSimpleName(), i, arg);
assert arg instanceof ParameterNode && ((ParameterNode) arg).index() == i : String.format("argument %d of call denoting partial intrinsic exit should be a %s with index %d, not %s",
i, ParameterNode.class.getSimpleName(), i, arg);
}
}
return true;
}
protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, ValueNode[] invokeArgs, ResolvedJavaMethod targetMethod,
InvokeKind invokeKind, JavaKind resultType, JavaType returnType, JavaTypeProfile profile) {
StampPair returnStamp = graphBuilderConfig.getPlugins().getOverridingStamp(this, returnType, false);
@ -1714,7 +1719,7 @@ public class BytecodeParser implements GraphBuilderContext {
}
MethodCallTargetNode callTarget = graph.add(createMethodCallTarget(invokeKind, targetMethod, invokeArgs, returnStamp, profile));
Invoke invoke = createNonInlinedInvoke(withExceptionEdge, invokeBci, callTarget, resultType);
Invoke invoke = createNonInlinedInvoke(exceptionEdge, invokeBci, callTarget, resultType);
for (InlineInvokePlugin plugin : graphBuilderConfig.getPlugins().getInlineInvokePlugins()) {
plugin.notifyNotInlined(this, targetMethod, invoke);
@ -1723,11 +1728,11 @@ public class BytecodeParser implements GraphBuilderContext {
return invoke;
}
protected Invoke createNonInlinedInvoke(boolean withExceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
if (!withExceptionEdge) {
protected Invoke createNonInlinedInvoke(ExceptionEdgeAction exceptionEdge, int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
if (exceptionEdge == ExceptionEdgeAction.OMIT) {
return createInvoke(invokeBci, callTarget, resultType);
} else {
Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType);
Invoke invoke = createInvokeWithException(invokeBci, callTarget, resultType, exceptionEdge);
AbstractBeginNode beginNode = graph.add(KillingBeginNode.create(LocationIdentity.any()));
invoke.setNext(beginNode);
lastInstr = beginNode;
@ -1736,20 +1741,29 @@ public class BytecodeParser implements GraphBuilderContext {
}
/**
* If the method returns true, the invocation of the given {@link MethodCallTargetNode call
* target} does not need an exception edge.
* Describes what should be done with the exception edge of an invocation. The edge can be
* omitted or included. An included edge can handle the exception or transfer execution to the
* interpreter for handling (deoptimize).
*/
protected boolean omitInvokeExceptionEdge(InlineInfo lastInlineInfo) {
protected enum ExceptionEdgeAction {
OMIT,
INCLUDE_AND_HANDLE,
INCLUDE_AND_DEOPTIMIZE
}
protected ExceptionEdgeAction getActionForInvokeExceptionEdge(InlineInfo lastInlineInfo) {
if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION) {
return false;
return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_NO_EXCEPTION) {
return true;
return ExceptionEdgeAction.OMIT;
} else if (lastInlineInfo == InlineInfo.DO_NOT_INLINE_DEOPTIMIZE_ON_EXCEPTION) {
return ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.CheckAll) {
return false;
return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.ExplicitOnly) {
return false;
return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
} else if (graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.OmitAll) {
return true;
return ExceptionEdgeAction.OMIT;
} else {
assert graphBuilderConfig.getBytecodeExceptionMode() == BytecodeExceptionMode.Profile;
// be conservative if information was not recorded (could result in endless
@ -1759,12 +1773,12 @@ public class BytecodeParser implements GraphBuilderContext {
if (profilingInfo != null) {
TriState exceptionSeen = profilingInfo.getExceptionSeen(bci());
if (exceptionSeen == TriState.FALSE) {
return true;
return ExceptionEdgeAction.OMIT;
}
}
}
}
return false;
return ExceptionEdgeAction.INCLUDE_AND_HANDLE;
}
}
@ -1887,7 +1901,7 @@ public class BytecodeParser implements GraphBuilderContext {
if (newProfile != profile) {
if (newProfile.getTypes().length == 0) {
// All profiled types select the intrinsic so
// emit a fixed guard instead of a if-then-else.
// emit a fixed guard instead of an if-then-else.
lastInstr = append(new FixedGuardNode(compare, TypeCheckedInliningViolated, InvalidateReprofile, false));
return new IntrinsicGuard(currentLastInstr, intrinsicReceiver, mark, null, null);
}
@ -1966,7 +1980,7 @@ public class BytecodeParser implements GraphBuilderContext {
}
lastInstr = intrinsicGuard.nonIntrinsicBranch;
createNonInlinedInvoke(omitInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
createNonInlinedInvoke(getActionForInvokeExceptionEdge(null), bci(), args, targetMethod, invokeKind, resultType, returnType, intrinsicGuard.profile);
EndNode nonIntrinsicEnd = append(new EndNode());
AbstractMergeNode mergeNode = graph.add(new MergeNode());
@ -2303,7 +2317,7 @@ public class BytecodeParser implements GraphBuilderContext {
if (calleeBeforeUnwindNode != null) {
ValueNode calleeUnwindValue = parser.getUnwindValue();
assert calleeUnwindValue != null;
calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci()));
calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false));
}
}
}
@ -2319,7 +2333,7 @@ public class BytecodeParser implements GraphBuilderContext {
return invoke;
}
protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType) {
protected InvokeWithExceptionNode createInvokeWithException(int invokeBci, CallTargetNode callTarget, JavaKind resultType, ExceptionEdgeAction exceptionEdgeAction) {
if (currentBlock != null && stream.nextBCI() > currentBlock.endBci) {
/*
* Clear non-live locals early so that the exception handler entry gets the cleared
@ -2328,7 +2342,7 @@ public class BytecodeParser implements GraphBuilderContext {
frameState.clearNonLiveLocals(currentBlock, liveness, false);
}
AbstractBeginNode exceptionEdge = handleException(null, bci());
AbstractBeginNode exceptionEdge = handleException(null, bci(), exceptionEdgeAction == ExceptionEdgeAction.INCLUDE_AND_DEOPTIMIZE);
InvokeWithExceptionNode invoke = append(new InvokeWithExceptionNode(callTarget, exceptionEdge, invokeBci));
frameState.pushReturn(resultType, invoke);
invoke.setStateAfter(createFrameState(stream.nextBCI(), invoke));
@ -2359,20 +2373,43 @@ public class BytecodeParser implements GraphBuilderContext {
}
}
ValueNode realReturnVal = processReturnValue(returnVal, returnKind);
frameState.setRethrowException(false);
frameState.clearStack();
beforeReturn(returnVal, returnKind);
beforeReturn(realReturnVal, returnKind);
if (parent == null) {
append(new ReturnNode(returnVal));
append(new ReturnNode(realReturnVal));
} else {
if (returnDataList == null) {
returnDataList = new ArrayList<>();
}
returnDataList.add(new ReturnToCallerData(returnVal, lastInstr));
returnDataList.add(new ReturnToCallerData(realReturnVal, lastInstr));
lastInstr = null;
}
}
private ValueNode processReturnValue(ValueNode value, JavaKind kind) {
JavaKind returnKind = method.getSignature().getReturnKind();
if (kind != returnKind) {
// sub-word integer
assert returnKind.isNumericInteger() && returnKind.getStackKind() == JavaKind.Int;
IntegerStamp stamp = (IntegerStamp) value.stamp();
// the bytecode verifier doesn't check that the value is in the correct range
if (stamp.lowerBound() < returnKind.getMinValue() || returnKind.getMaxValue() < stamp.upperBound()) {
ValueNode narrow = append(genNarrow(value, returnKind.getBitCount()));
if (returnKind.isUnsigned()) {
return append(genZeroExtend(narrow, 32));
} else {
return append(genSignExtend(narrow, 32));
}
}
}
return value;
}
private void beforeReturn(ValueNode x, JavaKind kind) {
if (graph.method() != null && graph.method().isJavaLangObjectInit()) {
/*
@ -2794,6 +2831,8 @@ public class BytecodeParser implements GraphBuilderContext {
}
private void createExceptionDispatch(ExceptionDispatchBlock block) {
lastInstr = finishInstruction(lastInstr, frameState);
assert frameState.stackSize() == 1 : frameState;
if (block.handler.isCatchAll()) {
assert block.getSuccessorCount() == 1;

View File

@ -207,7 +207,7 @@ public final class FrameStateBuilder implements SideEffectsState {
receiver = new ParameterNode(javaIndex, receiverStamp);
}
locals[javaIndex] = graph.addOrUnique(receiver);
locals[javaIndex] = graph.addOrUniqueWithInputs(receiver);
javaIndex = 1;
index = 1;
}
@ -241,7 +241,7 @@ public final class FrameStateBuilder implements SideEffectsState {
param = new ParameterNode(index, stamp);
}
locals[javaIndex] = graph.addOrUnique(param);
locals[javaIndex] = graph.addOrUniqueWithInputs(param);
javaIndex++;
if (kind.needsTwoSlots()) {
locals[javaIndex] = TWO_SLOT_MARKER;

View File

@ -29,6 +29,9 @@ 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;
public class ConditionalElimination02 extends JTTTest {
@ -59,6 +62,14 @@ public class ConditionalElimination02 extends JTTTest {
return -1;
}
/**
* 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));
}
@Test
public void run0() throws Throwable {
runTest(EnumSet.of(DeoptimizationReason.NullCheckException), "test", new A(5), false, false);

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.graalvm.compiler.jtt.optimize;
import org.junit.Test;
import org.graalvm.compiler.jtt.JTTTest;
/*
* Tests constant folding of double operations.
*/
public class Fold_Double04 extends JTTTest {
// Contrived check whether both arguments are the same kind of zero
public static boolean test(double x, double y) {
if (x == 0) {
if (1 / x == Double.NEGATIVE_INFINITY) {
return 1 / y == Double.NEGATIVE_INFINITY;
} else {
return 1 / y == Double.POSITIVE_INFINITY;
}
}
return false;
}
@Test
public void run0() throws Throwable {
runTest("test", -0d, -0d);
}
@Test
public void run1() throws Throwable {
runTest("test", -0d, 0d);
}
@Test
public void run2() throws Throwable {
runTest("test", 0d, -0d);
}
@Test
public void run3() throws Throwable {
runTest("test", 0d, 0d);
}
}

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