8198969: Update Graal
Reviewed-by: kvn
This commit is contained in:
parent
2cfacefbb5
commit
089f83703a
@ -120,6 +120,7 @@ ifeq ($(INCLUDE_GRAAL), true)
|
||||
SRC := \
|
||||
$(SRC_DIR)/org.graalvm.word/src \
|
||||
$(SRC_DIR)/org.graalvm.collections/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.bytecode/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
|
||||
$(SRC_DIR)/org.graalvm.compiler.code/src \
|
||||
|
@ -195,11 +195,6 @@ public class AMD64Assembler extends Assembler {
|
||||
private static final int VEX_W = 0x80;
|
||||
}
|
||||
|
||||
private static class AvxVectorLen {
|
||||
private static final int AVX_128bit = 0x0;
|
||||
private static final int AVX_256bit = 0x1;
|
||||
}
|
||||
|
||||
private static class VexSimdPrefix {
|
||||
private static final int VEX_SIMD_NONE = 0x0;
|
||||
private static final int VEX_SIMD_66 = 0x1;
|
||||
@ -208,11 +203,44 @@ public class AMD64Assembler extends Assembler {
|
||||
}
|
||||
|
||||
private static class VexOpcode {
|
||||
private static final int VEX_OPCODE_NONE = 0x0;
|
||||
private static final int VEX_OPCODE_0F = 0x1;
|
||||
private static final int VEX_OPCODE_0F_38 = 0x2;
|
||||
private static final int VEX_OPCODE_0F_3A = 0x3;
|
||||
}
|
||||
|
||||
public static class AvxVectorLen {
|
||||
public static final int AVX_128bit = 0x0;
|
||||
public static final int AVX_256bit = 0x1;
|
||||
public static final int AVX_512bit = 0x2;
|
||||
public static final int AVX_NoVec = 0x4;
|
||||
}
|
||||
|
||||
public static class EvexTupleType {
|
||||
public static final int EVEX_FV = 0;
|
||||
public static final int EVEX_HV = 4;
|
||||
public static final int EVEX_FVM = 6;
|
||||
public static final int EVEX_T1S = 7;
|
||||
public static final int EVEX_T1F = 11;
|
||||
public static final int EVEX_T2 = 13;
|
||||
public static final int EVEX_T4 = 15;
|
||||
public static final int EVEX_T8 = 17;
|
||||
public static final int EVEX_HVM = 18;
|
||||
public static final int EVEX_QVM = 19;
|
||||
public static final int EVEX_OVM = 20;
|
||||
public static final int EVEX_M128 = 21;
|
||||
public static final int EVEX_DUP = 22;
|
||||
public static final int EVEX_ETUP = 23;
|
||||
}
|
||||
|
||||
public static class EvexInputSizeInBits {
|
||||
public static final int EVEX_8bit = 0;
|
||||
public static final int EVEX_16bit = 1;
|
||||
public static final int EVEX_32bit = 2;
|
||||
public static final int EVEX_64bit = 3;
|
||||
public static final int EVEX_NObit = 4;
|
||||
}
|
||||
|
||||
private AMD64InstructionAttr curAttributes;
|
||||
|
||||
AMD64InstructionAttr getCurAttributes() {
|
||||
@ -873,6 +901,7 @@ public class AMD64Assembler extends Assembler {
|
||||
opc = VexOpcode.VEX_OPCODE_0F_3A;
|
||||
break;
|
||||
default:
|
||||
opc = VexOpcode.VEX_OPCODE_NONE;
|
||||
isSimd = false;
|
||||
break;
|
||||
}
|
||||
@ -1770,6 +1799,13 @@ public class AMD64Assembler extends Assembler {
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void bsfq(Register dst, Register src) {
|
||||
int encode = prefixqAndEncode(dst.encoding(), src.encoding());
|
||||
emitByte(0x0F);
|
||||
emitByte(0xBC);
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
public final void bsrl(Register dst, Register src) {
|
||||
int encode = prefixAndEncode(dst.encoding(), src.encoding());
|
||||
emitByte(0x0F);
|
||||
@ -1857,6 +1893,26 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
public final void evmovdquq(Register dst, AMD64Address src, int vectorLen) {
|
||||
assert supports(CPUFeature.AVX512F);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target);
|
||||
attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
|
||||
attributes.setIsEvexInstruction();
|
||||
vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_F3, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x6F);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void evpcmpeqb(Register kdst, Register nds, AMD64Address src, int vectorLen) {
|
||||
assert supports(CPUFeature.AVX512BW);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
attributes.setIsEvexInstruction();
|
||||
attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
|
||||
vexPrefix(src, nds, kdst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x74);
|
||||
emitOperandHelper(kdst, src, 0);
|
||||
}
|
||||
|
||||
public final void hlt() {
|
||||
emitByte(0xF4);
|
||||
}
|
||||
@ -1982,6 +2038,32 @@ public class AMD64Assembler extends Assembler {
|
||||
}
|
||||
}
|
||||
|
||||
// This instruction produces ZF or CF flags
|
||||
public final void kortestql(Register src1, Register src2) {
|
||||
assert supports(CPUFeature.AVX512BW);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
int encode = vexPrefixAndEncode(src1, Register.None, src2, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x98);
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
public final void kmovql(Register dst, Register src) {
|
||||
assert supports(CPUFeature.AVX512BW);
|
||||
if (src.getRegisterCategory().equals(AMD64.MASK)) {
|
||||
// kmovql(KRegister dst, KRegister src)
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_NONE, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x90);
|
||||
emitByte(0xC0 | encode);
|
||||
} else {
|
||||
// kmovql(KRegister dst, Register src)
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ true, /* legacy_mode */ true, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
int encode = vexPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_F2, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0x92);
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
}
|
||||
|
||||
public final void lead(Register dst, AMD64Address src) {
|
||||
prefix(src, dst);
|
||||
emitByte(0x8D);
|
||||
@ -2050,6 +2132,15 @@ public class AMD64Assembler extends Assembler {
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param wide use 4 byte encoding for displacements that would normally fit in a byte
|
||||
*/
|
||||
public final void movl(Register dst, AMD64Address src, boolean wide) {
|
||||
prefix(src, dst);
|
||||
emitByte(0x8B);
|
||||
emitOperandHelper(dst, src, wide, 0);
|
||||
}
|
||||
|
||||
public final void movl(AMD64Address dst, int imm32) {
|
||||
prefix(dst);
|
||||
emitByte(0xC7);
|
||||
@ -2291,6 +2382,10 @@ public class AMD64Assembler extends Assembler {
|
||||
NOT.emit(this, DWORD, dst);
|
||||
}
|
||||
|
||||
public final void notq(Register dst) {
|
||||
NOT.emit(this, QWORD, dst);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void ensureUniquePC() {
|
||||
nop();
|
||||
@ -2540,7 +2635,7 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
void pcmpestri(Register dst, AMD64Address src, int imm8) {
|
||||
public final void pcmpestri(Register dst, AMD64Address src, int imm8) {
|
||||
assert supports(CPUFeature.SSE4_2);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
|
||||
@ -2549,7 +2644,7 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
void pcmpestri(Register dst, Register src, int imm8) {
|
||||
public final void pcmpestri(Register dst, Register src, int imm8) {
|
||||
assert supports(CPUFeature.SSE4_2);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target);
|
||||
int encode = simdPrefixAndEncode(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_3A, attributes);
|
||||
@ -2558,6 +2653,26 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(imm8);
|
||||
}
|
||||
|
||||
public final void pmovzxbw(Register dst, AMD64Address src) {
|
||||
assert supports(CPUFeature.SSE4_2);
|
||||
// XXX legacy_mode should be: _legacy_mode_bw
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
|
||||
simdPrefix(dst, Register.None, src, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
|
||||
emitByte(0x30);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void vpmovzxbw(Register dst, AMD64Address src, int vectorLen) {
|
||||
assert supports(CPUFeature.AVX);
|
||||
// XXX legacy_mode should be: _legacy_mode_bw
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(vectorLen, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false, target);
|
||||
attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_HVM, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_NObit);
|
||||
vexPrefix(src, Register.None, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F_38, attributes);
|
||||
emitByte(0x30);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void push(Register src) {
|
||||
int encode = prefixAndEncode(src.encoding);
|
||||
emitByte(0x50 | encode);
|
||||
@ -2634,6 +2749,15 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(0xC0 | encode);
|
||||
}
|
||||
|
||||
public final void vpxor(Register dst, Register nds, AMD64Address src) {
|
||||
assert supports(CPUFeature.AVX);
|
||||
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_256bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ false, /* uses_vl */ true, target);
|
||||
attributes.setAddressAttributes(/* tuple_type */ EvexTupleType.EVEX_FV, /* input_size_in_bits */ EvexInputSizeInBits.EVEX_32bit);
|
||||
vexPrefix(src, nds, dst, VexSimdPrefix.VEX_SIMD_66, VexOpcode.VEX_OPCODE_0F, attributes);
|
||||
emitByte(0xEF);
|
||||
emitOperandHelper(dst, src, 0);
|
||||
}
|
||||
|
||||
public final void pslld(Register dst, int imm8) {
|
||||
assert isUByte(imm8) : "invalid value";
|
||||
assert dst.getRegisterCategory().equals(AMD64.XMM);
|
||||
@ -3843,4 +3967,11 @@ public class AMD64Assembler extends Assembler {
|
||||
emitByte(0x0f);
|
||||
emitByte(0x0b);
|
||||
}
|
||||
|
||||
public void lfence() {
|
||||
emitByte(0x0f);
|
||||
emitByte(0xae);
|
||||
emitByte(0xe8);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -321,4 +321,61 @@ public class BytecodeDisassembler {
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public static JavaMethod getInvokedMethodAt(ResolvedJavaMethod method, int invokeBci) {
|
||||
if (method.getCode() == null) {
|
||||
return null;
|
||||
}
|
||||
ConstantPool cp = method.getConstantPool();
|
||||
BytecodeStream stream = new BytecodeStream(method.getCode());
|
||||
int opcode = stream.currentBC();
|
||||
while (opcode != Bytecodes.END) {
|
||||
int bci = stream.currentBCI();
|
||||
if (bci == invokeBci) {
|
||||
if (stream.nextBCI() > bci + 1) {
|
||||
switch (opcode) {
|
||||
case INVOKEVIRTUAL:
|
||||
case INVOKESPECIAL:
|
||||
case INVOKESTATIC: {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
case INVOKEINTERFACE: {
|
||||
int cpi = stream.readCPI();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
case INVOKEDYNAMIC: {
|
||||
int cpi = stream.readCPI4();
|
||||
JavaMethod callee = cp.lookupMethod(cpi, opcode);
|
||||
return callee;
|
||||
}
|
||||
default:
|
||||
throw new InternalError(BytecodeDisassembler.disassembleOne(method, invokeBci));
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int getBytecodeAt(ResolvedJavaMethod method, int invokeBci) {
|
||||
if (method.getCode() == null) {
|
||||
return -1;
|
||||
}
|
||||
BytecodeStream stream = new BytecodeStream(method.getCode());
|
||||
int opcode = stream.currentBC();
|
||||
while (opcode != Bytecodes.END) {
|
||||
int bci = stream.currentBCI();
|
||||
if (bci == invokeBci) {
|
||||
return opcode;
|
||||
}
|
||||
stream.next();
|
||||
opcode = stream.currentBC();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public interface DisassemblerProvider {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name denoting the format of the disassmembly return by this object.
|
||||
* Gets the name denoting the format of the disassembly returned by this object.
|
||||
*/
|
||||
String getName();
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ package org.graalvm.compiler.core.amd64;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.type.IntegerStamp;
|
||||
import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.graph.spi.Simplifiable;
|
||||
import org.graalvm.compiler.graph.spi.SimplifierTool;
|
||||
@ -72,7 +73,7 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
|
||||
}
|
||||
|
||||
public void canonicalizeIndex(SimplifierTool tool) {
|
||||
if (index instanceof AddNode) {
|
||||
if (index instanceof AddNode && ((IntegerStamp) index.stamp(NodeView.DEFAULT)).getBits() == 64) {
|
||||
AddNode add = (AddNode) index;
|
||||
ValueNode valX = add.getX();
|
||||
if (valX instanceof PhiNode) {
|
||||
|
@ -66,15 +66,14 @@ import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.FREM;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.COS;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.SIN;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.EXP;
|
||||
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicBinaryOp.BinaryIntrinsicOpcode.POW;
|
||||
|
||||
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.AMD64MOp;
|
||||
@ -83,10 +82,11 @@ import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMIOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RMOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AVXOp;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.core.common.calc.FloatConvert;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.lir.ConstantValue;
|
||||
@ -107,6 +107,7 @@ import org.graalvm.compiler.lir.amd64.AMD64ShiftOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64SignExtendOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Unary;
|
||||
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator;
|
||||
import org.graalvm.compiler.lir.gen.LIRGenerator;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64.CPUFeature;
|
||||
@ -114,6 +115,7 @@ import jdk.vm.ci.amd64.AMD64Kind;
|
||||
import jdk.vm.ci.code.CodeUtil;
|
||||
import jdk.vm.ci.code.Register;
|
||||
import jdk.vm.ci.code.RegisterValue;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import jdk.vm.ci.meta.AllocatableValue;
|
||||
import jdk.vm.ci.meta.Constant;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
@ -122,7 +124,6 @@ import jdk.vm.ci.meta.PlatformKind;
|
||||
import jdk.vm.ci.meta.VMConstant;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import jdk.vm.ci.meta.ValueKind;
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
|
||||
/**
|
||||
* This class implements the AMD64 specific portion of the LIR generator.
|
||||
@ -131,6 +132,40 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
|
||||
|
||||
private static final RegisterValue RCX_I = AMD64.rcx.asValue(LIRKind.value(AMD64Kind.DWORD));
|
||||
|
||||
public AMD64ArithmeticLIRGenerator(Maths maths) {
|
||||
this.maths = maths == null ? new Maths() {
|
||||
} : maths;
|
||||
}
|
||||
|
||||
private final Maths maths;
|
||||
|
||||
/**
|
||||
* Interface for emitting LIR for selected {@link Math} routines. A {@code null} return value
|
||||
* for any method in this interface means the caller must emit the LIR itself.
|
||||
*/
|
||||
public interface Maths {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitCos(LIRGenerator gen, Value input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitSin(LIRGenerator gen, Value input) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitTan(LIRGenerator gen, Value input) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitNegate(Value inputVal) {
|
||||
AllocatableValue input = getLIRGen().asAllocatable(inputVal);
|
||||
@ -1042,33 +1077,49 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
|
||||
|
||||
@Override
|
||||
public Value emitMathLog(Value input, boolean base10) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot));
|
||||
LIRGenerator gen = getLIRGen();
|
||||
Variable result = maths.emitLog(gen, input, base10);
|
||||
if (result == null) {
|
||||
result = gen.newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, gen.asAllocatable(input), stackSlot));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathCos(Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot));
|
||||
LIRGenerator gen = getLIRGen();
|
||||
Variable result = maths.emitCos(gen, input);
|
||||
if (result == null) {
|
||||
result = gen.newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, gen.asAllocatable(input), stackSlot));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathSin(Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot));
|
||||
LIRGenerator gen = getLIRGen();
|
||||
Variable result = maths.emitSin(gen, input);
|
||||
if (result == null) {
|
||||
result = gen.newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, gen.asAllocatable(input), stackSlot));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathTan(Value input) {
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot));
|
||||
LIRGenerator gen = getLIRGen();
|
||||
Variable result = maths.emitTan(gen, input);
|
||||
if (result == null) {
|
||||
result = gen.newVariable(LIRKind.combine(input));
|
||||
AllocatableValue stackSlot = gen.getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD));
|
||||
gen.append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, gen.asAllocatable(input), stackSlot));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.SwitchStrategy;
|
||||
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.AMD64ArrayCompareToOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64ArrayEqualsOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Binary;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer;
|
||||
@ -74,6 +75,7 @@ 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;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64LFenceOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
|
||||
import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
|
||||
@ -489,6 +491,20 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
|
||||
LIRKind resultKind = LIRKind.value(AMD64Kind.DWORD);
|
||||
RegisterValue raxRes = AMD64.rax.asValue(resultKind);
|
||||
RegisterValue cnt1 = AMD64.rcx.asValue(length1.getValueKind());
|
||||
RegisterValue cnt2 = AMD64.rdx.asValue(length2.getValueKind());
|
||||
emitMove(cnt1, length1);
|
||||
emitMove(cnt2, length2);
|
||||
append(new AMD64ArrayCompareToOp(this, kind1, kind2, raxRes, array1, array2, cnt1, cnt2));
|
||||
Variable result = newVariable(resultKind);
|
||||
emitMove(result, raxRes);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
|
||||
Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
|
||||
@ -554,4 +570,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
|
||||
public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
|
||||
return new AMD64ZapStackOp(zappedStack, zapValues);
|
||||
}
|
||||
|
||||
public void emitLFence() {
|
||||
append(new AMD64LFenceOp());
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,8 @@
|
||||
|
||||
package org.graalvm.compiler.core.amd64;
|
||||
|
||||
import static org.graalvm.compiler.core.amd64.AMD64NodeLIRBuilder.Options.MitigateSpeculativeExecutionAttacks;
|
||||
|
||||
import org.graalvm.compiler.core.gen.NodeLIRBuilder;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.lir.LIRFrameState;
|
||||
@ -37,6 +39,11 @@ import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
|
||||
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op;
|
||||
import org.graalvm.compiler.nodes.cfg.Block;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.meta.AllocatableValue;
|
||||
@ -44,6 +51,13 @@ import jdk.vm.ci.meta.Value;
|
||||
|
||||
public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
|
||||
|
||||
public static class Options {
|
||||
// @formatter:off
|
||||
@Option(help = "AMD64: Emit lfence instructions at the beginning of basic blocks", type = OptionType.Expert)
|
||||
public static final OptionKey<Boolean> MitigateSpeculativeExecutionAttacks = new OptionKey<>(false);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
|
||||
super(graph, gen, nodeMatchRules);
|
||||
}
|
||||
@ -121,4 +135,21 @@ public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
|
||||
public AMD64LIRGenerator getLIRGeneratorTool() {
|
||||
return (AMD64LIRGenerator) gen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doBlockPrologue(Block block, OptionValues options) {
|
||||
if (MitigateSpeculativeExecutionAttacks.getValue(options)) {
|
||||
boolean hasControlSplitPredecessor = false;
|
||||
for (Block b : block.getPredecessors()) {
|
||||
if (b.getSuccessorCount() > 1) {
|
||||
hasControlSplitPredecessor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
boolean isStartBlock = block.getPredecessorCount() == 0;
|
||||
if (hasControlSplitPredecessor || isStartBlock) {
|
||||
getLIRGeneratorTool().emitLFence();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,6 +259,9 @@ public final class GraalOptions {
|
||||
@Option(help = "", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> OptDevirtualizeInvokesOptimistically = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "Track the NodeSourcePosition.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> TrackNodeSourcePosition = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> MatchExpressions = new OptionKey<>(true);
|
||||
|
||||
@ -273,8 +276,7 @@ public final class GraalOptions {
|
||||
|
||||
@Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug)
|
||||
public static final OptionKey<TraceInliningMode> TraceInlining = new OptionKey<>(TraceInliningMode.None);
|
||||
@Option(help = "Enable tracing of inlining decision.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> TraceInlining = new OptionKey<>(false);
|
||||
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ public final class BiDirectionalTraceBuilder {
|
||||
AbstractBlockBase<?> block = worklist.pollFirst();
|
||||
assert block != null;
|
||||
if (!processed(block)) {
|
||||
Trace trace = new Trace(startTrace(debug, block));
|
||||
Trace trace = new Trace(findTrace(debug, block));
|
||||
for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
|
||||
blockToTrace[traceBlock.getId()] = trace;
|
||||
}
|
||||
@ -101,13 +101,13 @@ public final class BiDirectionalTraceBuilder {
|
||||
* @param debug
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
private Collection<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) {
|
||||
private Collection<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> initBlock) {
|
||||
ArrayDeque<AbstractBlockBase<?>> trace = new ArrayDeque<>();
|
||||
try (Indent i = debug.logAndIndent("StartTrace: %s", block)) {
|
||||
try (Indent i = debug.logAndIndent("StartTrace: %s", initBlock)) {
|
||||
try (Indent indentFront = debug.logAndIndent("Head:")) {
|
||||
for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) {
|
||||
addBlockToTrace(debug, currentBlock);
|
||||
trace.addFirst(currentBlock);
|
||||
for (AbstractBlockBase<?> block = initBlock; block != null; block = selectPredecessor(block)) {
|
||||
addBlockToTrace(debug, block);
|
||||
trace.addFirst(block);
|
||||
}
|
||||
}
|
||||
/* Number head blocks. Can not do this in the loop as we go backwards. */
|
||||
@ -117,11 +117,11 @@ public final class BiDirectionalTraceBuilder {
|
||||
}
|
||||
|
||||
try (Indent indentBack = debug.logAndIndent("Tail:")) {
|
||||
for (AbstractBlockBase<?> currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) {
|
||||
addBlockToTrace(debug, currentBlock);
|
||||
trace.addLast(currentBlock);
|
||||
for (AbstractBlockBase<?> block = selectSuccessor(initBlock); block != null; block = selectSuccessor(block)) {
|
||||
addBlockToTrace(debug, block);
|
||||
trace.addLast(block);
|
||||
/* This time we can number the blocks immediately as we go forwards. */
|
||||
currentBlock.setLinearScanNumber(blockNr++);
|
||||
block.setLinearScanNumber(blockNr++);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,18 +129,18 @@ public final class BiDirectionalTraceBuilder {
|
||||
return trace;
|
||||
}
|
||||
|
||||
private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> currentBlock) {
|
||||
debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
|
||||
processed.set(currentBlock.getId());
|
||||
private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> block) {
|
||||
debug.log("add %s (prob: %f)", block, block.probability());
|
||||
processed.set(block.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The unprocessed predecessor with the highest probability, or {@code null}.
|
||||
*/
|
||||
private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> currentBlock) {
|
||||
private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> block) {
|
||||
AbstractBlockBase<?> next = null;
|
||||
for (AbstractBlockBase<?> pred : currentBlock.getPredecessors()) {
|
||||
if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) {
|
||||
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
|
||||
if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.probability() > next.probability())) {
|
||||
next = pred;
|
||||
}
|
||||
}
|
||||
@ -155,9 +155,9 @@ public final class BiDirectionalTraceBuilder {
|
||||
/**
|
||||
* @return The unprocessed successor with the highest probability, or {@code null}.
|
||||
*/
|
||||
private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> currentBlock) {
|
||||
private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> block) {
|
||||
AbstractBlockBase<?> next = null;
|
||||
for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
|
||||
for (AbstractBlockBase<?> succ : block.getSuccessors()) {
|
||||
if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
|
||||
next = succ;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ import org.graalvm.compiler.debug.DebugContext;
|
||||
import org.graalvm.compiler.debug.Indent;
|
||||
|
||||
/**
|
||||
* Computes traces by starting at a trace head and keep adding predecessors as long as possible.
|
||||
* Computes traces by starting at a trace head and keep adding successors as long as possible.
|
||||
*/
|
||||
public final class UniDirectionalTraceBuilder {
|
||||
|
||||
@ -87,7 +87,7 @@ public final class UniDirectionalTraceBuilder {
|
||||
AbstractBlockBase<?> block = worklist.poll();
|
||||
assert block != null;
|
||||
if (!processed(block)) {
|
||||
Trace trace = new Trace(startTrace(debug, block));
|
||||
Trace trace = new Trace(findTrace(debug, block));
|
||||
for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
|
||||
blockToTrace[traceBlock.getId()] = trace;
|
||||
}
|
||||
@ -102,17 +102,17 @@ public final class UniDirectionalTraceBuilder {
|
||||
* Build a new trace starting at {@code block}.
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
private List<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) {
|
||||
assert checkPredecessorsProcessed(block);
|
||||
private List<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> traceStart) {
|
||||
assert checkPredecessorsProcessed(traceStart);
|
||||
ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>();
|
||||
int blockNumber = 0;
|
||||
try (Indent i = debug.logAndIndent("StartTrace: %s", block)) {
|
||||
for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) {
|
||||
debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability());
|
||||
processed.set(currentBlock.getId());
|
||||
trace.add(currentBlock);
|
||||
unblock(currentBlock);
|
||||
currentBlock.setLinearScanNumber(blockNumber++);
|
||||
try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) {
|
||||
for (AbstractBlockBase<?> block = traceStart; block != null; block = selectNext(block)) {
|
||||
debug.log("add %s (prob: %f)", block, block.probability());
|
||||
processed.set(block.getId());
|
||||
trace.add(block);
|
||||
unblock(block);
|
||||
block.setLinearScanNumber(blockNumber++);
|
||||
}
|
||||
}
|
||||
return trace;
|
||||
@ -120,11 +120,7 @@ public final class UniDirectionalTraceBuilder {
|
||||
|
||||
private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) {
|
||||
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
|
||||
if (!processed(pred)) {
|
||||
assert false : "Predecessor unscheduled: " + pred;
|
||||
return false;
|
||||
}
|
||||
|
||||
assert processed(pred) : "Predecessor unscheduled: " + pred;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -133,8 +129,8 @@ public final class UniDirectionalTraceBuilder {
|
||||
* Decrease the {@link #blocked} count for all predecessors and add them to the worklist once
|
||||
* the count reaches 0.
|
||||
*/
|
||||
private void unblock(AbstractBlockBase<?> currentBlock) {
|
||||
for (AbstractBlockBase<?> successor : currentBlock.getSuccessors()) {
|
||||
private void unblock(AbstractBlockBase<?> block) {
|
||||
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
|
||||
if (!processed(successor)) {
|
||||
int blockCount = --blocked[successor.getId()];
|
||||
assert blockCount >= 0;
|
||||
@ -148,11 +144,11 @@ public final class UniDirectionalTraceBuilder {
|
||||
/**
|
||||
* @return The unprocessed predecessor with the highest probability, or {@code null}.
|
||||
*/
|
||||
private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> currentBlock) {
|
||||
private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> block) {
|
||||
AbstractBlockBase<?> next = null;
|
||||
for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) {
|
||||
if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
|
||||
next = succ;
|
||||
for (AbstractBlockBase<?> successor : block.getSuccessors()) {
|
||||
if (!processed(successor) && (next == null || successor.probability() > next.probability())) {
|
||||
next = successor;
|
||||
}
|
||||
}
|
||||
return next;
|
||||
|
@ -191,8 +191,6 @@ public abstract class AbstractObjectStamp extends AbstractPointerStamp {
|
||||
boolean joinExactType = exactType || other.exactType;
|
||||
if (Objects.equals(type, other.type)) {
|
||||
joinType = type;
|
||||
} else if (type == null && other.type == null) {
|
||||
joinType = null;
|
||||
} else if (type == null) {
|
||||
joinType = other.type;
|
||||
} else if (other.type == null) {
|
||||
|
@ -176,11 +176,15 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append('f');
|
||||
str.append(getBits());
|
||||
str.append(nonNaN ? "!" : "");
|
||||
if (lowerBound == upperBound) {
|
||||
str.append(" [").append(lowerBound).append(']');
|
||||
} else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
|
||||
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
|
||||
if (hasValues()) {
|
||||
str.append(nonNaN ? "!" : "");
|
||||
if (lowerBound == upperBound) {
|
||||
str.append(" [").append(lowerBound).append(']');
|
||||
} else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) {
|
||||
str.append(" [").append(lowerBound).append(" - ").append(upperBound).append(']');
|
||||
}
|
||||
} else {
|
||||
str.append("<empty>");
|
||||
}
|
||||
return str.toString();
|
||||
}
|
||||
@ -200,6 +204,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
if (otherStamp == this) {
|
||||
return this;
|
||||
}
|
||||
if (isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
if (otherStamp.isEmpty()) {
|
||||
return otherStamp;
|
||||
}
|
||||
FloatStamp other = (FloatStamp) otherStamp;
|
||||
assert getBits() == other.getBits();
|
||||
double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
|
||||
@ -383,6 +393,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s) {
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
FloatStamp stamp = (FloatStamp) s;
|
||||
Stamp folded = maybeFoldConstant(this, stamp);
|
||||
if (folded != null) {
|
||||
@ -412,6 +425,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -454,6 +473,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -496,6 +521,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -544,6 +575,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -586,6 +623,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -615,6 +658,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s) {
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
FloatStamp stamp = (FloatStamp) s;
|
||||
JavaConstant constant = stamp.asConstant();
|
||||
if (constant != null) {
|
||||
@ -653,6 +699,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -701,6 +753,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -747,6 +805,12 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s1, Stamp s2) {
|
||||
if (s1.isEmpty()) {
|
||||
return s1;
|
||||
}
|
||||
if (s2.isEmpty()) {
|
||||
return s2;
|
||||
}
|
||||
FloatStamp stamp1 = (FloatStamp) s1;
|
||||
FloatStamp stamp2 = (FloatStamp) s2;
|
||||
Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
|
||||
@ -789,6 +853,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s) {
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
FloatStamp stamp = (FloatStamp) s;
|
||||
Stamp folded = maybeFoldConstant(this, stamp);
|
||||
if (folded != null) {
|
||||
@ -818,6 +885,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s) {
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
FloatStamp stamp = (FloatStamp) s;
|
||||
Stamp folded = maybeFoldConstant(this, stamp);
|
||||
if (folded != null) {
|
||||
@ -839,6 +909,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Int);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 32;
|
||||
boolean mustHaveZero = !floatStamp.isNonNaN();
|
||||
@ -865,6 +938,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Long);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 32;
|
||||
boolean mustHaveZero = !floatStamp.isNonNaN();
|
||||
@ -891,6 +967,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Int);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 64;
|
||||
boolean mustHaveZero = !floatStamp.isNonNaN();
|
||||
@ -917,6 +996,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Long);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 64;
|
||||
boolean mustHaveZero = !floatStamp.isNonNaN();
|
||||
@ -943,6 +1025,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Double);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 32;
|
||||
return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
|
||||
@ -959,6 +1044,9 @@ public class FloatStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Float);
|
||||
}
|
||||
FloatStamp floatStamp = (FloatStamp) stamp;
|
||||
assert floatStamp.getBits() == 64;
|
||||
return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());
|
||||
|
@ -122,11 +122,11 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask);
|
||||
}
|
||||
|
||||
static long significantBit(long bits, long value) {
|
||||
private static long significantBit(long bits, long value) {
|
||||
return (value >>> (bits - 1)) & 1;
|
||||
}
|
||||
|
||||
static long minValueForMasks(int bits, long downMask, long upMask) {
|
||||
private static long minValueForMasks(int bits, long downMask, long upMask) {
|
||||
if (significantBit(bits, upMask) == 0) {
|
||||
// Value is always positive. Minimum value always positive.
|
||||
assert significantBit(bits, downMask) == 0;
|
||||
@ -137,7 +137,7 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
}
|
||||
}
|
||||
|
||||
static long maxValueForMasks(int bits, long downMask, long upMask) {
|
||||
private static long maxValueForMasks(int bits, long downMask, long upMask) {
|
||||
if (significantBit(bits, downMask) == 1) {
|
||||
// Value is always negative. Maximum value always negative.
|
||||
assert significantBit(bits, upMask) == 1;
|
||||
@ -330,6 +330,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
if (otherStamp == this) {
|
||||
return this;
|
||||
}
|
||||
if (isEmpty()) {
|
||||
return otherStamp;
|
||||
}
|
||||
if (otherStamp.isEmpty()) {
|
||||
return this;
|
||||
}
|
||||
IntegerStamp other = (IntegerStamp) otherStamp;
|
||||
return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask);
|
||||
}
|
||||
@ -413,7 +419,7 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
return super.equals(other);
|
||||
}
|
||||
|
||||
public static long upMaskFor(int bits, long lowerBound, long upperBound) {
|
||||
private static long upMaskFor(int bits, long lowerBound, long upperBound) {
|
||||
long mask = lowerBound | upperBound;
|
||||
if (mask == 0) {
|
||||
return 0;
|
||||
@ -595,6 +601,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp s) {
|
||||
if (s.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) s;
|
||||
int bits = stamp.getBits();
|
||||
if (stamp.lowerBound == stamp.upperBound) {
|
||||
@ -622,6 +631,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
|
||||
@ -715,6 +730,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
|
||||
@ -885,6 +906,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
JavaKind javaKind = a.getStackKind();
|
||||
@ -952,6 +979,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
JavaKind javaKind = a.getStackKind();
|
||||
@ -1046,6 +1079,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
assert a.getBits() == b.getBits();
|
||||
@ -1083,6 +1122,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
assert a.getBits() == b.getBits();
|
||||
@ -1121,6 +1166,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp) {
|
||||
if (stamp.isEmpty()) {
|
||||
return stamp;
|
||||
}
|
||||
IntegerStamp integerStamp = (IntegerStamp) stamp;
|
||||
int bits = integerStamp.getBits();
|
||||
long defaultMask = CodeUtil.mask(bits);
|
||||
@ -1140,6 +1188,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
assert a.getBits() == b.getBits();
|
||||
@ -1167,6 +1221,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
assert a.getBits() == b.getBits();
|
||||
@ -1192,6 +1252,12 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
|
||||
if (stamp1.isEmpty()) {
|
||||
return stamp1;
|
||||
}
|
||||
if (stamp2.isEmpty()) {
|
||||
return stamp2;
|
||||
}
|
||||
IntegerStamp a = (IntegerStamp) stamp1;
|
||||
IntegerStamp b = (IntegerStamp) stamp2;
|
||||
assert a.getBits() == b.getBits();
|
||||
@ -1269,8 +1335,7 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
upMask |= value.upMask() << (i & shiftMask);
|
||||
}
|
||||
}
|
||||
Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
|
||||
return result;
|
||||
return IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
|
||||
}
|
||||
return value.unrestricted();
|
||||
}
|
||||
@ -1392,6 +1457,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return input;
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
int bits = stamp.getBits();
|
||||
if (stamp.lowerBound == stamp.upperBound) {
|
||||
@ -1419,6 +1487,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.forInteger(resultBits).empty();
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert inputBits == stamp.getBits();
|
||||
assert inputBits <= resultBits;
|
||||
@ -1458,6 +1529,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.forInteger(resultBits).empty();
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert inputBits == stamp.getBits();
|
||||
assert inputBits <= resultBits;
|
||||
@ -1487,6 +1561,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.forInteger(resultBits).empty();
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert inputBits == stamp.getBits();
|
||||
assert resultBits <= inputBits;
|
||||
@ -1526,6 +1603,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Float);
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert stamp.getBits() == 32;
|
||||
float lowerBound = stamp.lowerBound();
|
||||
@ -1544,6 +1624,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Float);
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert stamp.getBits() == 64;
|
||||
float lowerBound = stamp.lowerBound();
|
||||
@ -1562,6 +1645,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Double);
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert stamp.getBits() == 32;
|
||||
double lowerBound = stamp.lowerBound();
|
||||
@ -1580,6 +1666,9 @@ public final class IntegerStamp extends PrimitiveStamp {
|
||||
|
||||
@Override
|
||||
public Stamp foldStamp(Stamp input) {
|
||||
if (input.isEmpty()) {
|
||||
return StampFactory.empty(JavaKind.Double);
|
||||
}
|
||||
IntegerStamp stamp = (IntegerStamp) input;
|
||||
assert stamp.getBits() == 64;
|
||||
double lowerBound = stamp.lowerBound();
|
||||
|
@ -161,6 +161,10 @@ public class StampFactory {
|
||||
return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static IntegerStamp forUnsignedInteger(int bits) {
|
||||
return forUnsignedInteger(bits, 0, NumUtil.maxValueUnsigned(bits), 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
||||
public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
|
||||
return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
|
||||
}
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.common.util;
|
||||
|
||||
public final class UnsignedLong {
|
||||
private final long value;
|
||||
|
||||
public UnsignedLong(long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public long asLong() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean equals(long unsignedValue) {
|
||||
return value == unsignedValue;
|
||||
}
|
||||
|
||||
public boolean isLessThan(long unsignedValue) {
|
||||
return Long.compareUnsigned(value, unsignedValue) < 0;
|
||||
}
|
||||
|
||||
public boolean isLessOrEqualTo(long unsignedValue) {
|
||||
return Long.compareUnsigned(value, unsignedValue) <= 0;
|
||||
}
|
||||
|
||||
public UnsignedLong times(long unsignedValue) {
|
||||
if (unsignedValue != 0 && Long.compareUnsigned(value, Long.divideUnsigned(0xffff_ffff_ffff_ffffL, unsignedValue)) > 0) {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
return new UnsignedLong(value * unsignedValue);
|
||||
}
|
||||
|
||||
public UnsignedLong minus(long unsignedValue) {
|
||||
if (Long.compareUnsigned(value, unsignedValue) < 0) {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
return new UnsignedLong(value - unsignedValue);
|
||||
}
|
||||
|
||||
public UnsignedLong plus(long unsignedValue) {
|
||||
if (Long.compareUnsigned(0xffff_ffff_ffff_ffffL - unsignedValue, value) < 0) {
|
||||
throw new ArithmeticException();
|
||||
}
|
||||
return new UnsignedLong(value + unsignedValue);
|
||||
}
|
||||
|
||||
public UnsignedLong wrappingPlus(long unsignedValue) {
|
||||
return new UnsignedLong(value + unsignedValue);
|
||||
}
|
||||
|
||||
public UnsignedLong wrappingTimes(long unsignedValue) {
|
||||
return new UnsignedLong(value * unsignedValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UnsignedLong(" + Long.toUnsignedString(value) + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
UnsignedLong that = (UnsignedLong) o;
|
||||
return value == that.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Long.hashCode(value);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.debug.DebugContext;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.printer.BinaryGraphPrinter;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class BasePhaseBinaryGraphTest {
|
||||
private MyPhase phase;
|
||||
private BinaryGraphPrinter printer;
|
||||
|
||||
@Before
|
||||
public void createPhase() {
|
||||
phase = new MyPhase();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void createPrinter() throws Exception {
|
||||
printer = new BinaryGraphPrinter(DebugContext.DISABLED, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void phaseNameIsRecognizedAsType() {
|
||||
String res = printer.typeName(phase.getName());
|
||||
assertEquals(MyPhase.class.getName(), res);
|
||||
}
|
||||
|
||||
private static final class MyPhase extends BasePhase<Void> {
|
||||
@Override
|
||||
protected void run(StructuredGraph graph, Void context) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CharSequence getName() {
|
||||
return super.getName();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ConditionalNodeTest extends GraalCompilerTest {
|
||||
|
||||
@SuppressWarnings("unused") private static int sink0;
|
||||
@SuppressWarnings("unused") private static int sink1;
|
||||
|
||||
@Test
|
||||
public void test0() {
|
||||
test("conditionalTest0", 0);
|
||||
test("conditionalTest0", 1);
|
||||
}
|
||||
|
||||
public static int conditionalTest0(int a) {
|
||||
int value;
|
||||
if (a == 1) {
|
||||
value = -1;
|
||||
sink1 = 0;
|
||||
} else {
|
||||
value = 6;
|
||||
sink1 = 1;
|
||||
}
|
||||
sink0 = 1;
|
||||
return Math.max(value, 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
test("conditionalTest1", 0);
|
||||
test("conditionalTest1", 1);
|
||||
}
|
||||
|
||||
public static int conditionalTest1(int a) {
|
||||
int value;
|
||||
if (a == 1) {
|
||||
value = -1;
|
||||
sink1 = 0;
|
||||
} else {
|
||||
value = 6;
|
||||
sink1 = 1;
|
||||
}
|
||||
sink0 = 1;
|
||||
return Math.max(6, value);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() {
|
||||
test("conditionalTest2", 0);
|
||||
test("conditionalTest2", 1);
|
||||
}
|
||||
|
||||
public static int conditionalTest2(int a) {
|
||||
int value;
|
||||
if (a == 1) {
|
||||
value = -1;
|
||||
sink1 = 0;
|
||||
} else {
|
||||
value = 6;
|
||||
sink1 = 1;
|
||||
}
|
||||
sink0 = 1;
|
||||
return Math.min(value, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test3() {
|
||||
test("conditionalTest3", 0);
|
||||
test("conditionalTest3", 1);
|
||||
}
|
||||
|
||||
public static int conditionalTest3(int a) {
|
||||
int value;
|
||||
if (a == 1) {
|
||||
value = -1;
|
||||
sink1 = 0;
|
||||
} else {
|
||||
value = 6;
|
||||
sink1 = 1;
|
||||
}
|
||||
sink0 = 1;
|
||||
return Math.min(-1, value);
|
||||
}
|
||||
}
|
@ -30,6 +30,7 @@ import org.graalvm.compiler.graph.NodeClass;
|
||||
import org.graalvm.compiler.loop.InductionVariable;
|
||||
import org.graalvm.compiler.loop.LoopsData;
|
||||
import org.graalvm.compiler.nodeinfo.NodeInfo;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.NodeView;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.ValueNode;
|
||||
@ -52,25 +53,47 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
ValueNode get(InductionVariable iv);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface StaticIVProperty {
|
||||
long get(InductionVariable iv);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface IVPredicate {
|
||||
boolean test(InductionVariable iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property of an induction variable.
|
||||
*
|
||||
* @param property
|
||||
*/
|
||||
private static int get(IVProperty property, int iv) {
|
||||
private static int get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck,
|
||||
int iv) {
|
||||
return iv;
|
||||
}
|
||||
|
||||
private static int get(@SuppressWarnings("unused") IVProperty property, int iv) {
|
||||
return iv;
|
||||
}
|
||||
|
||||
private static long get(@SuppressWarnings("unused") IVProperty property, @SuppressWarnings("unused") StaticIVProperty staticProperty, @SuppressWarnings("unused") IVPredicate constantCheck,
|
||||
long iv) {
|
||||
return iv;
|
||||
}
|
||||
|
||||
private static long get(@SuppressWarnings("unused") IVProperty property, long iv) {
|
||||
return iv;
|
||||
}
|
||||
|
||||
private static class Result {
|
||||
public int extremum;
|
||||
public int exitValue;
|
||||
public long extremum;
|
||||
public long exitValue;
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + exitValue;
|
||||
result = prime * result + extremum;
|
||||
result = prime * result + Long.hashCode(exitValue);
|
||||
result = prime * result + Long.hashCode(extremum);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -95,7 +118,7 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
Result ret = new Result();
|
||||
for (i = start; i < limit; i += inc) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
@ -103,32 +126,42 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void increment1() {
|
||||
test("incrementSnippet", 0, 256, 1);
|
||||
testCounted("incrementSnippet", 0, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment2() {
|
||||
test("incrementSnippet", 0, 256, 2);
|
||||
testCounted("incrementSnippet", 0, 256, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment3() {
|
||||
test("incrementSnippet", 0, 256, 3);
|
||||
testCounted("incrementSnippet", 0, 256, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment4() {
|
||||
test("incrementSnippet", -10, Integer.MAX_VALUE, 1);
|
||||
testCounted("incrementSnippet", -10, 1, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment5() {
|
||||
test("incrementSnippet", 256, 256, 1);
|
||||
testCounted("incrementSnippet", 256, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment6() {
|
||||
test("incrementSnippet", 257, 256, 1);
|
||||
testCounted("incrementSnippet", 257, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment7() {
|
||||
testCounted("incrementSnippet", -10, Integer.MAX_VALUE, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void increment8() {
|
||||
testCounted("incrementSnippet", -10, Integer.MAX_VALUE - 1, 2);
|
||||
}
|
||||
|
||||
public static Result incrementEqSnippet(int start, int limit, int step) {
|
||||
@ -137,7 +170,7 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
Result ret = new Result();
|
||||
for (i = start; i <= limit; i += inc) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
@ -145,32 +178,42 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void incrementEq1() {
|
||||
test("incrementEqSnippet", 0, 256, 1);
|
||||
testCounted("incrementEqSnippet", 0, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq2() {
|
||||
test("incrementEqSnippet", 0, 256, 2);
|
||||
testCounted("incrementEqSnippet", 0, 256, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq3() {
|
||||
test("incrementEqSnippet", 0, 256, 3);
|
||||
testCounted("incrementEqSnippet", 0, 256, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq4() {
|
||||
test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
|
||||
testCounted("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq5() {
|
||||
test("incrementEqSnippet", 256, 256, 1);
|
||||
testCounted("incrementEqSnippet", 256, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq6() {
|
||||
test("incrementEqSnippet", 257, 256, 1);
|
||||
testCounted("incrementEqSnippet", 257, 256, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq7() {
|
||||
testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 1, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementEq8() {
|
||||
testCounted("incrementEqSnippet", -10, Integer.MAX_VALUE - 2, 2);
|
||||
}
|
||||
|
||||
public static Result decrementSnippet(int start, int limit, int step) {
|
||||
@ -179,7 +222,7 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
Result ret = new Result();
|
||||
for (i = start; i > limit; i -= dec) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
@ -187,17 +230,27 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void decrement1() {
|
||||
test("decrementSnippet", 256, 0, 1);
|
||||
testCounted("decrementSnippet", 256, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrement2() {
|
||||
test("decrementSnippet", 256, 0, 2);
|
||||
testCounted("decrementSnippet", 256, 0, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrement3() {
|
||||
test("decrementSnippet", 256, 0, 3);
|
||||
testCounted("decrementSnippet", 256, 0, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrement4() {
|
||||
testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrement5() {
|
||||
testCounted("decrementSnippet", Integer.MAX_VALUE, -10, 2);
|
||||
}
|
||||
|
||||
public static Result decrementEqSnippet(int start, int limit, int step) {
|
||||
@ -206,7 +259,7 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
Result ret = new Result();
|
||||
for (i = start; i >= limit; i -= dec) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
@ -214,22 +267,32 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void decrementEq1() {
|
||||
test("decrementEqSnippet", 256, 0, 1);
|
||||
testCounted("decrementEqSnippet", 256, 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementEq2() {
|
||||
test("decrementEqSnippet", 256, 0, 2);
|
||||
testCounted("decrementEqSnippet", 256, 0, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementEq3() {
|
||||
test("decrementEqSnippet", 256, 0, 3);
|
||||
testCounted("decrementEqSnippet", 256, 0, 3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementEq4() {
|
||||
test("decrementEqSnippet", -10, 0, Integer.MAX_VALUE);
|
||||
testCounted("decrementEqSnippet", -10, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementEq5() {
|
||||
testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementEq6() {
|
||||
testCounted("decrementEqSnippet", Integer.MAX_VALUE, -10, 2);
|
||||
}
|
||||
|
||||
public static Result twoVariablesSnippet() {
|
||||
@ -238,7 +301,7 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
j += 5;
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, j);
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, j);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, j);
|
||||
return ret;
|
||||
@ -246,7 +309,83 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
|
||||
@Test
|
||||
public void testTwoVariables() {
|
||||
test("twoVariablesSnippet");
|
||||
testCounted("twoVariablesSnippet");
|
||||
}
|
||||
|
||||
public static Result incrementNeqSnippet(int limit) {
|
||||
int i;
|
||||
int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
|
||||
Result ret = new Result();
|
||||
for (i = 0; i != posLimit; i++) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementNeq() {
|
||||
testCounted("decrementNeqSnippet", 256);
|
||||
}
|
||||
|
||||
public static Result decrementNeqSnippet(int limit) {
|
||||
int i;
|
||||
int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
|
||||
Result ret = new Result();
|
||||
for (i = posLimit; i != 0; i--) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementNeq() {
|
||||
testCounted("incrementNeqSnippet", 256);
|
||||
}
|
||||
|
||||
public static Result incrementLongSnippet(long start, long limit, long step) {
|
||||
long i;
|
||||
long inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
|
||||
Result ret = new Result();
|
||||
for (i = start; i < limit; i += inc) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong1() {
|
||||
testCounted("incrementLongSnippet", 0L, 256L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong2() {
|
||||
testCounted("incrementLongSnippet", 0L, 256L, 2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong3() {
|
||||
testCounted("incrementLongSnippet", 0L, 256L, 3L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong4() {
|
||||
testCounted("incrementLongSnippet", -10L, 1L, Long.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong5() {
|
||||
testCounted("incrementLongSnippet", 256L, 256L, 1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementLong6() {
|
||||
testCounted("incrementLongSnippet", 257L, 256L, 1L);
|
||||
}
|
||||
|
||||
@NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
|
||||
@ -255,18 +394,31 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
public static final NodeClass<IVPropertyNode> TYPE = NodeClass.create(IVPropertyNode.class);
|
||||
|
||||
private final IVProperty property;
|
||||
private final StaticIVProperty staticProperty;
|
||||
private final IVPredicate staticCheck;
|
||||
@Input private ValueNode iv;
|
||||
|
||||
protected IVPropertyNode(IVProperty property, ValueNode iv) {
|
||||
protected IVPropertyNode(IVProperty property, StaticIVProperty staticProperty, IVPredicate staticCheck, ValueNode iv) {
|
||||
super(TYPE, iv.stamp(NodeView.DEFAULT).unrestricted());
|
||||
this.property = property;
|
||||
this.staticProperty = staticProperty;
|
||||
this.staticCheck = staticCheck;
|
||||
this.iv = iv;
|
||||
}
|
||||
|
||||
public void rewrite(LoopsData loops) {
|
||||
InductionVariable inductionVariable = loops.getInductionVariable(iv);
|
||||
assert inductionVariable != null;
|
||||
ValueNode node = property.get(inductionVariable);
|
||||
ValueNode node = null;
|
||||
if (staticCheck != null) {
|
||||
assert staticProperty != null;
|
||||
if (staticCheck.test(inductionVariable)) {
|
||||
node = ConstantNode.forLong(staticProperty.get(inductionVariable), graph());
|
||||
}
|
||||
}
|
||||
if (node == null) {
|
||||
node = property.get(inductionVariable);
|
||||
}
|
||||
replaceAtUsagesAndDelete(node);
|
||||
}
|
||||
|
||||
@ -279,7 +431,13 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
@Override
|
||||
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
|
||||
Registration r = new Registration(invocationPlugins, CountedLoopTest.class);
|
||||
r.register2("get", IVProperty.class, int.class, new InvocationPlugin() {
|
||||
registerPlugins(r, JavaKind.Int);
|
||||
registerPlugins(r, JavaKind.Long);
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
private void registerPlugins(Registration r, JavaKind ivKind) {
|
||||
r.register2("get", IVProperty.class, ivKind.toJavaClass(), new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
|
||||
IVProperty property = null;
|
||||
@ -287,14 +445,36 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
|
||||
}
|
||||
if (property != null) {
|
||||
b.addPush(JavaKind.Int, new IVPropertyNode(property, arg2));
|
||||
b.addPush(ivKind, new IVPropertyNode(property, null, null, arg2));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
r.register4("get", IVProperty.class, StaticIVProperty.class, IVPredicate.class, ivKind.toJavaClass(), new InvocationPlugin() {
|
||||
@Override
|
||||
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2, ValueNode arg3, ValueNode arg4) {
|
||||
IVProperty property = null;
|
||||
StaticIVProperty staticProperty = null;
|
||||
IVPredicate staticCheck = null;
|
||||
if (arg1.isConstant()) {
|
||||
property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
|
||||
}
|
||||
if (arg2.isConstant()) {
|
||||
staticProperty = getSnippetReflection().asObject(StaticIVProperty.class, arg2.asJavaConstant());
|
||||
}
|
||||
if (arg3.isConstant()) {
|
||||
staticCheck = getSnippetReflection().asObject(IVPredicate.class, arg3.asJavaConstant());
|
||||
}
|
||||
if (property != null && staticProperty != null && staticCheck != null) {
|
||||
b.addPush(ivKind, new IVPropertyNode(property, staticProperty, staticCheck, arg4));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
super.registerInvocationPlugins(invocationPlugins);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -308,37 +488,17 @@ public class CountedLoopTest extends GraalCompilerTest {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Result incrementNeqSnippet(int limit) {
|
||||
int i;
|
||||
int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
|
||||
Result ret = new Result();
|
||||
for (i = 0; i != posLimit; i++) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
private Object[] argsToBind;
|
||||
|
||||
@Override
|
||||
protected Object[] getArgumentToBind() {
|
||||
return argsToBind;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decrementNeq() {
|
||||
test("decrementNeqSnippet", 256);
|
||||
}
|
||||
|
||||
public static Result decrementNeqSnippet(int limit) {
|
||||
int i;
|
||||
int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive
|
||||
Result ret = new Result();
|
||||
for (i = posLimit; i != 0; i--) {
|
||||
GraalDirectives.controlFlowAnchor();
|
||||
ret.extremum = get(InductionVariable::extremumNode, i);
|
||||
}
|
||||
ret.exitValue = get(InductionVariable::exitValueNode, i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void incrementNeq() {
|
||||
test("incrementNeqSnippet", 256);
|
||||
public void testCounted(String snippetName, Object... args) {
|
||||
test(snippetName, args);
|
||||
argsToBind = args;
|
||||
test(snippetName, args);
|
||||
argsToBind = null;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package org.graalvm.compiler.core.test;
|
||||
|
||||
import static java.lang.reflect.Modifier.isStatic;
|
||||
import static jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
|
||||
import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
|
||||
import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION;
|
||||
@ -47,6 +48,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import org.graalvm.compiler.api.directives.GraalDirectives;
|
||||
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
|
||||
import org.graalvm.compiler.api.test.Graal;
|
||||
@ -931,7 +933,8 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
|
||||
if (!forceCompile && graph == null) {
|
||||
boolean useCache = !forceCompile && getArgumentToBind() == null;
|
||||
if (useCache && graph == null) {
|
||||
InstalledCode cached = cache.get(installedCodeOwner);
|
||||
if (cached != null) {
|
||||
if (cached.isValid()) {
|
||||
@ -964,7 +967,7 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
|
||||
}
|
||||
} catch (BailoutException e) {
|
||||
if (retry <= BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
|
||||
if (retry < BAILOUT_RETRY_LIMIT && graph == null && !e.isPermanent()) {
|
||||
// retry (if there is no predefined graph)
|
||||
TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
|
||||
continue;
|
||||
@ -978,7 +981,7 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
|
||||
if (!forceCompile) {
|
||||
if (useCache) {
|
||||
cache.put(installedCodeOwner, installedCode);
|
||||
}
|
||||
return installedCode;
|
||||
@ -1243,12 +1246,33 @@ public abstract class GraalCompilerTest extends GraalTest {
|
||||
DebugContext debug = graph.getDebug();
|
||||
try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) {
|
||||
graphBuilderSuite.apply(graph, getDefaultHighTierContext());
|
||||
Object[] args = getArgumentToBind();
|
||||
if (args != null) {
|
||||
bindArguments(graph, args);
|
||||
}
|
||||
return graph;
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void bindArguments(StructuredGraph graph, Object[] argsToBind) {
|
||||
ResolvedJavaMethod m = graph.method();
|
||||
Object receiver = isStatic(m.getModifiers()) ? null : this;
|
||||
Object[] args = argsWithReceiver(receiver, argsToBind);
|
||||
JavaType[] parameterTypes = m.toParameterTypes();
|
||||
assert parameterTypes.length == args.length;
|
||||
for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
|
||||
JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
|
||||
ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
|
||||
param.replaceAtUsages(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
protected Object[] getArgumentToBind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
|
||||
return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
|
||||
}
|
||||
|
@ -77,8 +77,7 @@ public class GraphEncoderTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
for (StructuredGraph originalGraph : originalGraphs) {
|
||||
EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(),
|
||||
originalGraph.getMethods());
|
||||
EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph);
|
||||
GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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 static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount;
|
||||
import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isEmpty;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.nodes.LoopBeginNode;
|
||||
import org.graalvm.compiler.nodes.ParameterNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
|
||||
public class SwitchDyingLoopTest extends GraalCompilerTest {
|
||||
|
||||
@SuppressWarnings("fallthrough")
|
||||
public static int snippet(int a, int n) {
|
||||
int r = 0;
|
||||
loop: for (int i = 0; i < n; i++) {
|
||||
int v = (i * 167 + 13) & 0xff;
|
||||
switch (v & a) {
|
||||
case 0x80:
|
||||
r += 1; // fall through
|
||||
case 0x40:
|
||||
r += 2; // fall through
|
||||
case 0x20:
|
||||
r += 3;
|
||||
continue;
|
||||
case 0x08:
|
||||
r += 5; // fall through
|
||||
case 0x04:
|
||||
r += 7; // fall through
|
||||
case 0x02:
|
||||
r += 9; // fall through
|
||||
default:
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
CanonicalizerPhase canonicalizerPhase = new CanonicalizerPhase();
|
||||
HighTierContext highTierContext = getDefaultHighTierContext();
|
||||
StructuredGraph graph = parseEager("snippet", StructuredGraph.AllowAssumptions.YES);
|
||||
// there should be 1 loop and 1 switch
|
||||
assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1));
|
||||
assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
|
||||
canonicalizerPhase.apply(graph, highTierContext);
|
||||
// after canonicalization, the loop and switch should still be there
|
||||
assertThat(graph.getNodes(LoopBeginNode.TYPE), hasCount(1));
|
||||
assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
|
||||
// add stamp to `a` so that paths leading to continue can be trimmed
|
||||
ParameterNode parameter = graph.getParameter(0);
|
||||
assertNotNull(parameter);
|
||||
parameter.setStamp(StampFactory.forInteger(JavaKind.Int, 0, 255, 0, 0xf));
|
||||
canonicalizerPhase.apply(graph, highTierContext);
|
||||
// the loop should have disappeared and there should still be a switch
|
||||
assertThat(graph.getNodes(LoopBeginNode.TYPE), isEmpty());
|
||||
assertThat(graph.getNodes(IntegerSwitchNode.TYPE), hasCount(1));
|
||||
}
|
||||
}
|
@ -74,9 +74,9 @@ public class TrivialInliningExplosionTest extends GraalCompilerTest {
|
||||
int afterCompileSize = lastCompiledGraph.getNodeCount();
|
||||
|
||||
// The values of afterParseSize and afterCompileSize when this
|
||||
// test was written were 849 and 848 respectively.
|
||||
Assert.assertTrue(afterParseSize < 2000);
|
||||
Assert.assertTrue(afterCompileSize < 2000);
|
||||
// test was written were 3223 and 3505 respectively.
|
||||
Assert.assertTrue(afterParseSize < 4000);
|
||||
Assert.assertTrue(afterCompileSize < 4000);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.core.common.util.UnsignedLong;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UnsignedLongTest {
|
||||
@Test
|
||||
public void testEquals() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertTrue(fortyTwo.equals(42));
|
||||
Assert.assertFalse(fortyTwo.equals(99));
|
||||
UnsignedLong longFortyTwo = new UnsignedLong(0x42_0000_8888L);
|
||||
Assert.assertTrue(longFortyTwo.equals(0x42_0000_8888L));
|
||||
Assert.assertFalse(longFortyTwo.equals(0x99_0000_8888L));
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
|
||||
Assert.assertTrue(longUnsigned.equals(0x8000_7777_0000_8888L));
|
||||
Assert.assertFalse(longUnsigned.equals(0xf000_7777_0000_8888L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLessThan() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertTrue(fortyTwo.isLessThan(45));
|
||||
Assert.assertFalse(fortyTwo.isLessThan(42));
|
||||
Assert.assertFalse(fortyTwo.isLessThan(40));
|
||||
Assert.assertTrue(fortyTwo.isLessThan(0xffff_ffff_ffff_ffffL));
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
|
||||
Assert.assertTrue(longUnsigned.isLessThan(0xffff_ffff_ffff_ffffL));
|
||||
Assert.assertFalse(longUnsigned.isLessThan(42));
|
||||
Assert.assertFalse(longUnsigned.isLessThan(0x8000_0777_0000_8888L));
|
||||
Assert.assertFalse(longUnsigned.isLessThan(0x8000_7777_0000_8888L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsLessOrEqualTo() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertTrue(fortyTwo.isLessOrEqualTo(45));
|
||||
Assert.assertTrue(fortyTwo.isLessOrEqualTo(42));
|
||||
Assert.assertFalse(fortyTwo.isLessOrEqualTo(40));
|
||||
Assert.assertTrue(fortyTwo.isLessOrEqualTo(0xffff_ffff_ffff_ffffL));
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0x8000_7777_0000_8888L);
|
||||
Assert.assertTrue(longUnsigned.isLessOrEqualTo(0xffff_ffff_ffff_ffffL));
|
||||
Assert.assertFalse(longUnsigned.isLessOrEqualTo(42));
|
||||
Assert.assertFalse(longUnsigned.isLessOrEqualTo(0x8000_0777_0000_8888L));
|
||||
Assert.assertTrue(longUnsigned.isLessOrEqualTo(0x8000_7777_0000_8888L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimes() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertEquals(42 * 42, fortyTwo.times(42).asLong());
|
||||
Assert.assertEquals(0xffff_ffff_ffff_fff0L, fortyTwo.times(0x618618618618618L).asLong());
|
||||
}
|
||||
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testTimesException() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
fortyTwo.times(0x618618618618619L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinus() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertEquals(0, fortyTwo.minus(42).asLong());
|
||||
Assert.assertEquals(40, fortyTwo.minus(2).asLong());
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
|
||||
Assert.assertEquals(0, longUnsigned.minus(0xffff_ffff_ffff_fff0L).asLong());
|
||||
}
|
||||
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testMinusException() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
fortyTwo.minus(43);
|
||||
}
|
||||
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testMinusException2() {
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
|
||||
longUnsigned.minus(0xffff_ffff_ffff_fff1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPlus() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertEquals(84, fortyTwo.plus(42).asLong());
|
||||
Assert.assertEquals(44, fortyTwo.plus(2).asLong());
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
|
||||
Assert.assertEquals(0xffff_ffff_ffff_ffffL, longUnsigned.plus(0xf).asLong());
|
||||
}
|
||||
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testPlusException() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
fortyTwo.plus(0xffff_ffff_ffff_fff0L);
|
||||
}
|
||||
|
||||
@Test(expected = ArithmeticException.class)
|
||||
public void testPlusException2() {
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
|
||||
longUnsigned.plus(42);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrappingTimes() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertEquals(0x1a, fortyTwo.wrappingTimes(0x618618618618619L).asLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrappingPlus() {
|
||||
UnsignedLong fortyTwo = new UnsignedLong(42);
|
||||
Assert.assertEquals(0x1a, fortyTwo.wrappingPlus(0xffff_ffff_ffff_fff0L).asLong());
|
||||
UnsignedLong longUnsigned = new UnsignedLong(0xffff_ffff_ffff_fff0L);
|
||||
Assert.assertEquals(0x1a, longUnsigned.wrappingPlus(42).asLong());
|
||||
}
|
||||
}
|
@ -240,6 +240,7 @@ public class GraalCompiler {
|
||||
debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
|
||||
|
||||
debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
|
||||
graph.logInliningTree();
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
} finally {
|
||||
|
@ -316,6 +316,10 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
|
||||
return values.toArray(new Value[values.size()]);
|
||||
}
|
||||
|
||||
public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("try")
|
||||
public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) {
|
||||
@ -341,6 +345,7 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
|
||||
}
|
||||
}
|
||||
}
|
||||
doBlockPrologue(block, options);
|
||||
|
||||
List<Node> nodes = blockMap.get(block);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -45,6 +45,7 @@ import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
|
||||
import org.graalvm.compiler.phases.common.NodeCounterPhase;
|
||||
import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
|
||||
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
|
||||
import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
|
||||
@ -74,6 +75,10 @@ public class HighTier extends PhaseSuite<HighTierContext> {
|
||||
|
||||
appendPhase(canonicalizer);
|
||||
|
||||
if (NodeCounterPhase.Options.NodeCounters.getValue(options)) {
|
||||
appendPhase(new NodeCounterPhase());
|
||||
}
|
||||
|
||||
if (Options.Inline.getValue(options)) {
|
||||
appendPhase(new InliningPhase(canonicalizer));
|
||||
appendPhase(new DeadCodeEliminationPhase(Optional));
|
||||
|
@ -178,7 +178,7 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
|
||||
* @param method the method compiled to produce {@code compiledCode} or {@code null} if the
|
||||
* input to {@code compResult} was not a {@link ResolvedJavaMethod}
|
||||
* @param compilationRequest the compilation request or {@code null}
|
||||
* @param compilationResult the code to be compiled
|
||||
* @param compilationResult the code to be installed
|
||||
* @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a
|
||||
* reference to the installed code. If {@code null}, a new {@link InstalledCode}
|
||||
* object will be created.
|
||||
@ -204,12 +204,13 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
|
||||
}
|
||||
try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
|
||||
DebugContext.Activation a = debug.activate()) {
|
||||
preCodeInstallationTasks(tasks, compilationResult);
|
||||
|
||||
InstalledCode installedCode;
|
||||
try {
|
||||
preCodeInstallationTasks(tasks, compilationResult, predefinedInstalledCode);
|
||||
CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
|
||||
installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
|
||||
assert predefinedInstalledCode == null || installedCode == predefinedInstalledCode;
|
||||
} catch (Throwable t) {
|
||||
failCodeInstallationTasks(tasks, t);
|
||||
throw t;
|
||||
@ -229,9 +230,9 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
|
||||
}
|
||||
}
|
||||
|
||||
private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult) {
|
||||
private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult, InstalledCode predefinedInstalledCode) {
|
||||
for (CodeInstallationTask task : tasks) {
|
||||
task.preProcess(compilationResult);
|
||||
task.preProcess(compilationResult, predefinedInstalledCode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,23 +306,29 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
|
||||
public abstract static class CodeInstallationTask {
|
||||
/**
|
||||
* Task to run before code installation.
|
||||
*
|
||||
* @param compilationResult the code about to be installed
|
||||
* @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object that will be
|
||||
* used as a reference to the installed code. May be {@code null}.
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void preProcess(CompilationResult compilationResult) {
|
||||
public void preProcess(CompilationResult compilationResult, InstalledCode predefinedInstalledCode) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Task to run after the code is installed.
|
||||
*
|
||||
* @param installedCode a reference to the installed code
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void postProcess(InstalledCode installedCode) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked after {@link #preProcess} when code installation fails.
|
||||
*
|
||||
* @param cause the cause of the installation failure
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public void installFailed(Throwable t) {
|
||||
public void installFailed(Throwable cause) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@
|
||||
<metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/>
|
||||
<property name="format" value="\s$"/>
|
||||
<property name="message" value="Illegal trailing whitespace(s) at the end of the line."/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
<property name="ignoreComments" value="false"/>
|
||||
<metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
|
||||
</module>
|
||||
<module name="RegexpSinglelineJava">
|
||||
|
@ -22,6 +22,9 @@
|
||||
*/
|
||||
package org.graalvm.compiler.graph;
|
||||
|
||||
import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Default;
|
||||
import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.Track;
|
||||
import static org.graalvm.compiler.graph.Graph.SourcePositionTracking.UpdateOnly;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
|
||||
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
|
||||
|
||||
@ -33,6 +36,7 @@ import java.util.function.Consumer;
|
||||
import org.graalvm.collections.EconomicMap;
|
||||
import org.graalvm.collections.Equivalence;
|
||||
import org.graalvm.collections.UnmodifiableEconomicMap;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.debug.CounterKey;
|
||||
import org.graalvm.compiler.debug.DebugCloseable;
|
||||
import org.graalvm.compiler.debug.DebugContext;
|
||||
@ -65,6 +69,13 @@ public class Graph {
|
||||
DeepFreeze
|
||||
}
|
||||
|
||||
public enum SourcePositionTracking {
|
||||
Default,
|
||||
Ignore,
|
||||
UpdateOnly,
|
||||
Track
|
||||
}
|
||||
|
||||
public final String name;
|
||||
|
||||
/**
|
||||
@ -80,7 +91,7 @@ public class Graph {
|
||||
/**
|
||||
* Records if updating of node source information is required when performing inlining.
|
||||
*/
|
||||
boolean seenNodeSourcePosition;
|
||||
protected SourcePositionTracking trackNodeSourcePosition;
|
||||
|
||||
/**
|
||||
* The number of valid entries in {@link #nodes}.
|
||||
@ -195,7 +206,7 @@ public class Graph {
|
||||
* was opened
|
||||
*/
|
||||
public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) {
|
||||
return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
|
||||
return trackNodeSourcePosition() && sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -212,16 +223,26 @@ public class Graph {
|
||||
* to short circuit logic for updating those positions after inlining since that requires
|
||||
* visiting every node in the graph.
|
||||
*/
|
||||
public boolean mayHaveNodeSourcePosition() {
|
||||
assert seenNodeSourcePosition || verifyHasNoSourcePosition();
|
||||
return seenNodeSourcePosition;
|
||||
public boolean updateNodeSourcePosition() {
|
||||
return trackNodeSourcePosition == Track || trackNodeSourcePosition == UpdateOnly;
|
||||
}
|
||||
|
||||
private boolean verifyHasNoSourcePosition() {
|
||||
for (Node node : getNodes()) {
|
||||
assert node.getNodeSourcePosition() == null;
|
||||
public boolean trackNodeSourcePosition() {
|
||||
return trackNodeSourcePosition == Track;
|
||||
}
|
||||
|
||||
public void setTrackNodeSourcePosition() {
|
||||
if (trackNodeSourcePosition != Track) {
|
||||
assert trackNodeSourcePosition == Default : trackNodeSourcePosition;
|
||||
trackNodeSourcePosition = Track;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static SourcePositionTracking trackNodeSourcePositionDefault(OptionValues options, DebugContext debug) {
|
||||
if (GraalOptions.TrackNodeSourcePosition.getValue(options) || debug.isDumpEnabledForMethod()) {
|
||||
return Track;
|
||||
}
|
||||
return Default;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,6 +276,7 @@ public class Graph {
|
||||
iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
|
||||
this.name = name;
|
||||
this.options = options;
|
||||
this.trackNodeSourcePosition = trackNodeSourcePositionDefault(options, debug);
|
||||
assert debug != null;
|
||||
this.debug = debug;
|
||||
|
||||
@ -358,6 +380,9 @@ public class Graph {
|
||||
*/
|
||||
protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) {
|
||||
Graph copy = new Graph(newName, options, debugForCopy);
|
||||
if (trackNodeSourcePosition()) {
|
||||
copy.setTrackNodeSourcePosition();
|
||||
}
|
||||
UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (EconomicMap<Node, Node>) null);
|
||||
if (duplicationMapCallback != null) {
|
||||
duplicationMapCallback.accept(duplicates);
|
||||
@ -1069,10 +1094,9 @@ public class Graph {
|
||||
int id = nodesSize++;
|
||||
nodes[id] = node;
|
||||
node.id = id;
|
||||
if (currentNodeSourcePosition != null) {
|
||||
if (currentNodeSourcePosition != null && trackNodeSourcePosition()) {
|
||||
node.setNodeSourcePosition(currentNodeSourcePosition);
|
||||
}
|
||||
seenNodeSourcePosition = seenNodeSourcePosition || node.getNodeSourcePosition() != null;
|
||||
|
||||
updateNodeCaches(node);
|
||||
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
|
||||
public class InlineCacheGuardPosition extends NodeSourcePosition {
|
||||
private final ResolvedJavaType dispatchedType;
|
||||
private final ResolvedJavaMethod concreteMethod;
|
||||
private final int hashCode;
|
||||
|
||||
public InlineCacheGuardPosition(NodeSourcePosition callStack, ResolvedJavaType dispatchedType, ResolvedJavaMethod targetMethod) {
|
||||
super(callStack.getCaller(), callStack.getMethod(), callStack.getBCI());
|
||||
this.concreteMethod = targetMethod;
|
||||
this.dispatchedType = dispatchedType;
|
||||
this.hashCode = super.hashCode() + 7 * ((dispatchedType == null) ? 0 : dispatchedType.hashCode()) + 31 * targetMethod.hashCode();
|
||||
}
|
||||
|
||||
public ResolvedJavaType getDispatchedType() {
|
||||
return dispatchedType;
|
||||
}
|
||||
|
||||
public ResolvedJavaMethod getTargetMethod() {
|
||||
return concreteMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && getClass() == obj.getClass()) {
|
||||
InlineCacheGuardPosition that = (InlineCacheGuardPosition) obj;
|
||||
if (hashCode != that.hashCode) {
|
||||
return false;
|
||||
}
|
||||
if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) &&
|
||||
Objects.equals(this.concreteMethod, that.concreteMethod) && Objects.equals(this.dispatchedType, that.dispatchedType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "dispatchedType=" + (dispatchedType == null ? "null" : dispatchedType.getName()) + " target_method=" + concreteMethod.getName() + " target_method_class=" +
|
||||
concreteMethod.getDeclaringClass().getName() + " position=" + super.toString();
|
||||
}
|
||||
}
|
@ -593,10 +593,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
|
||||
* Set the source position to {@code sourcePosition}.
|
||||
*/
|
||||
public void setNodeSourcePosition(NodeSourcePosition sourcePosition) {
|
||||
assert sourcePosition != null || this.sourcePosition == null || this.sourcePosition.isPlaceholder() : "Invalid source position at node with id " + id;
|
||||
this.sourcePosition = sourcePosition;
|
||||
if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) {
|
||||
graph.seenNodeSourcePosition = true;
|
||||
}
|
||||
// assert sourcePosition == null || graph == null || graph.trackNodeSourcePosition;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -920,6 +919,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
|
||||
}
|
||||
newNode.graph = into;
|
||||
newNode.id = INITIAL_ID;
|
||||
if (sourcePosition != null && (into == null || into.updateNodeSourcePosition())) {
|
||||
newNode.setNodeSourcePosition(sourcePosition);
|
||||
}
|
||||
if (into != null) {
|
||||
into.register(newNode);
|
||||
}
|
||||
@ -928,9 +930,6 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
|
||||
if (into != null && useIntoLeafNodeCache) {
|
||||
into.putNodeIntoCache(newNode);
|
||||
}
|
||||
if (graph != null && into != null && sourcePosition != null) {
|
||||
newNode.setNodeSourcePosition(sourcePosition);
|
||||
}
|
||||
newNode.afterClone(this);
|
||||
return newNode;
|
||||
}
|
||||
@ -1195,6 +1194,15 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
|
||||
return getNodeClass().dataEquals(this, other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this node is equal to the other node while ignoring differences in
|
||||
* {@linkplain Successor control-flow} edges.
|
||||
*
|
||||
*/
|
||||
public boolean dataFlowEquals(Node other) {
|
||||
return this == other || nodeClass == other.getNodeClass() && this.valueEquals(other) && nodeClass.equalInputs(this, other);
|
||||
}
|
||||
|
||||
public final void pushInputs(NodeStack stack) {
|
||||
getNodeClass().pushInputs(this, stack);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
|
||||
* Gets the {@link NodeClass} associated with a given {@link Class}.
|
||||
*/
|
||||
public static <T> NodeClass<T> create(Class<T> c) {
|
||||
assert get(c) == null;
|
||||
assert getUnchecked(c) == null;
|
||||
Class<? super T> superclass = c.getSuperclass();
|
||||
NodeClass<? super T> nodeSuperclass = null;
|
||||
if (superclass != NODE_CLASS) {
|
||||
@ -114,9 +114,9 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> NodeClass<T> get(Class<T> superclass) {
|
||||
private static <T> NodeClass<T> getUnchecked(Class<T> clazz) {
|
||||
try {
|
||||
Field field = superclass.getDeclaredField("TYPE");
|
||||
Field field = clazz.getDeclaredField("TYPE");
|
||||
field.setAccessible(true);
|
||||
return (NodeClass<T>) field.get(null);
|
||||
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
|
||||
@ -124,6 +124,14 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> NodeClass<T> get(Class<T> clazz) {
|
||||
NodeClass<T> result = getUnchecked(clazz);
|
||||
if (result == null && clazz != NODE_CLASS) {
|
||||
throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final Class<?> NODE_CLASS = Node.class;
|
||||
private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
|
||||
private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;
|
||||
|
@ -22,31 +22,100 @@
|
||||
*/
|
||||
package org.graalvm.compiler.graph;
|
||||
|
||||
import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.None;
|
||||
import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Placeholder;
|
||||
import static org.graalvm.compiler.graph.NodeSourcePosition.Marker.Substitution;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.graalvm.compiler.bytecode.BytecodeDisassembler;
|
||||
import org.graalvm.compiler.bytecode.Bytecodes;
|
||||
|
||||
import jdk.vm.ci.code.BytecodeFrame;
|
||||
import jdk.vm.ci.code.BytecodePosition;
|
||||
import jdk.vm.ci.code.CodeUtil;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaMethod;
|
||||
import jdk.vm.ci.meta.MetaUtil;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class NodeSourcePosition extends BytecodePosition {
|
||||
|
||||
/**
|
||||
* The receiver of the method this frame refers to.
|
||||
*/
|
||||
private final JavaConstant receiver;
|
||||
private final int hashCode;
|
||||
private static final boolean STRICT_SOURCE_POSITION = Boolean.getBoolean("debug.graal.SourcePositionStrictChecks");
|
||||
private static final boolean SOURCE_POSITION_BYTECODES = Boolean.getBoolean("debug.graal.SourcePositionDisassemble");
|
||||
|
||||
public NodeSourcePosition(JavaConstant receiver, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
|
||||
private final int hashCode;
|
||||
private final Marker marker;
|
||||
private final SourceLanguagePosition sourceLanguagePosition;
|
||||
|
||||
/**
|
||||
* Remove marker frames.
|
||||
*/
|
||||
public NodeSourcePosition trim() {
|
||||
if (marker != None) {
|
||||
return null;
|
||||
}
|
||||
NodeSourcePosition caller = getCaller();
|
||||
if (caller != null) {
|
||||
caller = caller.trim();
|
||||
}
|
||||
if (caller != getCaller()) {
|
||||
return new NodeSourcePosition(caller, getMethod(), getBCI());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
enum Marker {
|
||||
None,
|
||||
Placeholder,
|
||||
Substitution
|
||||
}
|
||||
|
||||
public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
|
||||
this(caller, method, bci, None);
|
||||
}
|
||||
|
||||
public NodeSourcePosition(NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) {
|
||||
this(null, caller, method, bci, marker);
|
||||
|
||||
}
|
||||
|
||||
public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
|
||||
this(sourceLanguagePosition, caller, method, bci, None);
|
||||
}
|
||||
|
||||
public NodeSourcePosition(SourceLanguagePosition sourceLanguagePosition, NodeSourcePosition caller, ResolvedJavaMethod method, int bci, Marker marker) {
|
||||
super(caller, method, bci);
|
||||
if (caller == null) {
|
||||
this.hashCode = 31 * bci + method.hashCode();
|
||||
} else {
|
||||
this.hashCode = caller.hashCode * 7 + 31 * bci + method.hashCode();
|
||||
}
|
||||
this.receiver = receiver;
|
||||
assert receiver == null || method.getDeclaringClass().isInstance(receiver);
|
||||
this.marker = marker;
|
||||
this.sourceLanguagePosition = sourceLanguagePosition;
|
||||
}
|
||||
|
||||
public static NodeSourcePosition placeholder(ResolvedJavaMethod method) {
|
||||
return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Placeholder);
|
||||
}
|
||||
|
||||
public static NodeSourcePosition placeholder(ResolvedJavaMethod method, int bci) {
|
||||
return new NodeSourcePosition(null, method, bci, Placeholder);
|
||||
}
|
||||
|
||||
public boolean isPlaceholder() {
|
||||
return marker == Placeholder;
|
||||
}
|
||||
|
||||
public static NodeSourcePosition substitution(ResolvedJavaMethod method) {
|
||||
return new NodeSourcePosition(null, method, BytecodeFrame.INVALID_FRAMESTATE_BCI, Substitution);
|
||||
}
|
||||
|
||||
public static NodeSourcePosition substitution(NodeSourcePosition caller, ResolvedJavaMethod method, int bci) {
|
||||
return new NodeSourcePosition(caller, method, bci, Substitution);
|
||||
}
|
||||
|
||||
public boolean isSubstitution() {
|
||||
return marker == Substitution;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -60,7 +129,7 @@ public class NodeSourcePosition extends BytecodePosition {
|
||||
return false;
|
||||
}
|
||||
if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) &&
|
||||
Objects.equals(this.receiver, that.receiver)) {
|
||||
Objects.equals(this.sourceLanguagePosition, that.sourceLanguagePosition)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -72,8 +141,18 @@ public class NodeSourcePosition extends BytecodePosition {
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public JavaConstant getReceiver() {
|
||||
return receiver;
|
||||
public int depth() {
|
||||
int d = 0;
|
||||
NodeSourcePosition pos = this;
|
||||
while (pos != null) {
|
||||
d++;
|
||||
pos = pos.getCaller();
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
public SourceLanguagePosition getSourceLanauage() {
|
||||
return sourceLanguagePosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,17 +160,29 @@ public class NodeSourcePosition extends BytecodePosition {
|
||||
return (NodeSourcePosition) super.getCaller();
|
||||
}
|
||||
|
||||
public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) {
|
||||
if (getCaller() == null) {
|
||||
assert newCallerReceiver == null || receiver == null : "replacing receiver";
|
||||
return new NodeSourcePosition(newCallerReceiver, link, getMethod(), getBCI());
|
||||
} else {
|
||||
return new NodeSourcePosition(receiver, getCaller().addCaller(newCallerReceiver, link), getMethod(), getBCI());
|
||||
}
|
||||
public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link) {
|
||||
return addCaller(newSourceLanguagePosition, link, false);
|
||||
}
|
||||
|
||||
public NodeSourcePosition addCaller(NodeSourcePosition link) {
|
||||
return addCaller(null, link);
|
||||
return addCaller(null, link, false);
|
||||
}
|
||||
|
||||
public NodeSourcePosition addCaller(NodeSourcePosition link, boolean isSubstitution) {
|
||||
return addCaller(null, link, isSubstitution);
|
||||
}
|
||||
|
||||
public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link, boolean isSubstitution) {
|
||||
if (getCaller() == null) {
|
||||
if (isPlaceholder()) {
|
||||
return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), 0);
|
||||
}
|
||||
assert link == null || isSubstitution || verifyCaller(this, link) : link;
|
||||
|
||||
return new NodeSourcePosition(newSourceLanguagePosition, link, getMethod(), getBCI());
|
||||
} else {
|
||||
return new NodeSourcePosition(getCaller().addCaller(newSourceLanguagePosition, link, isSubstitution), getMethod(), getBCI());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -99,9 +190,9 @@ public class NodeSourcePosition extends BytecodePosition {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
NodeSourcePosition pos = this;
|
||||
while (pos != null) {
|
||||
MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
|
||||
if (pos.receiver != null) {
|
||||
sb.append("receiver=" + pos.receiver + " ");
|
||||
format(sb, pos);
|
||||
if (pos.sourceLanguagePosition != null) {
|
||||
sb.append(" source=" + pos.sourceLanguagePosition.toShortString());
|
||||
}
|
||||
pos = pos.getCaller();
|
||||
if (pos != null) {
|
||||
@ -110,4 +201,55 @@ public class NodeSourcePosition extends BytecodePosition {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static void format(StringBuilder sb, NodeSourcePosition pos) {
|
||||
MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI());
|
||||
if (SOURCE_POSITION_BYTECODES) {
|
||||
String disassembly = BytecodeDisassembler.disassembleOne(pos.getMethod(), pos.getBCI());
|
||||
if (disassembly != null && disassembly.length() > 0) {
|
||||
sb.append(" // ");
|
||||
sb.append(disassembly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String shallowToString() {
|
||||
StringBuilder sb = new StringBuilder(100);
|
||||
format(sb, this);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public boolean verify() {
|
||||
NodeSourcePosition current = this;
|
||||
NodeSourcePosition caller = getCaller();
|
||||
while (caller != null) {
|
||||
assert verifyCaller(current, caller) : current;
|
||||
current = caller;
|
||||
caller = caller.getCaller();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean verifyCaller(NodeSourcePosition current, NodeSourcePosition caller) {
|
||||
if (!STRICT_SOURCE_POSITION) {
|
||||
return true;
|
||||
}
|
||||
if (BytecodeFrame.isPlaceholderBci(caller.getBCI())) {
|
||||
return true;
|
||||
}
|
||||
int opcode = BytecodeDisassembler.getBytecodeAt(caller.getMethod(), caller.getBCI());
|
||||
JavaMethod method = BytecodeDisassembler.getInvokedMethodAt(caller.getMethod(), caller.getBCI());
|
||||
/*
|
||||
* It's not really possible to match the declaring classes since this might be an interface
|
||||
* invoke. Matching name and signature probably provides enough accuracy.
|
||||
*/
|
||||
assert method == null || (method.getName().equals(current.getMethod().getName()) &&
|
||||
method.getSignature().equals(current.getMethod().getSignature())) ||
|
||||
caller.getMethod().getName().equals("linkToTargetMethod") ||
|
||||
opcode == Bytecodes.INVOKEDYNAMIC ||
|
||||
caller.getMethod().getDeclaringClass().getName().startsWith("Ljava/lang/invoke/LambdaForm$") ||
|
||||
current.getMethod().getName().equals("callInlined") : "expected " + method + " but found " +
|
||||
current.getMethod();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Provides a path to report information about a high level language source position to the Graph
|
||||
* Visualizer.
|
||||
*/
|
||||
public interface SourceLanguagePosition {
|
||||
|
||||
/**
|
||||
* This is called during dumping of Nodes. The implementation should add any properties which
|
||||
* describe this source position. The actual keys and values used are a private contract between
|
||||
* the language implementation and the Graph Visualizer.
|
||||
*/
|
||||
void addSourceInformation(Map<String, Object> props);
|
||||
|
||||
/**
|
||||
* Produce a compact description of this position suitable for printing.
|
||||
*/
|
||||
String toShortString();
|
||||
}
|
@ -20,20 +20,13 @@
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.core.common;
|
||||
package org.graalvm.compiler.graph;
|
||||
|
||||
public enum TraceInliningMode {
|
||||
None(false),
|
||||
Linear(true),
|
||||
Tree(true);
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
|
||||
private final boolean tracing;
|
||||
|
||||
TraceInliningMode(boolean tracing) {
|
||||
this.tracing = tracing;
|
||||
}
|
||||
|
||||
public boolean isTracing() {
|
||||
return tracing;
|
||||
}
|
||||
/**
|
||||
* Provider of {@link SourceLanguagePosition} for a constant if it represents an AST node.
|
||||
*/
|
||||
public interface SourceLanguagePositionProvider {
|
||||
SourceLanguagePosition getPosition(JavaConstant node);
|
||||
}
|
@ -288,33 +288,37 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend {
|
||||
}
|
||||
|
||||
private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
|
||||
/*
|
||||
* Insert a nop at the start of the prolog so we can patch in a branch if we need to
|
||||
* invalidate the method later.
|
||||
*/
|
||||
emitInvalidatePlaceholder(crb, masm);
|
||||
crb.emit(lir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a nop at the start of the prolog so we can patch in a branch if we need to invalidate
|
||||
* the method later.
|
||||
*
|
||||
* @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html"
|
||||
*/
|
||||
public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
crb.blockComment("[nop for method invalidation]");
|
||||
masm.nop();
|
||||
|
||||
crb.emit(lir);
|
||||
}
|
||||
|
||||
private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
|
||||
HotSpotProviders providers = getProviders();
|
||||
HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
|
||||
if (!frameContext.isStub) {
|
||||
HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
|
||||
try (ScratchRegister sc = masm.getScratchRegister()) {
|
||||
Register scratch = sc.getRegister();
|
||||
HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
|
||||
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
|
||||
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
|
||||
Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
|
||||
AArch64Call.directCall(crb, masm, linkage, helper, null);
|
||||
|
||||
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
|
||||
helper = AArch64Call.isNearCall(linkage) ? null : scratch;
|
||||
AArch64Call.directCall(crb, masm, linkage, helper, null);
|
||||
}
|
||||
crb.recordMark(config.MARKID_DEOPT_HANDLER_ENTRY);
|
||||
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(DEOPTIMIZATION_HANDLER);
|
||||
masm.adr(lr, 0); // Warning: the argument is an offset from the instruction!
|
||||
AArch64Call.directJmp(crb, masm, linkage);
|
||||
} else {
|
||||
// No need to emit the stubs for entries back into the method since
|
||||
// it has no calls that can cause such "return" entries
|
||||
|
@ -46,7 +46,9 @@ public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements Blo
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), null, info);
|
||||
try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
|
||||
AArch64Call.directCall(crb, masm, crb.foreignCalls.lookupForeignCall(UNCOMMON_TRAP_HANDLER), scratch.getRegister(), info, null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -155,22 +155,24 @@ public class AArch64HotSpotMove {
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
|
||||
Register ptr = asRegister(input);
|
||||
Register inputRegister = asRegister(input);
|
||||
Register resultRegister = asRegister(result);
|
||||
Register base = (isRegister(baseRegister) ? asRegister(baseRegister) : zr);
|
||||
Register base = encoding.hasBase() ? asRegister(baseRegister) : null;
|
||||
emitUncompressCode(masm, inputRegister, resultRegister, base, encoding.getShift(), nonNull);
|
||||
}
|
||||
|
||||
public static void emitUncompressCode(AArch64MacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) {
|
||||
// result = base + (ptr << shift)
|
||||
if (nonNull) {
|
||||
masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
|
||||
} else if (!encoding.hasBase()) {
|
||||
masm.add(64, resultRegister, zr, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
|
||||
if (nonNull || baseReg == null) {
|
||||
masm.add(64, resReg, baseReg == null ? zr : baseReg, inputRegister, AArch64Assembler.ShiftType.LSL, shift);
|
||||
} else {
|
||||
// if ptr is null it has to be null after decompression
|
||||
Label done = new Label();
|
||||
if (!resultRegister.equals(ptr)) {
|
||||
masm.mov(32, resultRegister, ptr);
|
||||
if (!resReg.equals(inputRegister)) {
|
||||
masm.mov(32, resReg, inputRegister);
|
||||
}
|
||||
masm.cbz(32, resultRegister, done);
|
||||
masm.add(64, resultRegister, base, resultRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift());
|
||||
masm.cbz(32, resReg, done);
|
||||
masm.add(64, resReg, baseReg, resReg, AArch64Assembler.ShiftType.LSL, shift);
|
||||
masm.bind(done);
|
||||
}
|
||||
}
|
||||
|
@ -65,6 +65,7 @@ import jdk.vm.ci.meta.AllocatableValue;
|
||||
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
|
||||
public class StubAVXTest extends LIRTest {
|
||||
|
||||
@ -72,6 +73,10 @@ public class StubAVXTest extends LIRTest {
|
||||
public void checkAMD64() {
|
||||
Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
|
||||
Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX));
|
||||
if (getBackend() instanceof HotSpotBackend) {
|
||||
HotSpotBackend backend = (HotSpotBackend) getBackend();
|
||||
Assume.assumeTrue("skipping because of MaxVectorSize", backend.getRuntime().getVMConfig().maxVectorSize >= 32);
|
||||
}
|
||||
}
|
||||
|
||||
private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32);
|
||||
|
@ -204,7 +204,7 @@ public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering {
|
||||
|
||||
if (init >= 0 && extremum >= 0) {
|
||||
long shortestTrip = (extremum - init) / stride + 1;
|
||||
if (shortestTrip == countedLoopInfo.constantMaxTripCount()) {
|
||||
if (countedLoopInfo.constantMaxTripCount().equals(shortestTrip)) {
|
||||
return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true));
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,13 @@ package org.graalvm.compiler.hotspot.amd64;
|
||||
import static jdk.vm.ci.amd64.AMD64.rbp;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
|
||||
import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
|
||||
import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -115,7 +115,7 @@ public class AMD64HotSpotLIRGenerator extends AMD64LIRGenerator implements HotSp
|
||||
}
|
||||
|
||||
private AMD64HotSpotLIRGenerator(HotSpotProviders providers, GraalHotSpotVMConfig config, LIRGenerationResult lirGenRes, BackupSlotProvider backupSlotProvider) {
|
||||
this(new AMD64HotSpotLIRKindTool(), new AMD64HotSpotArithmeticLIRGenerator(), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
|
||||
this(new AMD64HotSpotLIRKindTool(), new AMD64ArithmeticLIRGenerator(new AMD64HotSpotMaths()), new AMD64HotSpotMoveFactory(backupSlotProvider), providers, config, lirGenRes);
|
||||
}
|
||||
|
||||
protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,
|
||||
|
@ -31,49 +31,55 @@ import static org.graalvm.compiler.hotspot.amd64.AMD64HotSpotMathIntrinsicOp.Int
|
||||
|
||||
import org.graalvm.compiler.core.amd64.AMD64ArithmeticLIRGenerator;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend.Options;
|
||||
import org.graalvm.compiler.lir.Variable;
|
||||
import org.graalvm.compiler.lir.gen.LIRGenerator;
|
||||
|
||||
import jdk.vm.ci.meta.Value;
|
||||
|
||||
public class AMD64HotSpotArithmeticLIRGenerator extends AMD64ArithmeticLIRGenerator {
|
||||
/**
|
||||
* Lowering of selected {@link Math} routines that depends on the value of
|
||||
* {@link Options#GraalArithmeticStubs}.
|
||||
*/
|
||||
public class AMD64HotSpotMaths implements AMD64ArithmeticLIRGenerator.Maths {
|
||||
|
||||
@Override
|
||||
public Value emitMathLog(Value input, boolean base10) {
|
||||
if (GraalArithmeticStubs.getValue(getOptions())) {
|
||||
return super.emitMathLog(input, base10);
|
||||
public Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
|
||||
if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
|
||||
return null;
|
||||
}
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input)));
|
||||
Variable result = gen.newVariable(LIRKind.combine(input));
|
||||
gen.append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, gen.asAllocatable(input)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathCos(Value input) {
|
||||
if (GraalArithmeticStubs.getValue(getOptions())) {
|
||||
return super.emitMathCos(input);
|
||||
public Variable emitCos(LIRGenerator gen, Value input) {
|
||||
if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
|
||||
return null;
|
||||
}
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input)));
|
||||
Variable result = gen.newVariable(LIRKind.combine(input));
|
||||
gen.append(new AMD64HotSpotMathIntrinsicOp(COS, result, gen.asAllocatable(input)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathSin(Value input) {
|
||||
if (GraalArithmeticStubs.getValue(getOptions())) {
|
||||
return super.emitMathSin(input);
|
||||
public Variable emitSin(LIRGenerator gen, Value input) {
|
||||
if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
|
||||
return null;
|
||||
}
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input)));
|
||||
Variable result = gen.newVariable(LIRKind.combine(input));
|
||||
gen.append(new AMD64HotSpotMathIntrinsicOp(SIN, result, gen.asAllocatable(input)));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value emitMathTan(Value input) {
|
||||
if (GraalArithmeticStubs.getValue(getOptions())) {
|
||||
return super.emitMathTan(input);
|
||||
public Variable emitTan(LIRGenerator gen, Value input) {
|
||||
if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
|
||||
return null;
|
||||
}
|
||||
Variable result = getLIRGen().newVariable(LIRKind.combine(input));
|
||||
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input)));
|
||||
Variable result = gen.newVariable(LIRKind.combine(input));
|
||||
gen.append(new AMD64HotSpotMathIntrinsicOp(TAN, result, gen.asAllocatable(input)));
|
||||
return result;
|
||||
}
|
||||
|
@ -187,21 +187,26 @@ public class SPARCHotSpotMove {
|
||||
public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
|
||||
Register inputRegister = asRegister(input);
|
||||
Register resReg = asRegister(result);
|
||||
Register baseReg = encoding.hasBase() ? asRegister(baseRegister) : null;
|
||||
emitUncompressCode(masm, inputRegister, resReg, baseReg, encoding.getShift(), nonNull);
|
||||
}
|
||||
|
||||
public static void emitUncompressCode(SPARCMacroAssembler masm, Register inputRegister, Register resReg, Register baseReg, int shift, boolean nonNull) {
|
||||
Register secondaryInput;
|
||||
if (encoding.getShift() != 0) {
|
||||
masm.sll(inputRegister, encoding.getShift(), resReg);
|
||||
if (shift != 0) {
|
||||
masm.sll(inputRegister, shift, resReg);
|
||||
secondaryInput = resReg;
|
||||
} else {
|
||||
secondaryInput = inputRegister;
|
||||
}
|
||||
|
||||
if (encoding.hasBase()) {
|
||||
if (baseReg != null) {
|
||||
if (nonNull) {
|
||||
masm.add(secondaryInput, asRegister(baseRegister), resReg);
|
||||
masm.add(secondaryInput, baseReg, resReg);
|
||||
} else {
|
||||
Label done = new Label();
|
||||
BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done);
|
||||
masm.add(asRegister(baseRegister), secondaryInput, resReg);
|
||||
masm.add(baseReg, secondaryInput, resReg);
|
||||
masm.bind(done);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 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
|
||||
@ -553,6 +553,7 @@ public final class CompileTheWorld {
|
||||
classFileCounter++;
|
||||
|
||||
if (className.startsWith("jdk.management.") ||
|
||||
className.startsWith("jdk.internal.cmm.*") ||
|
||||
// GR-5881: The class initializer for
|
||||
// sun.tools.jconsole.OutputViewer
|
||||
// spawns non-daemon threads for redirecting sysout and syserr.
|
||||
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot.test;
|
||||
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.hotspot.meta.HotSpotClassInitializationPlugin;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
|
||||
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public class HotSpotLazyInitializationTest extends GraalCompilerTest {
|
||||
|
||||
HotSpotClassInitializationPlugin classInitPlugin = new HotSpotClassInitializationPlugin();
|
||||
|
||||
@Override
|
||||
protected Plugins getDefaultGraphBuilderPlugins() {
|
||||
Plugins plugins = super.getDefaultGraphBuilderPlugins();
|
||||
plugins.setClassInitializationPlugin(classInitPlugin);
|
||||
return plugins;
|
||||
}
|
||||
|
||||
static boolean initializerRun = false;
|
||||
|
||||
static class X {
|
||||
static {
|
||||
initializerRun = true;
|
||||
}
|
||||
|
||||
static void foo() {
|
||||
}
|
||||
}
|
||||
|
||||
public static void invokeStatic() {
|
||||
X.foo();
|
||||
}
|
||||
|
||||
// If constant pool can do eager resolve without eager initialization, then fail if the compiler
|
||||
// causes the static initializer to run.
|
||||
private void test(String name) {
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod(name);
|
||||
Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool()));
|
||||
parseEager(method, AllowAssumptions.NO);
|
||||
Assert.assertFalse(initializerRun);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
test("invokeStatic");
|
||||
}
|
||||
|
||||
}
|
@ -24,17 +24,25 @@ package org.graalvm.compiler.hotspot;
|
||||
|
||||
import static jdk.vm.ci.common.InitTimer.timer;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.graalvm.collections.EconomicMap;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.debug.TTY;
|
||||
import org.graalvm.compiler.lir.phases.LIRPhase;
|
||||
import org.graalvm.compiler.lir.phases.LIRPhaseSuite;
|
||||
import org.graalvm.compiler.options.EnumOptionKey;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
import org.graalvm.compiler.options.OptionKey;
|
||||
import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.BasePhase;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
|
||||
import org.graalvm.compiler.serviceprovider.GraalServices;
|
||||
|
||||
@ -48,12 +56,20 @@ import jdk.vm.ci.common.InitTimer;
|
||||
*/
|
||||
public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> {
|
||||
|
||||
enum ShowConfigurationLevel {
|
||||
none,
|
||||
info,
|
||||
verbose
|
||||
}
|
||||
|
||||
static class Options {
|
||||
// @formatter:off
|
||||
@Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " +
|
||||
"with the highest auto-selection priority is used. To see the set of available configurations, " +
|
||||
"supply the value 'help' to this option.", type = OptionType.Expert)
|
||||
public static final OptionKey<String> CompilerConfiguration = new OptionKey<>(null);
|
||||
@Option(help = "Writes to the VM log information about the Graal compiler configuration selected.", type = OptionType.User)
|
||||
public static final OptionKey<ShowConfigurationLevel> ShowConfiguration = new EnumOptionKey<>(ShowConfigurationLevel.none);
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@ -192,6 +208,52 @@ public abstract class CompilerConfigurationFactory implements Comparable<Compile
|
||||
factory = candidates.get(0);
|
||||
}
|
||||
}
|
||||
ShowConfigurationLevel level = Options.ShowConfiguration.getValue(options);
|
||||
if (level != ShowConfigurationLevel.none) {
|
||||
switch (level) {
|
||||
case info: {
|
||||
printConfigInfo(factory);
|
||||
break;
|
||||
}
|
||||
case verbose: {
|
||||
printConfigInfo(factory);
|
||||
CompilerConfiguration config = factory.createCompilerConfiguration();
|
||||
TTY.println("High tier: " + phaseNames(config.createHighTier(options)));
|
||||
TTY.println("Mid tier: " + phaseNames(config.createMidTier(options)));
|
||||
TTY.println("Low tier: " + phaseNames(config.createLowTier(options)));
|
||||
TTY.println("Pre regalloc stage: " + phaseNames(config.createPreAllocationOptimizationStage(options)));
|
||||
TTY.println("Regalloc stage: " + phaseNames(config.createAllocationStage(options)));
|
||||
TTY.println("Post regalloc stage: " + phaseNames(config.createPostAllocationOptimizationStage(options)));
|
||||
config.createAllocationStage(options);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
private static void printConfigInfo(CompilerConfigurationFactory factory) {
|
||||
URL location = factory.getClass().getResource(factory.getClass().getSimpleName() + ".class");
|
||||
TTY.printf("Using Graal compiler configuration '%s' provided by %s loaded from %s%n", factory.name, factory.getClass().getName(), location);
|
||||
}
|
||||
|
||||
private static <C> List<String> phaseNames(PhaseSuite<C> suite) {
|
||||
Collection<BasePhase<? super C>> phases = suite.getPhases();
|
||||
List<String> res = new ArrayList<>(phases.size());
|
||||
for (BasePhase<?> phase : phases) {
|
||||
res.add(phase.contractorName());
|
||||
}
|
||||
Collections.sort(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
private static <C> List<String> phaseNames(LIRPhaseSuite<C> suite) {
|
||||
List<LIRPhase<C>> phases = suite.getPhases();
|
||||
List<String> res = new ArrayList<>(phases.size());
|
||||
for (LIRPhase<?> phase : phases) {
|
||||
res.add(phase.getClass().getName());
|
||||
}
|
||||
Collections.sort(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
@ -45,8 +45,9 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
*/
|
||||
public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null;
|
||||
|
||||
// this uses `1.9` which will give the correct result with `1.9`, `9`, `10` etc.
|
||||
private final boolean isJDK8 = System.getProperty("java.specification.version").compareTo("1.9") < 0;
|
||||
private final int JDKVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version"));
|
||||
private final int jdkVersion = isJDK8 ? 8 : Integer.parseInt(System.getProperty("java.specification.version"));
|
||||
public final String osName = getHostOSName();
|
||||
public final String osArch = getHostArchitectureName();
|
||||
public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows");
|
||||
@ -160,6 +161,7 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
public final boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class);
|
||||
public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class);
|
||||
public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class);
|
||||
public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class);
|
||||
|
||||
public final boolean useTLAB = getFlag("UseTLAB", Boolean.class);
|
||||
public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class);
|
||||
@ -555,12 +557,10 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
|
||||
|
||||
public final int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int");
|
||||
|
||||
public final byte dirtyCardValue = JDKVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) :
|
||||
(JDKVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) :
|
||||
getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int"));
|
||||
public final byte g1YoungCardValue = JDKVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class) :
|
||||
(JDKVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) :
|
||||
getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int"));
|
||||
public final byte dirtyCardValue = jdkVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class)
|
||||
: (jdkVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int"));
|
||||
public final byte g1YoungCardValue = jdkVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class)
|
||||
: (jdkVersion > 8 ? getConstant("G1SATBCardTableModRefBS::g1_young_gen", Byte.class) : getFieldValue("CompilerToVM::Data::g1_young_card", Byte.class, "int"));
|
||||
|
||||
public final long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*");
|
||||
public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int");
|
||||
|
@ -91,7 +91,7 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
|
||||
public static class Options {
|
||||
// @formatter:off
|
||||
@Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible")
|
||||
public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(true);
|
||||
public static final OptionKey<Boolean> GraalArithmeticStubs = new OptionKey<>(false); // GR-8276
|
||||
@Option(help = "Enables instruction profiling on assembler level. Valid values are a comma separated list of supported instructions." +
|
||||
" Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
|
||||
public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null);
|
||||
|
@ -22,6 +22,8 @@
|
||||
*/
|
||||
package org.graalvm.compiler.hotspot;
|
||||
|
||||
import static org.graalvm.util.CollectionsUtil.anyMatch;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
@ -37,9 +39,9 @@ import org.graalvm.compiler.code.CompilationResult;
|
||||
import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
|
||||
import org.graalvm.compiler.code.CompilationResult.CodeComment;
|
||||
import org.graalvm.compiler.code.CompilationResult.JumpTable;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.code.DataSection;
|
||||
import org.graalvm.compiler.code.SourceMapping;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.graph.NodeSourcePosition;
|
||||
|
||||
import jdk.vm.ci.code.CodeCacheProvider;
|
||||
@ -55,7 +57,6 @@ import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
|
||||
import jdk.vm.ci.hotspot.HotSpotCompiledCode;
|
||||
import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
|
||||
import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
|
||||
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.Assumptions.Assumption;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
@ -210,16 +211,31 @@ public class HotSpotCompiledCodeBuilder {
|
||||
sites.addAll(target.getDataPatches());
|
||||
sites.addAll(target.getMarks());
|
||||
|
||||
/*
|
||||
* Translate the source mapping into appropriate info points. In HotSpot only one position
|
||||
* can really be represented and recording the end PC seems to give the best results and
|
||||
* corresponds with what C1 and C2 do.
|
||||
*/
|
||||
if (codeCache.shouldDebugNonSafepoints()) {
|
||||
/*
|
||||
* Translate the source mapping into appropriate info points. In HotSpot only one
|
||||
* position can really be represented and recording the end PC seems to give the best
|
||||
* results and corresponds with what C1 and C2 do. HotSpot doesn't like to see these
|
||||
* unless -XX:+DebugNonSafepoints is enabled, so don't emit them in that case.
|
||||
*/
|
||||
List<Site> sourcePositionSites = new ArrayList<>();
|
||||
for (SourceMapping source : target.getSourceMappings()) {
|
||||
sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION));
|
||||
assert verifySourcePositionReceivers(source.getSourcePosition());
|
||||
NodeSourcePosition sourcePosition = source.getSourcePosition();
|
||||
assert sourcePosition.verify();
|
||||
sourcePosition = sourcePosition.trim();
|
||||
/*
|
||||
* Don't add BYTECODE_POSITION info points that would potentially create conflicts.
|
||||
* Under certain conditions the site's pc is not the pc that gets recorded by
|
||||
* HotSpot (see @code {CodeInstaller::site_Call}). So, avoid adding any source
|
||||
* positions that can potentially map to the same pc. To do that make sure that the
|
||||
* source mapping doesn't contain a pc of any important Site.
|
||||
*/
|
||||
if (sourcePosition != null && !anyMatch(sites, s -> source.contains(s.pcOffset))) {
|
||||
sourcePositionSites.add(new Infopoint(source.getEndOffset(), new DebugInfo(sourcePosition), InfopointReason.BYTECODE_POSITION));
|
||||
|
||||
}
|
||||
}
|
||||
sites.addAll(sourcePositionSites);
|
||||
}
|
||||
|
||||
SiteComparator c = new SiteComparator();
|
||||
@ -245,18 +261,4 @@ public class HotSpotCompiledCodeBuilder {
|
||||
}
|
||||
return sites.toArray(new Site[sites.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the captured receiver type agrees with the declared type of the method.
|
||||
*/
|
||||
private static boolean verifySourcePositionReceivers(NodeSourcePosition start) {
|
||||
NodeSourcePosition pos = start;
|
||||
while (pos != null) {
|
||||
if (pos.getReceiver() != null) {
|
||||
assert ((HotSpotObjectConstant) pos.getReceiver()).asObject(pos.getMethod().getDeclaringClass()) != null;
|
||||
}
|
||||
pos = pos.getCaller();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -26,8 +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 java.util.Map;
|
||||
|
||||
import org.graalvm.compiler.debug.MethodFilter;
|
||||
import org.graalvm.compiler.options.Option;
|
||||
@ -36,6 +36,7 @@ import org.graalvm.compiler.options.OptionType;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.options.OptionsParser;
|
||||
import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
|
||||
import org.graalvm.compiler.serviceprovider.JDK9Method;
|
||||
|
||||
import jdk.vm.ci.common.InitTimer;
|
||||
import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
|
||||
@ -48,6 +49,22 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
private static MethodFilter[] graalCompileOnlyFilter;
|
||||
private static boolean compileGraalWithC1Only;
|
||||
|
||||
/**
|
||||
* Module containing {@link HotSpotJVMCICompilerFactory}.
|
||||
*/
|
||||
private Object jvmciModule;
|
||||
|
||||
/**
|
||||
* Module containing {@link HotSpotGraalCompilerFactory}.
|
||||
*/
|
||||
private Object graalModule;
|
||||
|
||||
/**
|
||||
* Module containing the {@linkplain CompilerConfigurationFactory#selectFactory selected}
|
||||
* configuration.
|
||||
*/
|
||||
private Object compilerConfigurationModule;
|
||||
|
||||
private final HotSpotGraalJVMCIServiceLocator locator;
|
||||
|
||||
HotSpotGraalCompilerFactory(HotSpotGraalJVMCIServiceLocator locator) {
|
||||
@ -70,6 +87,10 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
assert options == null : "cannot select " + getClass() + " service more than once";
|
||||
options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
|
||||
initializeGraalCompilePolicyFields(options);
|
||||
if (!JDK9Method.Java8OrEarlier) {
|
||||
jvmciModule = JDK9Method.getModule(HotSpotJVMCICompilerFactory.class);
|
||||
graalModule = JDK9Method.getModule(HotSpotGraalCompilerFactory.class);
|
||||
}
|
||||
/*
|
||||
* Exercise this code path early to encourage loading now. This doesn't solve problem of
|
||||
* deadlock during class loading but seems to eliminate it in practice.
|
||||
@ -102,7 +123,9 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
@Option(help = "In tiered mode compile Graal and JVMCI using optimized first tier code.", type = OptionType.Expert)
|
||||
public static final OptionKey<Boolean> CompileGraalWithC1Only = new OptionKey<>(true);
|
||||
|
||||
@Option(help = "A method filter selecting what should be compiled by Graal. All other requests will be reduced to CompilationLevel.Simple.", type = OptionType.Expert)
|
||||
@Option(help = "A filter applied to a method the VM has selected for compilation by Graal. " +
|
||||
"A method not matching the filter is redirected to a lower tier compiler. " +
|
||||
"The filter format is the same as for the MethodFilter option.", type = OptionType.Expert)
|
||||
public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
|
||||
// @formatter:on
|
||||
|
||||
@ -110,7 +133,11 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
|
||||
@Override
|
||||
public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) {
|
||||
HotSpotGraalCompiler compiler = createCompiler(runtime, options, CompilerConfigurationFactory.selectFactory(null, options));
|
||||
CompilerConfigurationFactory factory = CompilerConfigurationFactory.selectFactory(null, options);
|
||||
if (!JDK9Method.Java8OrEarlier) {
|
||||
compilerConfigurationModule = JDK9Method.getModule(factory.getClass());
|
||||
}
|
||||
HotSpotGraalCompiler compiler = createCompiler(runtime, options, factory);
|
||||
// Only the HotSpotGraalRuntime associated with the compiler created via
|
||||
// jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
|
||||
// VM events.
|
||||
@ -160,15 +187,54 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
|
||||
assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory");
|
||||
}
|
||||
|
||||
static final ClassLoader JVMCI_LOADER = HotSpotGraalCompilerFactory.class.getClassLoader();
|
||||
|
||||
/*
|
||||
* This method is static so it can be exercised during initialization.
|
||||
*/
|
||||
private static CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
|
||||
private CompilationLevel adjustCompilationLevelInternal(Class<?> declaringClass, String name, String signature, CompilationLevel level) {
|
||||
if (compileGraalWithC1Only) {
|
||||
if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
|
||||
String declaringClassName = declaringClass.getName();
|
||||
if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) {
|
||||
return CompilationLevel.Simple;
|
||||
if (JDK9Method.Java8OrEarlier) {
|
||||
if (JVMCI_LOADER != null) {
|
||||
// When running with +UseJVMCIClassLoader all classes in
|
||||
// the JVMCI loader should be compiled with C1.
|
||||
try {
|
||||
if (declaringClass.getClassLoader() == JVMCI_LOADER) {
|
||||
return CompilationLevel.Simple;
|
||||
}
|
||||
} catch (SecurityException e) {
|
||||
// This is definitely not a JVMCI or Graal class
|
||||
}
|
||||
} else {
|
||||
// JVMCI and Graal are on the bootclasspath so match based on the package.
|
||||
String declaringClassName = declaringClass.getName();
|
||||
if (declaringClassName.startsWith("jdk.vm.ci")) {
|
||||
return CompilationLevel.Simple;
|
||||
}
|
||||
if (declaringClassName.startsWith("org.graalvm.") &&
|
||||
(declaringClassName.startsWith("org.graalvm.compiler.") ||
|
||||
declaringClassName.startsWith("org.graalvm.collections.") ||
|
||||
declaringClassName.startsWith("org.graalvm.compiler.word.") ||
|
||||
declaringClassName.startsWith("org.graalvm.graphio."))) {
|
||||
return CompilationLevel.Simple;
|
||||
}
|
||||
if (declaringClassName.startsWith("com.oracle.graal") &&
|
||||
(declaringClassName.startsWith("com.oracle.graal.enterprise") ||
|
||||
declaringClassName.startsWith("com.oracle.graal.vector") ||
|
||||
declaringClassName.startsWith("com.oracle.graal.asm"))) {
|
||||
return CompilationLevel.Simple;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Object module = JDK9Method.getModule(declaringClass);
|
||||
if (jvmciModule == module || graalModule == module || compilerConfigurationModule == module) {
|
||||
return CompilationLevel.Simple;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
@ -114,14 +113,9 @@ public class NodeCostDumpUtil {
|
||||
}
|
||||
System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
|
||||
List<NodeClass<?>> nc = new ArrayList<>();
|
||||
for (Class<?> nodeClass : nodeClasses) {
|
||||
Field f;
|
||||
for (Class<?> c : nodeClasses) {
|
||||
try {
|
||||
f = nodeClass.getField("TYPE");
|
||||
f.setAccessible(true);
|
||||
Object val = f.get(null);
|
||||
NodeClass<?> nodeType = (NodeClass<?>) val;
|
||||
nc.add(nodeType);
|
||||
nc.add(NodeClass.get(c));
|
||||
} catch (Throwable t) {
|
||||
// Silently ignore problems here
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* 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.lir;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
|
||||
import org.graalvm.compiler.lir.LIR;
|
||||
import org.graalvm.compiler.lir.LIRInstruction;
|
||||
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
|
||||
import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
|
||||
|
||||
import jdk.vm.ci.code.TargetDescription;
|
||||
import static jdk.vm.ci.code.ValueUtil.isRegister;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
|
||||
import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
|
||||
|
||||
/**
|
||||
* Checks that no registers exceed the MaxVectorSize flag from the VM config.
|
||||
*/
|
||||
public final class VerifyMaxRegisterSizePhase extends PostAllocationOptimizationPhase {
|
||||
|
||||
private final int maxVectorSize;
|
||||
|
||||
public VerifyMaxRegisterSizePhase(int maxVectorSize) {
|
||||
this.maxVectorSize = maxVectorSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, PostAllocationOptimizationContext context) {
|
||||
LIR lir = lirGenRes.getLIR();
|
||||
for (AbstractBlockBase<?> block : lir.getControlFlowGraph().getBlocks()) {
|
||||
verifyBlock(lir, block);
|
||||
}
|
||||
}
|
||||
|
||||
protected void verifyBlock(LIR lir, AbstractBlockBase<?> block) {
|
||||
for (LIRInstruction inst : lir.getLIRforBlock(block)) {
|
||||
verifyInstruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
protected void verifyInstruction(LIRInstruction inst) {
|
||||
inst.visitEachInput(this::verifyOperands);
|
||||
inst.visitEachOutput(this::verifyOperands);
|
||||
inst.visitEachAlive(this::verifyOperands);
|
||||
inst.visitEachTemp(this::verifyOperands);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected void verifyOperands(LIRInstruction instruction, Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
|
||||
if (isRegister(value)) {
|
||||
assert value.getPlatformKind().getSizeInBytes() <= maxVectorSize : "value " + value + " exceeds MaxVectorSize " + maxVectorSize;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ package org.graalvm.compiler.hotspot.meta;
|
||||
import org.graalvm.compiler.core.common.type.ObjectStamp;
|
||||
import org.graalvm.compiler.core.common.type.Stamp;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
@ -37,6 +38,11 @@ import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
|
||||
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
import jdk.vm.ci.meta.ConstantPool;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin {
|
||||
@Override
|
||||
@ -73,4 +79,47 @@ public final class HotSpotClassInitializationPlugin implements ClassInitializati
|
||||
result.setStateBefore(frameState);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final Class<? extends ConstantPool> hscp;
|
||||
private static final MethodHandle loadReferencedTypeIIZMH;
|
||||
|
||||
static {
|
||||
MethodHandle m = null;
|
||||
Class<? extends ConstantPool> c = null;
|
||||
try {
|
||||
c = Class.forName("jdk.vm.ci.hotspot.HotSpotConstantPool").asSubclass(ConstantPool.class);
|
||||
m = MethodHandles.lookup().findVirtual(c, "loadReferencedType", MethodType.methodType(void.class, int.class, int.class, boolean.class));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
loadReferencedTypeIIZMH = m;
|
||||
hscp = c;
|
||||
}
|
||||
|
||||
private static boolean isHotSpotConstantPool(ConstantPool cp) {
|
||||
// jdk.vm.ci.hotspot.HotSpotConstantPool is final, so we can
|
||||
// directly compare Classes.
|
||||
return cp.getClass() == hscp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLazyInitialization(ConstantPool cp) {
|
||||
if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadReferencedType(GraphBuilderContext builder, ConstantPool cp, int cpi, int opcode) {
|
||||
if (loadReferencedTypeIIZMH != null && isHotSpotConstantPool(cp)) {
|
||||
try {
|
||||
loadReferencedTypeIIZMH.invoke(cp, cpi, opcode, false);
|
||||
} catch (Throwable t) {
|
||||
throw GraalError.shouldNotReachHere(t);
|
||||
}
|
||||
} else {
|
||||
cp.loadReferencedType(cpi, opcode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ public class HotSpotGraphBuilderPlugins {
|
||||
b.addPush(JavaKind.Object, object);
|
||||
} else {
|
||||
FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
|
||||
b.addPush(JavaKind.Object, new DynamicPiNode(object, fixedGuard, javaClass));
|
||||
b.addPush(JavaKind.Object, DynamicPiNode.create(b.getAssumptions(), b.getConstantReflection(), object, fixedGuard, javaClass));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot.meta;
|
||||
|
||||
import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Set;
|
||||
|
||||
@ -129,7 +130,7 @@ final class HotSpotInvocationPlugins extends InvocationPlugins {
|
||||
ClassLoader cl = javaClass.getClassLoader();
|
||||
return cl == null || cl == getClass().getClassLoader() || cl == extLoader;
|
||||
} else {
|
||||
Object module = JDK9Method.getModule.invoke(javaClass);
|
||||
Object module = JDK9Method.getModule(javaClass);
|
||||
return trustedModules.contains(module);
|
||||
}
|
||||
}
|
||||
@ -148,34 +149,43 @@ final class HotSpotInvocationPlugins extends InvocationPlugins {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of modules whose methods can be intrinsified. This set is the module owning the
|
||||
* class of {@code compilerConfiguration} and all its dependencies.
|
||||
*/
|
||||
private static EconomicSet<Object> initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError {
|
||||
try {
|
||||
EconomicSet<Object> res = EconomicSet.create();
|
||||
Object compilerConfigurationModule = JDK9Method.getModule.invoke(compilerConfiguration.getClass());
|
||||
Object compilerConfigurationModule = JDK9Method.getModule(compilerConfiguration.getClass());
|
||||
res.add(compilerConfigurationModule);
|
||||
Class<?> moduleClass = compilerConfigurationModule.getClass();
|
||||
Object layer = new JDK9Method(moduleClass, "getLayer").invoke(compilerConfigurationModule);
|
||||
Object layer = JDK9Method.lookupMethodHandle(moduleClass, "getLayer").invoke(compilerConfigurationModule);
|
||||
Class<? extends Object> layerClass = layer.getClass();
|
||||
JDK9Method getName = new JDK9Method(moduleClass, "getName");
|
||||
Set<Object> modules = new JDK9Method(layerClass, "modules").invoke(layer);
|
||||
Object descriptor = new JDK9Method(moduleClass, "getDescriptor").invoke(compilerConfigurationModule);
|
||||
MethodHandle getName = JDK9Method.lookupMethodHandle(moduleClass, "getName");
|
||||
Set<Object> modules = (Set<Object>) JDK9Method.lookupMethodHandle(layerClass, "modules").invoke(layer);
|
||||
Object descriptor = JDK9Method.lookupMethodHandle(moduleClass, "getDescriptor").invoke(compilerConfigurationModule);
|
||||
Class<?> moduleDescriptorClass = descriptor.getClass();
|
||||
Set<Object> requires = new JDK9Method(moduleDescriptorClass, "requires").invoke(descriptor);
|
||||
JDK9Method requireNameGetter = null;
|
||||
Set<Object> requires = (Set<Object>) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "requires").invoke(descriptor);
|
||||
boolean isAutomatic = (Boolean) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "isAutomatic").invoke(descriptor);
|
||||
if (isAutomatic) {
|
||||
throw new IllegalArgumentException(String.format("The module '%s' defining the Graal compiler configuration class '%s' must not be an automatic module",
|
||||
getName.invoke(compilerConfigurationModule), compilerConfiguration.getClass().getName()));
|
||||
}
|
||||
MethodHandle requireNameGetter = null;
|
||||
for (Object require : requires) {
|
||||
if (requireNameGetter == null) {
|
||||
requireNameGetter = new JDK9Method(require.getClass(), "name");
|
||||
requireNameGetter = JDK9Method.lookupMethodHandle(require.getClass(), "name");
|
||||
}
|
||||
String name = requireNameGetter.invoke(require);
|
||||
String name = (String) requireNameGetter.invoke(require);
|
||||
for (Object module : modules) {
|
||||
String moduleName = getName.invoke(module);
|
||||
String moduleName = (String) getName.invoke(module);
|
||||
if (moduleName.equals(name)) {
|
||||
res.add(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
} catch (Exception e) {
|
||||
} catch (Throwable e) {
|
||||
throw new GraalError(e);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,11 +28,13 @@ import static org.graalvm.compiler.core.common.GraalOptions.VerifyPhases;
|
||||
import static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
|
||||
|
||||
import java.util.ListIterator;
|
||||
import org.graalvm.compiler.debug.Assertions;
|
||||
|
||||
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
|
||||
import org.graalvm.compiler.hotspot.HotSpotBackend;
|
||||
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
|
||||
import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling;
|
||||
import org.graalvm.compiler.hotspot.lir.VerifyMaxRegisterSizePhase;
|
||||
import org.graalvm.compiler.hotspot.phases.AheadOfTimeVerificationPhase;
|
||||
import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
|
||||
import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase;
|
||||
@ -139,6 +141,10 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
|
||||
StructuredGraph targetGraph = new StructuredGraph.Builder(graph.getOptions(), graph.getDebug(), AllowAssumptions.YES).method(graph.method()).build();
|
||||
SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
|
||||
context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
|
||||
|
||||
if (graph.trackNodeSourcePosition()) {
|
||||
targetGraph.setTrackNodeSourcePosition();
|
||||
}
|
||||
graphDecoder.decode(encodedGraph);
|
||||
}
|
||||
|
||||
@ -171,6 +177,9 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
|
||||
if (profileInstructions != null) {
|
||||
suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
|
||||
}
|
||||
if (Assertions.detailedAssertionsEnabled(options)) {
|
||||
suites.getPostAllocationOptimizationStage().appendPhase(new VerifyMaxRegisterSizePhase(config.maxVectorSize));
|
||||
}
|
||||
return suites;
|
||||
}
|
||||
}
|
||||
|
@ -76,17 +76,17 @@ public class AOTInliningPolicy extends GreedyInliningPolicy {
|
||||
|
||||
OptionValues options = info.graph().getOptions();
|
||||
if (InlineEverything.getValue(options)) {
|
||||
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
|
||||
InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isIntrinsic(replacements, info)) {
|
||||
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
|
||||
InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.shouldInline()) {
|
||||
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
|
||||
InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -94,18 +94,18 @@ public class AOTInliningPolicy extends GreedyInliningPolicy {
|
||||
int nodes = info.determineNodeCount();
|
||||
|
||||
if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) {
|
||||
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
|
||||
InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "trivial (relevance=%f, probability=%f, bonus=%f, nodes=%d)", relevance, probability, inliningBonus, nodes);
|
||||
return true;
|
||||
}
|
||||
|
||||
double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus));
|
||||
if (nodes <= maximumNodes) {
|
||||
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
|
||||
InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d <= %f)", relevance, probability, inliningBonus,
|
||||
nodes, maximumNodes);
|
||||
return true;
|
||||
}
|
||||
|
||||
InliningUtil.logNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
|
||||
InliningUtil.traceNotInlinedMethod(info, inliningDepth, "relevance-based (relevance=%f, probability=%f, bonus=%f, nodes=%d > %f)", relevance, probability, inliningBonus, nodes, maximumNodes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ public class AssertionSnippets implements Snippets {
|
||||
args.add("condition", assertionNode.condition());
|
||||
args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")");
|
||||
|
||||
template(assertionNode.getDebug(), args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
|
||||
template(assertionNode, args).instantiate(providers.getMetaAccess(), assertionNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class HashCodeSnippets implements Snippets {
|
||||
StructuredGraph graph = node.graph();
|
||||
Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("thisObj", node.object);
|
||||
SnippetTemplate template = template(node.getDebug(), args);
|
||||
SnippetTemplate template = template(node, args);
|
||||
template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,7 @@ public class LoadExceptionObjectSnippets implements Snippets {
|
||||
} else {
|
||||
Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage());
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
template(loadExceptionObject.getDebug(), args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
|
||||
template(loadExceptionObject, args).instantiate(providers.getMetaAccess(), loadExceptionObject, DEFAULT_REPLACER, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -759,7 +759,7 @@ public class MonitorSnippets implements Snippets {
|
||||
args.addConst("counters", counters);
|
||||
}
|
||||
|
||||
template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
|
||||
template(monitorenterNode, args).instantiate(providers.getMetaAccess(), monitorenterNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(MonitorExitNode monitorexitNode, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -778,7 +778,7 @@ public class MonitorSnippets implements Snippets {
|
||||
args.addConst("options", graph.getOptions());
|
||||
args.addConst("counters", counters);
|
||||
|
||||
template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
|
||||
template(monitorexitNode, args).instantiate(providers.getMetaAccess(), monitorexitNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public static boolean isTracingEnabledForType(ValueNode object) {
|
||||
@ -828,7 +828,7 @@ public class MonitorSnippets implements Snippets {
|
||||
invoke.setStateAfter(graph.start().stateAfter());
|
||||
graph.addAfterFixed(graph.start(), invoke);
|
||||
|
||||
StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null);
|
||||
StructuredGraph inlineeGraph = providers.getReplacements().getSnippet(initCounter.getMethod(), null, invoke.graph().trackNodeSourcePosition(), invoke.getNodeSourcePosition());
|
||||
InliningUtil.inline(invoke, inlineeGraph, false, null);
|
||||
|
||||
List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot();
|
||||
@ -846,7 +846,7 @@ public class MonitorSnippets implements Snippets {
|
||||
|
||||
Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.addConst("errMsg", msg);
|
||||
inlineeGraph = template(graph.getDebug(), args).copySpecializedGraph(graph.getDebug());
|
||||
inlineeGraph = template(invoke, args).copySpecializedGraph(graph.getDebug());
|
||||
InliningUtil.inline(invoke, inlineeGraph, false, null);
|
||||
}
|
||||
}
|
||||
|
@ -626,7 +626,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
args.addConst("options", localOptions);
|
||||
args.addConst("counters", counters);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(newInstanceNode, args);
|
||||
graph.getDebug().log("Lowering allocateInstance in %s: node=%s, template=%s, arguments=%s", graph, newInstanceNode, template, args);
|
||||
template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
@ -669,7 +669,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
args.addConst("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
|
||||
args.addConst("options", localOptions);
|
||||
args.addConst("counters", counters);
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(newArrayNode, args);
|
||||
graph.getDebug().log("Lowering allocateArray in %s: node=%s, template=%s, arguments=%s", graph, newArrayNode, template, args);
|
||||
template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
@ -686,7 +686,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
args.addConst("options", localOptions);
|
||||
args.addConst("counters", counters);
|
||||
|
||||
SnippetTemplate template = template(newInstanceNode.getDebug(), args);
|
||||
SnippetTemplate template = template(newInstanceNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
@ -715,7 +715,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
args.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
|
||||
args.addConst("options", localOptions);
|
||||
args.addConst("counters", counters);
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(newArrayNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
@ -739,7 +739,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
args.add("hub", hub);
|
||||
args.addConst("rank", rank);
|
||||
args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims);
|
||||
template(newmultiarrayNode.getDebug(), args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
|
||||
template(newmultiarrayNode, args).instantiate(providers.getMetaAccess(), newmultiarrayNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
private static int instanceSize(HotSpotResolvedObjectType type) {
|
||||
@ -753,7 +753,7 @@ public class NewObjectSnippets implements Snippets {
|
||||
Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
|
||||
SnippetTemplate template = template(verifyHeapNode.getDebug(), args);
|
||||
SnippetTemplate template = template(verifyHeapNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
|
||||
} else {
|
||||
GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);
|
||||
|
@ -86,7 +86,7 @@ public final class ObjectCloneNode extends BasicObjectCloneNode implements Virtu
|
||||
StructuredGraph snippetGraph = null;
|
||||
DebugContext debug = getDebug();
|
||||
try (DebugContext.Scope s = debug.scope("ArrayCloneSnippet", snippetMethod)) {
|
||||
snippetGraph = replacements.getSnippet(snippetMethod, null);
|
||||
snippetGraph = replacements.getSnippet(snippetMethod, null, graph().trackNodeSourcePosition(), this.getNodeSourcePosition());
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class StringToBytesSnippets implements Snippets {
|
||||
public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) {
|
||||
Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage());
|
||||
args.addConst("compilationTimeString", stringToBytesNode.getValue());
|
||||
SnippetTemplate template = template(stringToBytesNode.getDebug(), args);
|
||||
SnippetTemplate template = template(stringToBytesNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class UnsafeLoadSnippets implements Snippets {
|
||||
Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("object", load.object());
|
||||
args.add("offset", load.offset());
|
||||
template(load.getDebug(), args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args);
|
||||
template(load, args).instantiate(providers.getMetaAccess(), load, DEFAULT_REPLACER, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -434,7 +434,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.add("object", address.getBase());
|
||||
}
|
||||
args.addConst("counters", counters);
|
||||
template(writeBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
|
||||
template(writeBarrier, args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
|
||||
@ -442,7 +442,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.add("address", arrayRangeWriteBarrier.getAddress());
|
||||
args.add("length", arrayRangeWriteBarrier.getLength());
|
||||
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
||||
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(G1PreWriteBarrier writeBarrierPre, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -467,7 +467,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
args.addConst("trace", traceBarrier(writeBarrierPre.graph()));
|
||||
args.addConst("counters", counters);
|
||||
template(writeBarrierPre.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
|
||||
template(writeBarrierPre, args).instantiate(providers.getMetaAccess(), writeBarrierPre, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(G1ReferentFieldReadBarrier readBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -492,7 +492,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
args.addConst("trace", traceBarrier(readBarrier.graph()));
|
||||
args.addConst("counters", counters);
|
||||
template(readBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
|
||||
template(readBarrier, args).instantiate(providers.getMetaAccess(), readBarrier, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(G1PostWriteBarrier writeBarrierPost, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -522,7 +522,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
|
||||
args.addConst("counters", counters);
|
||||
template(graph.getDebug(), args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
|
||||
template(writeBarrierPost, args).instantiate(providers.getMetaAccess(), writeBarrierPost, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -531,7 +531,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.add("length", arrayRangeWriteBarrier.getLength());
|
||||
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
}
|
||||
|
||||
public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
|
||||
@ -540,7 +540,7 @@ public class WriteBarrierSnippets implements Snippets {
|
||||
args.add("length", arrayRangeWriteBarrier.getLength());
|
||||
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
|
||||
args.addConst("threadRegister", registers.getThreadRegister());
|
||||
template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
template(arrayRangeWriteBarrier, args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,10 +36,10 @@ import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassStubCall;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicStubCall;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
|
||||
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
|
||||
import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp;
|
||||
@ -141,7 +141,7 @@ public class ResolveConstantSnippets implements Snippets {
|
||||
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("constant", value);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(resolveConstantNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
|
||||
|
||||
assert resolveConstantNode.hasNoUsages();
|
||||
@ -180,7 +180,7 @@ public class ResolveConstantSnippets implements Snippets {
|
||||
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("constant", value);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(resolveConstantNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
|
||||
|
||||
assert resolveConstantNode.hasNoUsages();
|
||||
@ -200,7 +200,7 @@ public class ResolveConstantSnippets implements Snippets {
|
||||
Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("constant", value);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(initializeKlassNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args);
|
||||
assert initializeKlassNode.hasNoUsages();
|
||||
if (!initializeKlassNode.isDeleted()) {
|
||||
@ -218,7 +218,7 @@ public class ResolveConstantSnippets implements Snippets {
|
||||
Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage());
|
||||
args.add("method", method);
|
||||
args.add("klassHint", resolveMethodAndLoadCountersNode.getHub());
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(resolveMethodAndLoadCountersNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args);
|
||||
|
||||
assert resolveMethodAndLoadCountersNode.hasNoUsages();
|
||||
|
@ -524,7 +524,7 @@ public class ArrayCopySnippets implements Snippets {
|
||||
*/
|
||||
private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
|
||||
StructuredGraph graph = arraycopy.graph();
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(arraycopy, args);
|
||||
UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false);
|
||||
for (Node originalNode : replacements.getKeys()) {
|
||||
if (originalNode instanceof Invoke) {
|
||||
|
@ -150,7 +150,7 @@ public class ProbabilisticProfileSnippets implements Snippets {
|
||||
args.add("bci", bci);
|
||||
args.add("targetBci", targetBci);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(profileNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
|
||||
} else if (profileNode instanceof ProfileInvokeNode) {
|
||||
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
|
||||
@ -163,7 +163,7 @@ public class ProbabilisticProfileSnippets implements Snippets {
|
||||
args.add("stepLog", stepLog);
|
||||
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
|
||||
args.addConst("probLog", profileInvokeNode.getProbabilityLog());
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(profileNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
|
||||
} else {
|
||||
throw new GraalError("Unsupported profile node type: " + profileNode);
|
||||
|
@ -132,7 +132,7 @@ public class ProfileSnippets implements Snippets {
|
||||
args.add("bci", bci);
|
||||
args.add("targetBci", targetBci);
|
||||
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(profileNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
|
||||
} else if (profileNode instanceof ProfileInvokeNode) {
|
||||
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
|
||||
@ -142,7 +142,7 @@ public class ProfileSnippets implements Snippets {
|
||||
args.add("step", step);
|
||||
args.add("stepLog", stepLog);
|
||||
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
|
||||
SnippetTemplate template = template(graph.getDebug(), args);
|
||||
SnippetTemplate template = template(profileNode, args);
|
||||
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
|
||||
} else {
|
||||
throw new GraalError("Unsupported profile node type: " + profileNode);
|
||||
|
@ -34,8 +34,11 @@ import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
|
||||
import org.graalvm.compiler.core.common.type.Stamp;
|
||||
import org.graalvm.compiler.core.common.type.StampFactory;
|
||||
import org.graalvm.compiler.core.common.type.StampPair;
|
||||
import org.graalvm.compiler.debug.DebugCloseable;
|
||||
import org.graalvm.compiler.debug.DebugContext;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
import org.graalvm.compiler.debug.JavaMethodContext;
|
||||
import org.graalvm.compiler.graph.NodeSourcePosition;
|
||||
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
|
||||
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition;
|
||||
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl;
|
||||
@ -224,33 +227,37 @@ public class ForeignCallStub extends Stub {
|
||||
* %r15 on AMD64) and is only prepended if {@link #prependThread} is true.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("try")
|
||||
protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) {
|
||||
WordTypes wordTypes = providers.getWordTypes();
|
||||
Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
|
||||
boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn());
|
||||
StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build();
|
||||
graph.disableUnsafeAccessTracking();
|
||||
graph.setTrackNodeSourcePosition();
|
||||
try {
|
||||
ResolvedJavaMethod thisMethod = providers.getMetaAccess().lookupJavaMethod(ForeignCallStub.class.getDeclaredMethod("getGraph", DebugContext.class, CompilationIdentifier.class));
|
||||
try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.substitution(thisMethod))) {
|
||||
GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
|
||||
ParameterNode[] params = createParameters(kit, args);
|
||||
ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
|
||||
ValueNode result = createTargetCall(kit, params, thread);
|
||||
kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
|
||||
if (isObjectResult) {
|
||||
InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
|
||||
result = kit.createInvoke(StubUtil.class, "verifyObject", object);
|
||||
}
|
||||
kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
|
||||
debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph");
|
||||
|
||||
GraphKit kit = new GraphKit(graph, providers, wordTypes, providers.getGraphBuilderPlugins());
|
||||
ParameterNode[] params = createParameters(kit, args);
|
||||
kit.inlineInvokes();
|
||||
new RemoveValueProxyPhase().apply(graph);
|
||||
|
||||
ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false));
|
||||
ValueNode result = createTargetCall(kit, params, thread);
|
||||
kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph));
|
||||
if (isObjectResult) {
|
||||
InvokeNode object = kit.createInvoke(HotSpotReplacementsUtil.class, "getAndClearObjectResult", thread);
|
||||
result = kit.createInvoke(StubUtil.class, "verifyObject", object);
|
||||
debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw GraalError.shouldNotReachHere(e);
|
||||
}
|
||||
kit.append(new ReturnNode(linkage.getDescriptor().getResultType() == void.class ? null : result));
|
||||
|
||||
debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Initial stub graph");
|
||||
|
||||
kit.inlineInvokes();
|
||||
|
||||
new RemoveValueProxyPhase().apply(graph);
|
||||
|
||||
debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
|
@ -279,6 +279,7 @@ import org.graalvm.compiler.bytecode.Bytecodes;
|
||||
import org.graalvm.compiler.bytecode.Bytes;
|
||||
import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
|
||||
import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
|
||||
import org.graalvm.compiler.core.common.GraalOptions;
|
||||
import org.graalvm.compiler.core.common.PermanentBailoutException;
|
||||
import org.graalvm.compiler.core.common.calc.CanonicalCondition;
|
||||
import org.graalvm.compiler.core.common.calc.Condition;
|
||||
@ -678,6 +679,8 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
|
||||
private boolean finalBarrierRequired;
|
||||
private ValueNode originalReceiver;
|
||||
private final boolean eagerInitializing;
|
||||
private final boolean uninitializedIsError;
|
||||
|
||||
protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method,
|
||||
int entryBCI, IntrinsicContext intrinsicContext) {
|
||||
@ -701,6 +704,14 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
this.entryBCI = entryBCI;
|
||||
this.parent = parent;
|
||||
|
||||
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
|
||||
if (classInitializationPlugin != null && graphBuilderConfig.eagerResolving()) {
|
||||
uninitializedIsError = eagerInitializing = !classInitializationPlugin.supportsLazyInitialization(constantPool);
|
||||
} else {
|
||||
eagerInitializing = graphBuilderConfig.eagerResolving();
|
||||
uninitializedIsError = graphBuilderConfig.unresolvedIsError();
|
||||
}
|
||||
|
||||
assert code.getCode() != null : "method must contain bytecodes: " + method;
|
||||
|
||||
if (TraceBytecodeParserLevel.getValue(options) != 0) {
|
||||
@ -713,6 +724,11 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
lnt = code.getLineNumberTable();
|
||||
previousLineNumber = -1;
|
||||
}
|
||||
|
||||
assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || graph.trackNodeSourcePosition();
|
||||
if (graphBuilderConfig.trackNodeSourcePosition() || (parent != null && parent.graph.trackNodeSourcePosition())) {
|
||||
graph.setTrackNodeSourcePosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected GraphBuilderPhase.Instance getGraphBuilderInstance() {
|
||||
@ -807,26 +823,28 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
if (method.isSynchronized()) {
|
||||
finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI);
|
||||
try (DebugCloseable context = openNodeContext()) {
|
||||
if (method.isSynchronized()) {
|
||||
finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI);
|
||||
|
||||
// add a monitor enter to the start block
|
||||
methodSynchronizedObject = synchronizedObject(frameState, method);
|
||||
frameState.clearNonLiveLocals(startBlock, liveness, true);
|
||||
assert bci() == 0;
|
||||
genMonitorEnter(methodSynchronizedObject, bci());
|
||||
// add a monitor enter to the start block
|
||||
methodSynchronizedObject = synchronizedObject(frameState, method);
|
||||
frameState.clearNonLiveLocals(startBlock, liveness, true);
|
||||
assert bci() == 0;
|
||||
genMonitorEnter(methodSynchronizedObject, bci());
|
||||
}
|
||||
|
||||
ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
|
||||
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
|
||||
FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
|
||||
profilingPlugin.profileInvoke(this, method, stateBefore);
|
||||
}
|
||||
|
||||
finishPrepare(lastInstr, 0);
|
||||
|
||||
genInfoPointNode(InfopointReason.METHOD_START, null);
|
||||
}
|
||||
|
||||
ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
|
||||
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
|
||||
FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
|
||||
profilingPlugin.profileInvoke(this, method, stateBefore);
|
||||
}
|
||||
|
||||
finishPrepare(lastInstr, 0);
|
||||
|
||||
genInfoPointNode(InfopointReason.METHOD_START, null);
|
||||
|
||||
currentBlock = blockMap.getStartBlock();
|
||||
setEntryState(startBlock, frameState);
|
||||
if (startBlock.isLoopHeader) {
|
||||
@ -1338,6 +1356,8 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
|
||||
protected void genInvokeStatic(int cpi, int opcode) {
|
||||
JavaMethod target = lookupMethod(cpi, opcode);
|
||||
assert !uninitializedIsError ||
|
||||
(target instanceof ResolvedJavaMethod && ((ResolvedJavaMethod) target).getDeclaringClass().isInitialized()) : target;
|
||||
genInvokeStatic(target);
|
||||
}
|
||||
|
||||
@ -2017,6 +2037,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
|
||||
InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
|
||||
if (plugin != null) {
|
||||
@ -2041,11 +2062,13 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
|
||||
InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
|
||||
if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
|
||||
afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
|
||||
return true;
|
||||
} else {
|
||||
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
|
||||
try (DebugCloseable context = openNodeContext(targetMethod)) {
|
||||
if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
|
||||
afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
|
||||
return true;
|
||||
} else {
|
||||
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@ -2112,6 +2135,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
* Tries to inline {@code targetMethod} if it is an instance field accessor. This avoids the
|
||||
* overhead of creating and using a nested {@link BytecodeParser} object.
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) {
|
||||
byte[] bytecode = targetMethod.getCode();
|
||||
if (bytecode != null && bytecode.length == ACCESSOR_BYTECODE_LENGTH &&
|
||||
@ -2124,10 +2148,12 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
if (field instanceof ResolvedJavaField) {
|
||||
ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get();
|
||||
ResolvedJavaField resolvedField = (ResolvedJavaField) field;
|
||||
genGetField(resolvedField, receiver);
|
||||
notifyBeforeInline(targetMethod);
|
||||
printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
|
||||
notifyAfterInline(targetMethod);
|
||||
try (DebugCloseable context = openNodeContext(targetMethod, 1)) {
|
||||
genGetField(resolvedField, receiver);
|
||||
notifyBeforeInline(targetMethod);
|
||||
printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
|
||||
notifyAfterInline(targetMethod);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2562,6 +2588,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
|
||||
@Override
|
||||
public <T extends ValueNode> T append(T v) {
|
||||
assert !graph.trackNodeSourcePosition() || graph.currentNodeSourcePosition() != null || currentBlock == blockMap.getUnwindBlock() || currentBlock instanceof ExceptionDispatchBlock;
|
||||
if (v.graph() != null) {
|
||||
return v;
|
||||
}
|
||||
@ -2670,93 +2697,97 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
return createTarget(block, state, false, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
|
||||
assert block != null && state != null;
|
||||
assert !block.isExceptionEntry || state.stackSize() == 1;
|
||||
|
||||
if (getFirstInstruction(block) == null) {
|
||||
/*
|
||||
* This is the first time we see this block as a branch target. Create and return a
|
||||
* placeholder that later can be replaced with a MergeNode when we see this block again.
|
||||
*/
|
||||
FixedNode targetNode;
|
||||
if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
|
||||
setFirstInstruction(block, lastInstr);
|
||||
lastInstr = null;
|
||||
} else {
|
||||
setFirstInstruction(block, graph.add(new BeginNode()));
|
||||
}
|
||||
targetNode = getFirstInstruction(block);
|
||||
Target target = checkLoopExit(targetNode, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
|
||||
setEntryState(block, currentEntryState);
|
||||
currentEntryState.clearNonLiveLocals(block, liveness, true);
|
||||
try (DebugCloseable context = openNodeContext(state, block.startBci)) {
|
||||
if (getFirstInstruction(block) == null) {
|
||||
/*
|
||||
* This is the first time we see this block as a branch target. Create and return a
|
||||
* placeholder that later can be replaced with a MergeNode when we see this block
|
||||
* again.
|
||||
*/
|
||||
FixedNode targetNode;
|
||||
if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
|
||||
setFirstInstruction(block, lastInstr);
|
||||
lastInstr = null;
|
||||
} else {
|
||||
setFirstInstruction(block, graph.add(new BeginNode()));
|
||||
}
|
||||
targetNode = getFirstInstruction(block);
|
||||
Target target = checkLoopExit(targetNode, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state;
|
||||
setEntryState(block, currentEntryState);
|
||||
currentEntryState.clearNonLiveLocals(block, liveness, true);
|
||||
|
||||
debug.log("createTarget %s: first visit, result: %s", block, targetNode);
|
||||
return result;
|
||||
}
|
||||
|
||||
// We already saw this block before, so we have to merge states.
|
||||
if (!getEntryState(block).isCompatibleWith(state)) {
|
||||
throw bailout("stacks do not match; bytecodes would not verify");
|
||||
}
|
||||
|
||||
if (getFirstInstruction(block) instanceof LoopBeginNode) {
|
||||
assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
|
||||
/*
|
||||
* Backward loop edge. We need to create a special LoopEndNode and merge with the loop
|
||||
* begin node created before.
|
||||
*/
|
||||
LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
|
||||
LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
|
||||
Target target = checkLoopExit(loopEnd, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
getEntryState(block).merge(loopBegin, target.state);
|
||||
|
||||
debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
|
||||
return result;
|
||||
}
|
||||
assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
|
||||
assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
|
||||
|
||||
if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
|
||||
/*
|
||||
* This is the second time we see this block. Create the actual MergeNode and the End
|
||||
* Node for the already existing edge.
|
||||
*/
|
||||
AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
|
||||
|
||||
// The EndNode for the already existing edge.
|
||||
EndNode end = graph.add(new EndNode());
|
||||
// The MergeNode that replaces the placeholder.
|
||||
AbstractMergeNode mergeNode = graph.add(new MergeNode());
|
||||
FixedNode next = beginNode.next();
|
||||
|
||||
if (beginNode.predecessor() instanceof ControlSplitNode) {
|
||||
beginNode.setNext(end);
|
||||
} else {
|
||||
beginNode.replaceAtPredecessor(end);
|
||||
beginNode.safeDelete();
|
||||
debug.log("createTarget %s: first visit, result: %s", block, targetNode);
|
||||
return result;
|
||||
}
|
||||
|
||||
mergeNode.addForwardEnd(end);
|
||||
mergeNode.setNext(next);
|
||||
// We already saw this block before, so we have to merge states.
|
||||
if (!getEntryState(block).isCompatibleWith(state)) {
|
||||
throw bailout("stacks do not match; bytecodes would not verify");
|
||||
}
|
||||
|
||||
setFirstInstruction(block, mergeNode);
|
||||
if (getFirstInstruction(block) instanceof LoopBeginNode) {
|
||||
assert (block.isLoopHeader && currentBlock.getId() >= block.getId()) : "must be backward branch";
|
||||
/*
|
||||
* Backward loop edge. We need to create a special LoopEndNode and merge with the
|
||||
* loop begin node created before.
|
||||
*/
|
||||
LoopBeginNode loopBegin = (LoopBeginNode) getFirstInstruction(block);
|
||||
LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin));
|
||||
Target target = checkLoopExit(loopEnd, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
getEntryState(block).merge(loopBegin, target.state);
|
||||
|
||||
debug.log("createTarget %s: merging backward branch to loop header %s, result: %s", block, loopBegin, result);
|
||||
return result;
|
||||
}
|
||||
assert currentBlock == null || currentBlock.getId() < block.getId() : "must not be backward branch";
|
||||
assert getFirstInstruction(block).next() == null : "bytecodes already parsed for block";
|
||||
|
||||
if (getFirstInstruction(block) instanceof AbstractBeginNode && !(getFirstInstruction(block) instanceof AbstractMergeNode)) {
|
||||
/*
|
||||
* This is the second time we see this block. Create the actual MergeNode and the
|
||||
* End Node for the already existing edge.
|
||||
*/
|
||||
AbstractBeginNode beginNode = (AbstractBeginNode) getFirstInstruction(block);
|
||||
|
||||
// The EndNode for the already existing edge.
|
||||
EndNode end = graph.add(new EndNode());
|
||||
// The MergeNode that replaces the placeholder.
|
||||
AbstractMergeNode mergeNode = graph.add(new MergeNode());
|
||||
FixedNode next = beginNode.next();
|
||||
|
||||
if (beginNode.predecessor() instanceof ControlSplitNode) {
|
||||
beginNode.setNext(end);
|
||||
} else {
|
||||
beginNode.replaceAtPredecessor(end);
|
||||
beginNode.safeDelete();
|
||||
}
|
||||
|
||||
mergeNode.addForwardEnd(end);
|
||||
mergeNode.setNext(next);
|
||||
|
||||
setFirstInstruction(block, mergeNode);
|
||||
}
|
||||
|
||||
AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
|
||||
|
||||
// The EndNode for the newly merged edge.
|
||||
EndNode newEnd = graph.add(new EndNode());
|
||||
Target target = checkLoopExit(newEnd, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
getEntryState(block).merge(mergeNode, target.state);
|
||||
mergeNode.addForwardEnd(newEnd);
|
||||
|
||||
debug.log("createTarget %s: merging state, result: %s", block, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
AbstractMergeNode mergeNode = (AbstractMergeNode) getFirstInstruction(block);
|
||||
|
||||
// The EndNode for the newly merged edge.
|
||||
EndNode newEnd = graph.add(new EndNode());
|
||||
Target target = checkLoopExit(newEnd, block, state);
|
||||
FixedNode result = target.fixed;
|
||||
getEntryState(block).merge(mergeNode, target.state);
|
||||
mergeNode.addForwardEnd(newEnd);
|
||||
|
||||
debug.log("createTarget %s: merging state, result: %s", block, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2965,28 +2996,28 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
|
||||
while (bci < endBCI) {
|
||||
if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
|
||||
currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
|
||||
if (currentLineNumber != previousLineNumber) {
|
||||
genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
|
||||
previousLineNumber = currentLineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
// read the opcode
|
||||
int opcode = stream.currentBC();
|
||||
assert traceState();
|
||||
assert traceInstruction(bci, opcode, bci == block.startBci);
|
||||
if (parent == null && bci == entryBCI) {
|
||||
if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
|
||||
throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
|
||||
}
|
||||
EntryMarkerNode x = append(new EntryMarkerNode());
|
||||
frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
|
||||
x.setStateAfter(createFrameState(bci, x));
|
||||
}
|
||||
|
||||
try (DebugCloseable context = openNodeContext()) {
|
||||
if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
|
||||
currentLineNumber = lnt != null ? lnt.getLineNumber(bci) : -1;
|
||||
if (currentLineNumber != previousLineNumber) {
|
||||
genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
|
||||
previousLineNumber = currentLineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
// read the opcode
|
||||
int opcode = stream.currentBC();
|
||||
assert traceState();
|
||||
assert traceInstruction(bci, opcode, bci == block.startBci);
|
||||
if (parent == null && bci == entryBCI) {
|
||||
if (block.getJsrScope() != JsrScope.EMPTY_SCOPE) {
|
||||
throw new JsrNotSupportedBailout("OSR into a JSR scope is not supported");
|
||||
}
|
||||
EntryMarkerNode x = append(new EntryMarkerNode());
|
||||
frameState.insertProxies(value -> graph.unique(new EntryProxyNode(value, x)));
|
||||
x.setStateAfter(createFrameState(bci, x));
|
||||
}
|
||||
|
||||
processBytecode(bci, opcode);
|
||||
} catch (BailoutException e) {
|
||||
// Don't wrap bailouts as parser errors
|
||||
@ -3017,13 +3048,28 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
private DebugCloseable openNodeContext() {
|
||||
if ((graphBuilderConfig.trackNodeSourcePosition() || debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) {
|
||||
return graph.withNodeSourcePosition(createBytecodePosition());
|
||||
private DebugCloseable openNodeContext(FrameStateBuilder state, int startBci) {
|
||||
if (graph.trackNodeSourcePosition()) {
|
||||
return graph.withNodeSourcePosition(state.createBytecodePosition(startBci));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod) {
|
||||
return openNodeContext(targetMethod, -1);
|
||||
}
|
||||
|
||||
private DebugCloseable openNodeContext(ResolvedJavaMethod targetMethod, int bci) {
|
||||
if (graph.trackNodeSourcePosition()) {
|
||||
return graph.withNodeSourcePosition(new NodeSourcePosition(createBytecodePosition(), targetMethod, bci));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DebugCloseable openNodeContext() {
|
||||
return openNodeContext(frameState, bci());
|
||||
}
|
||||
|
||||
/* Also a hook for subclasses. */
|
||||
protected boolean forceLoopPhis() {
|
||||
return graph.isOSR();
|
||||
@ -3133,7 +3179,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
genIf(condition, trueSuccessor, falseSuccessor, probability);
|
||||
}
|
||||
|
||||
private double getProfileProbability(boolean negate) {
|
||||
protected double getProfileProbability(boolean negate) {
|
||||
double probability;
|
||||
if (profilingInfo == null) {
|
||||
probability = 0.5;
|
||||
@ -3433,7 +3479,8 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
|
||||
protected NodeSourcePosition createBytecodePosition() {
|
||||
return frameState.createBytecodePosition(bci());
|
||||
NodeSourcePosition bytecodePosition = frameState.createBytecodePosition(bci());
|
||||
return bytecodePosition;
|
||||
}
|
||||
|
||||
public void setCurrentFrameState(FrameStateBuilder frameState) {
|
||||
@ -3454,6 +3501,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
frameState.push(kind, value);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
public void loadLocalObject(int index) {
|
||||
ValueNode value = frameState.loadLocal(index, JavaKind.Object);
|
||||
|
||||
@ -3461,7 +3509,9 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
int nextBC = stream.readUByte(nextBCI);
|
||||
if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
|
||||
stream.next();
|
||||
genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
|
||||
try (DebugCloseable ignored = openNodeContext()) {
|
||||
genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
|
||||
}
|
||||
} else {
|
||||
frameState.push(JavaKind.Object, value);
|
||||
}
|
||||
@ -3689,6 +3739,17 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
genIf(x, cond, y);
|
||||
}
|
||||
|
||||
private static void initialize(ResolvedJavaType resolvedType) {
|
||||
/*
|
||||
* Since we're potentially triggering class initialization here, we need synchronization to
|
||||
* mitigate the potential for class initialization related deadlock being caused by the
|
||||
* compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
|
||||
*/
|
||||
synchronized (BytecodeParser.class) {
|
||||
resolvedType.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
protected JavaType lookupType(int cpi, int bytecode) {
|
||||
maybeEagerlyResolve(cpi, bytecode);
|
||||
JavaType result = constantPool.lookupType(cpi, bytecode);
|
||||
@ -3699,32 +3760,26 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
private JavaMethod lookupMethod(int cpi, int opcode) {
|
||||
maybeEagerlyResolve(cpi, opcode);
|
||||
JavaMethod result = constantPool.lookupMethod(cpi, opcode);
|
||||
/*
|
||||
* In general, one cannot assume that the declaring class being initialized is useful, since
|
||||
* the actual concrete receiver may be a different class (except for static calls). Also,
|
||||
* interfaces are initialized only under special circumstances, so that this assertion would
|
||||
* often fail for interface calls.
|
||||
*/
|
||||
assert !graphBuilderConfig.unresolvedIsError() ||
|
||||
(result instanceof ResolvedJavaMethod && (opcode != INVOKESTATIC || ((ResolvedJavaMethod) result).getDeclaringClass().isInitialized())) : result;
|
||||
assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : result;
|
||||
return result;
|
||||
}
|
||||
|
||||
protected JavaField lookupField(int cpi, int opcode) {
|
||||
maybeEagerlyResolve(cpi, opcode);
|
||||
JavaField result = constantPool.lookupField(cpi, method, opcode);
|
||||
|
||||
if (graphBuilderConfig.eagerResolving()) {
|
||||
assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
|
||||
assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
|
||||
if (parsingIntrinsic() || eagerInitializing) {
|
||||
if (result instanceof ResolvedJavaField) {
|
||||
ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
|
||||
if (!declaringClass.isInitialized()) {
|
||||
assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
|
||||
declaringClass.initialize();
|
||||
// Even with eager initialization, superinterfaces are not always initialized.
|
||||
// See StaticInterfaceFieldTest
|
||||
assert !eagerInitializing || declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass;
|
||||
initialize(declaringClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert !graphBuilderConfig.unresolvedIsError() || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
|
||||
assert !uninitializedIsError || (result instanceof ResolvedJavaField && ((ResolvedJavaField) result).getDeclaringClass().isInitialized()) : result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -3745,7 +3800,12 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
* the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
|
||||
*/
|
||||
synchronized (BytecodeParser.class) {
|
||||
constantPool.loadReferencedType(cpi, bytecode);
|
||||
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
|
||||
if (classInitializationPlugin != null) {
|
||||
classInitializationPlugin.loadReferencedType(this, constantPool, cpi, bytecode);
|
||||
} else {
|
||||
constantPool.loadReferencedType(cpi, bytecode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3872,11 +3932,16 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
|
||||
void genNewInstance(JavaType type) {
|
||||
if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) {
|
||||
if (!(type instanceof ResolvedJavaType)) {
|
||||
handleUnresolvedNewInstance(type);
|
||||
return;
|
||||
}
|
||||
ResolvedJavaType resolvedType = (ResolvedJavaType) type;
|
||||
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
|
||||
if (!resolvedType.isInitialized() && classInitializationPlugin == null) {
|
||||
handleUnresolvedNewInstance(type);
|
||||
return;
|
||||
}
|
||||
|
||||
ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
|
||||
if (skippedExceptionTypes != null) {
|
||||
@ -3888,7 +3953,6 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
|
||||
if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) {
|
||||
FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
|
||||
classInitializationPlugin.apply(this, resolvedType, stateBefore);
|
||||
@ -4078,7 +4142,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needsExplicitException() {
|
||||
protected boolean needsExplicitException() {
|
||||
BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode();
|
||||
if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) {
|
||||
return true;
|
||||
@ -4163,7 +4227,7 @@ public class BytecodeParser implements GraphBuilderContext {
|
||||
private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) {
|
||||
if (field instanceof ResolvedJavaField) {
|
||||
ResolvedJavaField resolvedField = (ResolvedJavaField) field;
|
||||
if (resolvedField.getDeclaringClass().isInitialized()) {
|
||||
if (resolvedField.getDeclaringClass().isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) {
|
||||
return resolvedField;
|
||||
}
|
||||
/*
|
||||
|
@ -58,7 +58,7 @@ public class BytecodeParserOptions {
|
||||
public static final OptionKey<Boolean> TraceParserPlugins = new OptionKey<>(false);
|
||||
|
||||
@Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
|
||||
public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(3);
|
||||
public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(10);
|
||||
|
||||
@Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
|
||||
public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);
|
||||
|
@ -32,7 +32,6 @@ import static org.graalvm.compiler.bytecode.Bytecodes.POP;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.POP2;
|
||||
import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
|
||||
import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
|
||||
import static org.graalvm.compiler.java.BytecodeParserOptions.HideSubstitutionStates;
|
||||
import static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -74,7 +73,6 @@ import org.graalvm.compiler.nodes.util.GraphUtil;
|
||||
|
||||
import jdk.vm.ci.code.BytecodeFrame;
|
||||
import jdk.vm.ci.meta.Assumptions;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
@ -112,8 +110,6 @@ public final class FrameStateBuilder implements SideEffectsState {
|
||||
*/
|
||||
private List<StateSplit> sideEffects;
|
||||
|
||||
private JavaConstant constantReceiver;
|
||||
|
||||
/**
|
||||
* Creates a new frame state builder for the given method and the given target graph.
|
||||
*
|
||||
@ -164,7 +160,6 @@ public final class FrameStateBuilder implements SideEffectsState {
|
||||
locals[javaIndex] = arguments[index];
|
||||
javaIndex = 1;
|
||||
index = 1;
|
||||
constantReceiver = locals[0].asJavaConstant();
|
||||
}
|
||||
Signature sig = getMethod().getSignature();
|
||||
int max = sig.getParameterCount(false);
|
||||
@ -310,7 +305,7 @@ public final class FrameStateBuilder implements SideEffectsState {
|
||||
|
||||
public FrameState create(int bci, StateSplit forStateSplit) {
|
||||
if (parser != null && parser.parsingIntrinsic()) {
|
||||
NodeSourcePosition sourcePosition = createBytecodePosition(bci, false);
|
||||
NodeSourcePosition sourcePosition = parser.getGraph().trackNodeSourcePosition() ? createBytecodePosition(bci) : null;
|
||||
return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition);
|
||||
}
|
||||
|
||||
@ -354,25 +349,14 @@ public final class FrameStateBuilder implements SideEffectsState {
|
||||
}
|
||||
|
||||
public NodeSourcePosition createBytecodePosition(int bci) {
|
||||
return createBytecodePosition(bci, HideSubstitutionStates.getValue(parser.graph.getOptions()));
|
||||
}
|
||||
|
||||
private NodeSourcePosition createBytecodePosition(int bci, boolean hideSubstitutionStates) {
|
||||
BytecodeParser parent = parser.getParent();
|
||||
if (hideSubstitutionStates) {
|
||||
if (parser.parsingIntrinsic()) {
|
||||
// Attribute to the method being replaced
|
||||
return new NodeSourcePosition(constantReceiver, parent.getFrameStateBuilder().createBytecodePosition(parent.bci()), parser.intrinsicContext.getOriginalMethod(), -1);
|
||||
}
|
||||
// Skip intrinsic frames
|
||||
parent = parser.getNonIntrinsicAncestor();
|
||||
}
|
||||
return create(constantReceiver, bci, parent, hideSubstitutionStates);
|
||||
NodeSourcePosition position = create(bci, parent);
|
||||
return position;
|
||||
}
|
||||
|
||||
private NodeSourcePosition create(JavaConstant receiver, int bci, BytecodeParser parent, boolean hideSubstitutionStates) {
|
||||
private NodeSourcePosition create(int bci, BytecodeParser parent) {
|
||||
if (outerSourcePosition == null && parent != null) {
|
||||
outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci(), hideSubstitutionStates);
|
||||
outerSourcePosition = parent.getFrameStateBuilder().createBytecodePosition(parent.bci());
|
||||
}
|
||||
if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
|
||||
return FrameState.toSourcePosition(outerFrameState);
|
||||
@ -380,7 +364,7 @@ public final class FrameStateBuilder implements SideEffectsState {
|
||||
if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
|
||||
throw shouldNotReachHere();
|
||||
}
|
||||
return new NodeSourcePosition(receiver, outerSourcePosition, code.getMethod(), bci);
|
||||
return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci);
|
||||
}
|
||||
|
||||
public FrameStateBuilder copy() {
|
||||
|
@ -22,25 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt;
|
||||
|
||||
import static java.lang.reflect.Modifier.isStatic;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.graalvm.compiler.core.test.GraalCompilerTest;
|
||||
import org.graalvm.compiler.nodes.ConstantNode;
|
||||
import org.graalvm.compiler.nodes.ParameterNode;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph;
|
||||
import org.graalvm.compiler.nodes.StructuredGraph.Builder;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.graalvm.compiler.phases.PhaseSuite;
|
||||
import org.graalvm.compiler.phases.tiers.HighTierContext;
|
||||
import org.junit.Assert;
|
||||
|
||||
import jdk.vm.ci.code.InstalledCode;
|
||||
import jdk.vm.ci.meta.DeoptimizationReason;
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.JavaType;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/**
|
||||
@ -66,45 +55,35 @@ public class JTTTest extends GraalCompilerTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StructuredGraph parse(Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) {
|
||||
StructuredGraph graph = super.parse(builder, graphBuilderSuite);
|
||||
if (argsToBind != null) {
|
||||
ResolvedJavaMethod m = graph.method();
|
||||
Object receiver = isStatic(m.getModifiers()) ? null : this;
|
||||
Object[] args = argsWithReceiver(receiver, argsToBind);
|
||||
JavaType[] parameterTypes = m.toParameterTypes();
|
||||
assert parameterTypes.length == args.length;
|
||||
for (ParameterNode param : graph.getNodes(ParameterNode.TYPE)) {
|
||||
JavaConstant c = getSnippetReflection().forBoxed(parameterTypes[param.index()].getJavaKind(), args[param.index()]);
|
||||
ConstantNode replacement = ConstantNode.forConstant(c, getMetaAccess(), graph);
|
||||
param.replaceAtUsages(replacement);
|
||||
}
|
||||
}
|
||||
return graph;
|
||||
protected Object[] getArgumentToBind() {
|
||||
return argsToBind;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) {
|
||||
return super.getCode(method, graph, argsToBind != null, installAsDefault, options);
|
||||
}
|
||||
|
||||
Double delta;
|
||||
/**
|
||||
* If non-null, then this is a test for a method returning a {@code double} value that must be
|
||||
* within {@code ulpDelta}s of the expected value.
|
||||
*/
|
||||
protected Double ulpDelta;
|
||||
|
||||
@Override
|
||||
protected void assertDeepEquals(Object expected, Object actual) {
|
||||
if (delta != null) {
|
||||
Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta);
|
||||
if (ulpDelta != null) {
|
||||
double expectedDouble = (double) expected;
|
||||
double actualDouble = (Double) actual;
|
||||
double ulp = Math.ulp(expectedDouble);
|
||||
double delta = ulpDelta * ulp;
|
||||
try {
|
||||
Assert.assertEquals(expectedDouble, actualDouble, delta);
|
||||
} catch (AssertionError e) {
|
||||
double diff = Math.abs(expectedDouble - actualDouble);
|
||||
double diffUlps = diff / ulp;
|
||||
throw new AssertionError(e.getMessage() + " // " + diffUlps + " ulps");
|
||||
}
|
||||
} else {
|
||||
super.assertDeepEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
protected void runTestWithDelta(double delta, String name, Object... args) {
|
||||
this.delta = Double.valueOf(delta);
|
||||
runTest(name, args);
|
||||
}
|
||||
|
||||
protected void runTest(String name, Object... args) {
|
||||
runTest(getInitialOptions(), name, args);
|
||||
}
|
||||
|
@ -24,10 +24,8 @@
|
||||
|
||||
package org.graalvm.compiler.jtt.hotpath;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import org.junit.Test;
|
||||
|
||||
/*
|
||||
*/
|
||||
@ -101,17 +99,16 @@ public class HP_series extends JTTTest {
|
||||
return (0.0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This test is sensible to the implementation of Math.pow, cos and sin. Since for these
|
||||
* functions, the specs says "The computed result must be within 1 ulp of the exact result",
|
||||
* different implementation may return different results. The 11 ulp delta allowed for test(100)
|
||||
* tries to account for that but is not guaranteed to work forever.
|
||||
/**
|
||||
* This test is sensitive to the implementation of {@link Math#pow}, {@link Math#cos} and
|
||||
* {@link Math#sin(double)}. Since for these functions, the specs says "The computed result must
|
||||
* be within 1 ulp of the exact result", different implementation may return different results.
|
||||
* The 11 ulp delta allowed for test(100) tries to account for that but is not guaranteed to
|
||||
* work forever.
|
||||
*/
|
||||
@Ignore("failure-prone because of the variabiliy of pow/cos/sin")
|
||||
@Test
|
||||
public void run0() throws Throwable {
|
||||
double expected = 0.6248571921291398d;
|
||||
runTestWithDelta(11 * Math.ulp(expected), "test", 100);
|
||||
ulpDelta = 11.0D;
|
||||
runTest("test", 100);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_abs extends JTTTest {
|
||||
public class Math_abs extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -78,4 +79,10 @@ public class Math_abs extends JTTTest {
|
||||
runTest("test", java.lang.Double.NaN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run7() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_cos extends JTTTest {
|
||||
public class Math_cos extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -58,4 +59,10 @@ public class Math_cos extends JTTTest {
|
||||
runTest("test", java.lang.Double.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run3() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -22,14 +22,12 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_exp extends JTTTest {
|
||||
public class Math_exp extends UnaryMath {
|
||||
|
||||
public static double test(double arg) {
|
||||
return Math.exp(arg);
|
||||
@ -65,9 +63,19 @@ public class Math_exp extends JTTTest {
|
||||
runTest("test", 0.0D);
|
||||
}
|
||||
|
||||
@Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>")
|
||||
@Test
|
||||
public void run6() {
|
||||
runTest("test", 1.0D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run7() {
|
||||
runTest("test", -1024D);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run8() {
|
||||
OptionValues options = getInitialOptions();
|
||||
testManyValues(options, getResolvedJavaMethod("test"));
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_log extends JTTTest {
|
||||
public class Math_log extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -78,4 +79,10 @@ public class Math_log extends JTTTest {
|
||||
runTest("test", -0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run7() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -22,9 +22,11 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
@ -88,4 +90,44 @@ public class Math_pow extends JTTTest {
|
||||
public void run10() throws Throwable {
|
||||
runTest("test", 0.999998, 1500000.0);
|
||||
}
|
||||
|
||||
private static final long STEP = Long.MAX_VALUE / 1_000_000;
|
||||
|
||||
@Test
|
||||
public void run11() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
Object receiver = null;
|
||||
long testIteration = 0;
|
||||
for (long l = Long.MIN_VALUE;; l += STEP) {
|
||||
double x = Double.longBitsToDouble(l);
|
||||
double y = x;
|
||||
testOne(options, method, receiver, testIteration, l, x, y);
|
||||
y = l < 0 ? Double.longBitsToDouble(Long.MAX_VALUE + l) : Double.longBitsToDouble(Long.MAX_VALUE - l);
|
||||
testOne(options, method, receiver, testIteration, l, x, y);
|
||||
if (Long.MAX_VALUE - STEP < l) {
|
||||
break;
|
||||
}
|
||||
testIteration++;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run12() {
|
||||
long l = 4355599093822972882L;
|
||||
double x = Double.longBitsToDouble(l);
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
Object receiver = null;
|
||||
testOne(options, method, receiver, 1, l, x, x);
|
||||
}
|
||||
|
||||
private void testOne(OptionValues options, ResolvedJavaMethod method, Object receiver, long testIteration, long l, double x, double y) throws AssertionError {
|
||||
Result expect = executeExpected(method, receiver, x, y);
|
||||
try {
|
||||
testAgainstExpected(options, method, expect, EMPTY, receiver, x, y);
|
||||
} catch (AssertionError e) {
|
||||
throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, x, l, l), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_sin extends JTTTest {
|
||||
public class Math_sin extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -83,4 +84,10 @@ public class Math_sin extends JTTTest {
|
||||
runTest("test", 0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run5() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_sqrt extends JTTTest {
|
||||
public class Math_sqrt extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -78,4 +79,10 @@ public class Math_sqrt extends JTTTest {
|
||||
runTest("test", -0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run7() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -22,13 +22,14 @@
|
||||
*/
|
||||
package org.graalvm.compiler.jtt.lang;
|
||||
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
/*
|
||||
*/
|
||||
public class Math_tan extends JTTTest {
|
||||
public class Math_tan extends UnaryMath {
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class NaN extends Throwable {
|
||||
@ -68,4 +69,10 @@ public class Math_tan extends JTTTest {
|
||||
runTest("test", 0.0d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void run5() {
|
||||
OptionValues options = getInitialOptions();
|
||||
ResolvedJavaMethod method = getResolvedJavaMethod("test");
|
||||
testManyValues(options, method);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, 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.lang;
|
||||
|
||||
import org.graalvm.compiler.jtt.JTTTest;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||
|
||||
public abstract class UnaryMath extends JTTTest {
|
||||
|
||||
private static final long STEP = Long.MAX_VALUE / 1_000_000;
|
||||
|
||||
/**
|
||||
* Tests a unary {@link Math} method on a wide range of values.
|
||||
*/
|
||||
void testManyValues(OptionValues options, ResolvedJavaMethod method) throws AssertionError {
|
||||
if (!Java8OrEarlier) {
|
||||
/*
|
||||
* GR-8276: Allow for variance on JVMCI > 8 until a JVMCI version that includes
|
||||
* https://github.com/graalvm/graal-jvmci-8/commit/
|
||||
* c86fb66f86b8d52a08dd2495d34879d3730f9987 or Graal has stubs that a monotonic with
|
||||
* other HotSpot implementations of these Math routines.
|
||||
*/
|
||||
ulpDelta = 2D;
|
||||
} else {
|
||||
/*
|
||||
* Forces the assertion message shows the ulps by which a computed result is wrong.
|
||||
*/
|
||||
ulpDelta = 0D;
|
||||
}
|
||||
Object receiver = null;
|
||||
long testIteration = 0;
|
||||
for (long l = Long.MIN_VALUE;; l += STEP) {
|
||||
double d = Double.longBitsToDouble(l);
|
||||
Result expect = executeExpected(method, receiver, d);
|
||||
try {
|
||||
testAgainstExpected(options, method, expect, EMPTY, receiver, d);
|
||||
testIteration++;
|
||||
} catch (AssertionError e) {
|
||||
throw new AssertionError(String.format("%d: While testing %g [long: %d, hex: %x]", testIteration, d, l, l), e);
|
||||
}
|
||||
if (Long.MAX_VALUE - STEP < l) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -227,13 +227,15 @@ public class AArch64Call {
|
||||
masm.ensureUniquePC();
|
||||
}
|
||||
|
||||
public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) {
|
||||
int before = masm.position();
|
||||
// Address is fixed up later by c++ code.
|
||||
masm.jmp();
|
||||
int after = masm.position();
|
||||
crb.recordDirectCall(before, after, target, null);
|
||||
masm.ensureUniquePC();
|
||||
public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) {
|
||||
try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
|
||||
int before = masm.position();
|
||||
masm.movNativeAddress(scratch.getRegister(), 0L);
|
||||
masm.jmp(scratch.getRegister());
|
||||
int after = masm.position();
|
||||
crb.recordDirectCall(before, after, callTarget, null);
|
||||
masm.ensureUniquePC();
|
||||
}
|
||||
}
|
||||
|
||||
public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) {
|
||||
|
@ -0,0 +1,595 @@
|
||||
/*
|
||||
* 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.lir.amd64;
|
||||
|
||||
import static jdk.vm.ci.amd64.AMD64.k7;
|
||||
import static jdk.vm.ci.amd64.AMD64.rax;
|
||||
import static jdk.vm.ci.amd64.AMD64.rcx;
|
||||
import static jdk.vm.ci.amd64.AMD64.rdx;
|
||||
import static jdk.vm.ci.code.ValueUtil.asRegister;
|
||||
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
|
||||
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.graalvm.compiler.asm.Label;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AvxVectorLen;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
import org.graalvm.compiler.lir.Opcode;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
|
||||
|
||||
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.TargetDescription;
|
||||
import jdk.vm.ci.meta.JavaKind;
|
||||
import jdk.vm.ci.meta.Value;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
/**
|
||||
* Emits code which compares two arrays lexicographically. If the CPU supports any vector
|
||||
* instructions specialized code is emitted to leverage these instructions.
|
||||
*/
|
||||
@Opcode("ARRAY_COMPARE_TO")
|
||||
public final class AMD64ArrayCompareToOp extends AMD64LIRInstruction {
|
||||
public static final LIRInstructionClass<AMD64ArrayCompareToOp> TYPE = LIRInstructionClass.create(AMD64ArrayCompareToOp.class);
|
||||
|
||||
private final JavaKind kind1;
|
||||
private final JavaKind kind2;
|
||||
private final int array1BaseOffset;
|
||||
private final int array2BaseOffset;
|
||||
|
||||
@Def({REG}) protected Value resultValue;
|
||||
@Alive({REG}) protected Value array1Value;
|
||||
@Alive({REG}) protected Value array2Value;
|
||||
@Alive({REG}) protected Value length1Value;
|
||||
@Alive({REG}) protected Value length2Value;
|
||||
@Temp({REG}) protected Value temp1;
|
||||
@Temp({REG}) protected Value temp2;
|
||||
|
||||
@Temp({REG, ILLEGAL}) protected Value vectorTemp1;
|
||||
|
||||
public AMD64ArrayCompareToOp(LIRGeneratorTool tool, JavaKind kind1, JavaKind kind2, Value result, Value array1, Value array2, Value length1, Value length2) {
|
||||
super(TYPE);
|
||||
this.kind1 = kind1;
|
||||
this.kind2 = kind2;
|
||||
|
||||
// Both offsets should be the same but better be safe than sorry.
|
||||
Class<?> array1Class = Array.newInstance(kind1.toJavaClass(), 0).getClass();
|
||||
Class<?> array2Class = Array.newInstance(kind2.toJavaClass(), 0).getClass();
|
||||
this.array1BaseOffset = UNSAFE.arrayBaseOffset(array1Class);
|
||||
this.array2BaseOffset = UNSAFE.arrayBaseOffset(array2Class);
|
||||
|
||||
this.resultValue = result;
|
||||
this.array1Value = array1;
|
||||
this.array2Value = array2;
|
||||
this.length1Value = length1;
|
||||
this.length2Value = length2;
|
||||
|
||||
// Allocate some temporaries.
|
||||
this.temp1 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
|
||||
this.temp2 = tool.newVariable(LIRKind.unknownReference(tool.target().arch.getWordKind()));
|
||||
|
||||
// We only need the vector temporaries if we generate SSE code.
|
||||
if (supportsSSE42(tool.target())) {
|
||||
this.vectorTemp1 = tool.newVariable(LIRKind.value(AMD64Kind.DOUBLE));
|
||||
} else {
|
||||
this.vectorTemp1 = Value.ILLEGAL;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean supportsSSE42(TargetDescription target) {
|
||||
AMD64 arch = (AMD64) target.arch;
|
||||
return arch.getFeatures().contains(CPUFeature.SSE4_2);
|
||||
}
|
||||
|
||||
private static boolean supportsAVX2(TargetDescription target) {
|
||||
AMD64 arch = (AMD64) target.arch;
|
||||
return arch.getFeatures().contains(CPUFeature.AVX2);
|
||||
}
|
||||
|
||||
private static boolean supportsAVX512VLBW(TargetDescription target) {
|
||||
AMD64 arch = (AMD64) target.arch;
|
||||
EnumSet<CPUFeature> features = arch.getFeatures();
|
||||
return features.contains(CPUFeature.AVX512BW) && features.contains(CPUFeature.AVX512VL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
|
||||
Register result = asRegister(resultValue);
|
||||
Register str1 = asRegister(temp1);
|
||||
Register str2 = asRegister(temp2);
|
||||
|
||||
// Load array base addresses.
|
||||
masm.leaq(str1, new AMD64Address(asRegister(array1Value), array1BaseOffset));
|
||||
masm.leaq(str2, new AMD64Address(asRegister(array2Value), array2BaseOffset));
|
||||
Register cnt1 = asRegister(length1Value);
|
||||
Register cnt2 = asRegister(length2Value);
|
||||
|
||||
// Checkstyle: stop
|
||||
Label LENGTH_DIFF_LABEL = new Label();
|
||||
Label POP_LABEL = new Label();
|
||||
Label DONE_LABEL = new Label();
|
||||
Label WHILE_HEAD_LABEL = new Label();
|
||||
Label COMPARE_WIDE_VECTORS_LOOP_FAILED = new Label(); // used only _LP64 && AVX3
|
||||
int stride, stride2;
|
||||
int adr_stride = -1;
|
||||
int adr_stride1 = -1;
|
||||
int adr_stride2 = -1;
|
||||
// Checkstyle: resume
|
||||
int stride2x2 = 0x40;
|
||||
AMD64Address.Scale scale = null;
|
||||
AMD64Address.Scale scale1 = null;
|
||||
AMD64Address.Scale scale2 = null;
|
||||
|
||||
// if (ae != StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
stride2x2 = 0x20;
|
||||
}
|
||||
|
||||
// if (ae == StrIntrinsicNode::LU || ae == StrIntrinsicNode::UL) {
|
||||
if (kind1 != kind2) {
|
||||
masm.shrl(cnt2, 1);
|
||||
}
|
||||
// Compute the minimum of the string lengths and the
|
||||
// difference of the string lengths (stack).
|
||||
// Do the conditional move stuff
|
||||
masm.movl(result, cnt1);
|
||||
masm.subl(cnt1, cnt2);
|
||||
masm.push(cnt1);
|
||||
masm.cmovl(ConditionFlag.LessEqual, cnt2, result); // cnt2 = min(cnt1, cnt2)
|
||||
|
||||
// Is the minimum length zero?
|
||||
masm.testl(cnt2, cnt2);
|
||||
masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
// Load first bytes
|
||||
masm.movzbl(result, new AMD64Address(str1, 0)); // result = str1[0]
|
||||
masm.movzbl(cnt1, new AMD64Address(str2, 0)); // cnt1 = str2[0]
|
||||
// } else if (ae == StrIntrinsicNode::UU) {
|
||||
} else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
|
||||
// Load first characters
|
||||
masm.movzwl(result, new AMD64Address(str1, 0));
|
||||
masm.movzwl(cnt1, new AMD64Address(str2, 0));
|
||||
} else {
|
||||
masm.movzbl(result, new AMD64Address(str1, 0));
|
||||
masm.movzwl(cnt1, new AMD64Address(str2, 0));
|
||||
}
|
||||
masm.subl(result, cnt1);
|
||||
masm.jcc(ConditionFlag.NotZero, POP_LABEL);
|
||||
|
||||
// if (ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
|
||||
// Divide length by 2 to get number of chars
|
||||
masm.shrl(cnt2, 1);
|
||||
}
|
||||
masm.cmpl(cnt2, 1);
|
||||
masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL);
|
||||
|
||||
// Check if the strings start at the same location and setup scale and stride
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.cmpptr(str1, str2);
|
||||
masm.jcc(ConditionFlag.Equal, LENGTH_DIFF_LABEL);
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
scale = AMD64Address.Scale.Times1;
|
||||
stride = 16;
|
||||
} else {
|
||||
scale = AMD64Address.Scale.Times2;
|
||||
stride = 8;
|
||||
}
|
||||
} else {
|
||||
scale1 = AMD64Address.Scale.Times1;
|
||||
scale2 = AMD64Address.Scale.Times2;
|
||||
// scale not used
|
||||
stride = 8;
|
||||
}
|
||||
|
||||
// if (UseAVX >= 2 && UseSSE42Intrinsics) {
|
||||
if (supportsAVX2(crb.target) && supportsSSE42(crb.target)) {
|
||||
Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
|
||||
|
||||
// Checkstyle: stop
|
||||
Label COMPARE_WIDE_VECTORS = new Label();
|
||||
Label VECTOR_NOT_EQUAL = new Label();
|
||||
Label COMPARE_WIDE_TAIL = new Label();
|
||||
Label COMPARE_SMALL_STR = new Label();
|
||||
Label COMPARE_WIDE_VECTORS_LOOP = new Label();
|
||||
Label COMPARE_16_CHARS = new Label();
|
||||
Label COMPARE_INDEX_CHAR = new Label();
|
||||
Label COMPARE_WIDE_VECTORS_LOOP_AVX2 = new Label();
|
||||
Label COMPARE_TAIL_LONG = new Label();
|
||||
Label COMPARE_WIDE_VECTORS_LOOP_AVX3 = new Label(); // used only _LP64 && AVX3
|
||||
// Checkstyle: resume
|
||||
|
||||
int pcmpmask = 0x19;
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
pcmpmask &= ~0x01;
|
||||
}
|
||||
|
||||
// Setup to compare 16-chars (32-bytes) vectors,
|
||||
// start from first character again because it has aligned address.
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
stride2 = 32;
|
||||
} else {
|
||||
stride2 = 16;
|
||||
}
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
adr_stride = stride << scale.log2;
|
||||
} else {
|
||||
adr_stride1 = 8; // stride << scale1;
|
||||
adr_stride2 = 16; // stride << scale2;
|
||||
}
|
||||
|
||||
assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri";
|
||||
// rax and rdx are used by pcmpestri as elements counters
|
||||
masm.movl(result, cnt2);
|
||||
masm.andl(cnt2, ~(stride2 - 1)); // cnt2 holds the vector count
|
||||
masm.jcc(ConditionFlag.Zero, COMPARE_TAIL_LONG);
|
||||
|
||||
// fast path : compare first 2 8-char vectors.
|
||||
masm.bind(COMPARE_16_CHARS);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.movdqu(vec1, new AMD64Address(str1, 0));
|
||||
} else {
|
||||
masm.pmovzxbw(vec1, new AMD64Address(str1, 0));
|
||||
}
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask);
|
||||
masm.jccb(ConditionFlag.Below, COMPARE_INDEX_CHAR);
|
||||
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.movdqu(vec1, new AMD64Address(str1, adr_stride));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride), pcmpmask);
|
||||
} else {
|
||||
masm.pmovzxbw(vec1, new AMD64Address(str1, adr_stride1));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, adr_stride2), pcmpmask);
|
||||
}
|
||||
masm.jccb(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS);
|
||||
masm.addl(cnt1, stride);
|
||||
|
||||
// Compare the characters at index in cnt1
|
||||
masm.bind(COMPARE_INDEX_CHAR); // cnt1 has the offset of the mismatching character
|
||||
loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1);
|
||||
masm.subl(result, cnt2);
|
||||
masm.jmp(POP_LABEL);
|
||||
|
||||
// Setup the registers to start vector comparison loop
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale));
|
||||
} else {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale1));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale2));
|
||||
}
|
||||
masm.subl(result, stride2);
|
||||
masm.subl(cnt2, stride2);
|
||||
masm.jcc(ConditionFlag.Zero, COMPARE_WIDE_TAIL);
|
||||
masm.negq(result);
|
||||
|
||||
// In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest)
|
||||
masm.bind(COMPARE_WIDE_VECTORS_LOOP);
|
||||
|
||||
// if (VM_Version::supports_avx512vlbw()) { // trying 64 bytes fast loop
|
||||
if (supportsAVX512VLBW(crb.target)) {
|
||||
masm.cmpl(cnt2, stride2x2);
|
||||
masm.jccb(ConditionFlag.Below, COMPARE_WIDE_VECTORS_LOOP_AVX2);
|
||||
masm.testl(cnt2, stride2x2 - 1); // cnt2 holds the vector count
|
||||
// means we cannot subtract by 0x40
|
||||
masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX2);
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX3); // the hottest loop
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.evmovdquq(vec1, new AMD64Address(str1, result, scale), AvxVectorLen.AVX_512bit);
|
||||
// k7 == 11..11, if operands equal, otherwise k7 has some 0
|
||||
masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale), AvxVectorLen.AVX_512bit);
|
||||
} else {
|
||||
masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_512bit);
|
||||
// k7 == 11..11, if operands equal, otherwise k7 has some 0
|
||||
masm.evpcmpeqb(k7, vec1, new AMD64Address(str2, result, scale2), AvxVectorLen.AVX_512bit);
|
||||
}
|
||||
masm.kortestql(k7, k7);
|
||||
masm.jcc(ConditionFlag.AboveEqual, COMPARE_WIDE_VECTORS_LOOP_FAILED); // miscompare
|
||||
masm.addq(result, stride2x2); // update since we already compared at this addr
|
||||
masm.subl(cnt2, stride2x2); // and sub the size too
|
||||
masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP_AVX3);
|
||||
|
||||
masm.vpxor(vec1, vec1, vec1);
|
||||
masm.jmpb(COMPARE_WIDE_TAIL);
|
||||
}
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS_LOOP_AVX2);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.vmovdqu(vec1, new AMD64Address(str1, result, scale));
|
||||
masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale));
|
||||
} else {
|
||||
masm.vpmovzxbw(vec1, new AMD64Address(str1, result, scale1), AvxVectorLen.AVX_256bit);
|
||||
masm.vpxor(vec1, vec1, new AMD64Address(str2, result, scale2));
|
||||
}
|
||||
masm.vptest(vec1, vec1);
|
||||
masm.jcc(ConditionFlag.NotZero, VECTOR_NOT_EQUAL);
|
||||
masm.addq(result, stride2);
|
||||
masm.subl(cnt2, stride2);
|
||||
masm.jcc(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS_LOOP);
|
||||
// clean upper bits of YMM registers
|
||||
masm.vpxor(vec1, vec1, vec1);
|
||||
|
||||
// compare wide vectors tail
|
||||
masm.bind(COMPARE_WIDE_TAIL);
|
||||
masm.testq(result, result);
|
||||
masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
|
||||
|
||||
masm.movl(result, stride2);
|
||||
masm.movl(cnt2, result);
|
||||
masm.negq(result);
|
||||
masm.jmp(COMPARE_WIDE_VECTORS_LOOP_AVX2);
|
||||
|
||||
// Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors.
|
||||
masm.bind(VECTOR_NOT_EQUAL);
|
||||
// clean upper bits of YMM registers
|
||||
masm.vpxor(vec1, vec1, vec1);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale));
|
||||
} else {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale1));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale2));
|
||||
}
|
||||
masm.jmp(COMPARE_16_CHARS);
|
||||
|
||||
// Compare tail chars, length between 1 to 15 chars
|
||||
masm.bind(COMPARE_TAIL_LONG);
|
||||
masm.movl(cnt2, result);
|
||||
masm.cmpl(cnt2, stride);
|
||||
masm.jcc(ConditionFlag.Less, COMPARE_SMALL_STR);
|
||||
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.movdqu(vec1, new AMD64Address(str1, 0));
|
||||
} else {
|
||||
masm.pmovzxbw(vec1, new AMD64Address(str1, 0));
|
||||
}
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, 0), pcmpmask);
|
||||
masm.jcc(ConditionFlag.Below, COMPARE_INDEX_CHAR);
|
||||
masm.subq(cnt2, stride);
|
||||
masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale));
|
||||
} else {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale1));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale2));
|
||||
}
|
||||
masm.negq(cnt2);
|
||||
masm.jmpb(WHILE_HEAD_LABEL);
|
||||
|
||||
masm.bind(COMPARE_SMALL_STR);
|
||||
} else if (supportsSSE42(crb.target)) {
|
||||
Register vec1 = asRegister(vectorTemp1, AMD64Kind.DOUBLE);
|
||||
|
||||
// Checkstyle: stop
|
||||
Label COMPARE_WIDE_VECTORS = new Label();
|
||||
Label VECTOR_NOT_EQUAL = new Label();
|
||||
Label COMPARE_TAIL = new Label();
|
||||
// Checkstyle: resume
|
||||
int pcmpmask = 0x19;
|
||||
// Setup to compare 8-char (16-byte) vectors,
|
||||
// start from first character again because it has aligned address.
|
||||
masm.movl(result, cnt2);
|
||||
masm.andl(cnt2, ~(stride - 1)); // cnt2 holds the vector count
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
pcmpmask &= ~0x01;
|
||||
}
|
||||
masm.jcc(ConditionFlag.Zero, COMPARE_TAIL);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale));
|
||||
} else {
|
||||
masm.leaq(str1, new AMD64Address(str1, result, scale1));
|
||||
masm.leaq(str2, new AMD64Address(str2, result, scale2));
|
||||
}
|
||||
masm.negq(result);
|
||||
|
||||
// pcmpestri
|
||||
// inputs:
|
||||
// vec1- substring
|
||||
// rax - negative string length (elements count)
|
||||
// mem - scanned string
|
||||
// rdx - string length (elements count)
|
||||
// pcmpmask - cmp mode: 11000 (string compare with negated result)
|
||||
// + 00 (unsigned bytes) or + 01 (unsigned shorts)
|
||||
// outputs:
|
||||
// rcx - first mismatched element index
|
||||
assert result.equals(rax) && cnt2.equals(rdx) && cnt1.equals(rcx) : "pcmpestri";
|
||||
|
||||
masm.bind(COMPARE_WIDE_VECTORS);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.movdqu(vec1, new AMD64Address(str1, result, scale));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask);
|
||||
} else {
|
||||
masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask);
|
||||
}
|
||||
// After pcmpestri cnt1(rcx) contains mismatched element index
|
||||
|
||||
masm.jccb(ConditionFlag.Below, VECTOR_NOT_EQUAL); // CF==1
|
||||
masm.addq(result, stride);
|
||||
masm.subq(cnt2, stride);
|
||||
masm.jccb(ConditionFlag.NotZero, COMPARE_WIDE_VECTORS);
|
||||
|
||||
// compare wide vectors tail
|
||||
masm.testq(result, result);
|
||||
masm.jcc(ConditionFlag.Zero, LENGTH_DIFF_LABEL);
|
||||
|
||||
masm.movl(cnt2, stride);
|
||||
masm.movl(result, stride);
|
||||
masm.negq(result);
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.movdqu(vec1, new AMD64Address(str1, result, scale));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, result, scale), pcmpmask);
|
||||
} else {
|
||||
masm.pmovzxbw(vec1, new AMD64Address(str1, result, scale1));
|
||||
masm.pcmpestri(vec1, new AMD64Address(str2, result, scale2), pcmpmask);
|
||||
}
|
||||
masm.jccb(ConditionFlag.AboveEqual, LENGTH_DIFF_LABEL);
|
||||
|
||||
// Mismatched characters in the vectors
|
||||
masm.bind(VECTOR_NOT_EQUAL);
|
||||
masm.addq(cnt1, result);
|
||||
loadNextElements(masm, result, cnt2, str1, str2, scale, scale1, scale2, cnt1);
|
||||
masm.subl(result, cnt2);
|
||||
masm.jmpb(POP_LABEL);
|
||||
|
||||
masm.bind(COMPARE_TAIL); // limit is zero
|
||||
masm.movl(cnt2, result);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
|
||||
// Shift str2 and str1 to the end of the arrays, negate min
|
||||
// if (ae == StrIntrinsicNode::LL || ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == kind2) {
|
||||
masm.leaq(str1, new AMD64Address(str1, cnt2, scale));
|
||||
masm.leaq(str2, new AMD64Address(str2, cnt2, scale));
|
||||
} else {
|
||||
masm.leaq(str1, new AMD64Address(str1, cnt2, scale1));
|
||||
masm.leaq(str2, new AMD64Address(str2, cnt2, scale2));
|
||||
}
|
||||
masm.decrementl(cnt2); // first character was compared already
|
||||
masm.negq(cnt2);
|
||||
|
||||
// Compare the rest of the elements
|
||||
masm.bind(WHILE_HEAD_LABEL);
|
||||
loadNextElements(masm, result, cnt1, str1, str2, scale, scale1, scale2, cnt2);
|
||||
masm.subl(result, cnt1);
|
||||
masm.jccb(ConditionFlag.NotZero, POP_LABEL);
|
||||
masm.incrementq(cnt2, 1);
|
||||
masm.jccb(ConditionFlag.NotZero, WHILE_HEAD_LABEL);
|
||||
|
||||
// Strings are equal up to min length. Return the length difference.
|
||||
masm.bind(LENGTH_DIFF_LABEL);
|
||||
masm.pop(result);
|
||||
// if (ae == StrIntrinsicNode::UU) {
|
||||
if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
|
||||
// Divide diff by 2 to get number of chars
|
||||
masm.sarl(result, 1);
|
||||
}
|
||||
masm.jmpb(DONE_LABEL);
|
||||
|
||||
// if (VM_Version::supports_avx512vlbw()) {
|
||||
if (supportsAVX512VLBW(crb.target)) {
|
||||
masm.bind(COMPARE_WIDE_VECTORS_LOOP_FAILED);
|
||||
|
||||
masm.kmovql(cnt1, k7);
|
||||
masm.notq(cnt1);
|
||||
masm.bsfq(cnt2, cnt1);
|
||||
// if (ae != StrIntrinsicNode::LL) {
|
||||
if (kind1 != JavaKind.Byte && kind2 != JavaKind.Byte) {
|
||||
// Divide diff by 2 to get number of chars
|
||||
masm.sarl(cnt2, 1);
|
||||
}
|
||||
masm.addq(result, cnt2);
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
masm.movzbl(cnt1, new AMD64Address(str2, result, Scale.Times1));
|
||||
masm.movzbl(result, new AMD64Address(str1, result, Scale.Times1));
|
||||
} else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
|
||||
masm.movzwl(cnt1, new AMD64Address(str2, result, scale));
|
||||
masm.movzwl(result, new AMD64Address(str1, result, scale));
|
||||
} else {
|
||||
masm.movzwl(cnt1, new AMD64Address(str2, result, scale2));
|
||||
masm.movzbl(result, new AMD64Address(str1, result, scale1));
|
||||
}
|
||||
masm.subl(result, cnt1);
|
||||
masm.jmpb(POP_LABEL);
|
||||
}
|
||||
|
||||
// Discard the stored length difference
|
||||
masm.bind(POP_LABEL);
|
||||
masm.pop(cnt1);
|
||||
|
||||
// That's it
|
||||
masm.bind(DONE_LABEL);
|
||||
// if (ae == StrIntrinsicNode::UL) {
|
||||
if (kind1 == JavaKind.Char && kind2 == JavaKind.Byte) {
|
||||
masm.negl(result);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadNextElements(AMD64MacroAssembler masm, Register elem1, Register elem2, Register str1, Register str2,
|
||||
AMD64Address.Scale scale, AMD64Address.Scale scale1,
|
||||
AMD64Address.Scale scale2, Register index) {
|
||||
// if (ae == StrIntrinsicNode::LL) {
|
||||
if (kind1 == JavaKind.Byte && kind2 == JavaKind.Byte) {
|
||||
masm.movzbl(elem1, new AMD64Address(str1, index, scale, 0));
|
||||
masm.movzbl(elem2, new AMD64Address(str2, index, scale, 0));
|
||||
// } else if (ae == StrIntrinsicNode::UU) {
|
||||
} else if (kind1 == JavaKind.Char && kind2 == JavaKind.Char) {
|
||||
masm.movzwl(elem1, new AMD64Address(str1, index, scale, 0));
|
||||
masm.movzwl(elem2, new AMD64Address(str2, index, scale, 0));
|
||||
} else {
|
||||
masm.movzbl(elem1, new AMD64Address(str1, index, scale1, 0));
|
||||
masm.movzwl(elem2, new AMD64Address(str2, index, scale2, 0));
|
||||
}
|
||||
}
|
||||
|
||||
private static final Unsafe UNSAFE = initUnsafe();
|
||||
|
||||
private static Unsafe initUnsafe() {
|
||||
try {
|
||||
return Unsafe.getUnsafe();
|
||||
} catch (SecurityException se) {
|
||||
try {
|
||||
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
theUnsafe.setAccessible(true);
|
||||
return (Unsafe) theUnsafe.get(Unsafe.class);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("exception while trying to get Unsafe", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.lir.amd64;
|
||||
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
import org.graalvm.compiler.lir.LIRInstructionClass;
|
||||
import org.graalvm.compiler.lir.Opcode;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
|
||||
@Opcode("LFENCE")
|
||||
public final class AMD64LFenceOp extends AMD64LIRInstruction {
|
||||
public static final LIRInstructionClass<AMD64LFenceOp> TYPE = LIRInstructionClass.create(AMD64LFenceOp.class);
|
||||
|
||||
public AMD64LFenceOp() {
|
||||
super(TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler asm) {
|
||||
asm.lfence();
|
||||
}
|
||||
}
|
@ -22,6 +22,11 @@
|
||||
*/
|
||||
package org.graalvm.compiler.lir.amd64;
|
||||
|
||||
import static java.lang.Double.doubleToRawLongBits;
|
||||
import static java.lang.Float.floatToRawIntBits;
|
||||
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 static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal;
|
||||
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
|
||||
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
|
||||
@ -33,21 +38,16 @@ import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
|
||||
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.UNINITIALIZED;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
|
||||
import static java.lang.Double.doubleToRawLongBits;
|
||||
import static java.lang.Float.floatToRawIntBits;
|
||||
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.core.common.CompressEncoding;
|
||||
import org.graalvm.compiler.core.common.LIRKind;
|
||||
import org.graalvm.compiler.core.common.NumUtil;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Address;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
|
||||
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
|
||||
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.spi.LIRKindTool;
|
||||
import org.graalvm.compiler.core.common.type.DataPointerConstant;
|
||||
import org.graalvm.compiler.debug.GraalError;
|
||||
@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.StandardOp.NullCheck;
|
||||
import org.graalvm.compiler.lir.StandardOp.ValueMoveOp;
|
||||
import org.graalvm.compiler.lir.VirtualStackSlot;
|
||||
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
|
||||
import org.graalvm.compiler.options.OptionValues;
|
||||
|
||||
import jdk.vm.ci.amd64.AMD64;
|
||||
import jdk.vm.ci.amd64.AMD64Kind;
|
||||
@ -763,7 +764,7 @@ public class AMD64Move {
|
||||
|
||||
@Def({REG, HINT}) private AllocatableValue result;
|
||||
@Use({REG, CONST}) private Value input;
|
||||
@Alive({REG, ILLEGAL}) private AllocatableValue baseRegister;
|
||||
@Alive({REG, ILLEGAL, UNINITIALIZED}) private AllocatableValue baseRegister;
|
||||
|
||||
protected PointerCompressionOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
|
||||
AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
|
||||
@ -777,8 +778,8 @@ public class AMD64Move {
|
||||
this.lirKindTool = lirKindTool;
|
||||
}
|
||||
|
||||
protected boolean hasBase(CompilationResultBuilder crb) {
|
||||
return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase();
|
||||
public static boolean hasBase(OptionValues options, CompressEncoding encoding) {
|
||||
return GeneratePIC.getValue(options) || encoding.hasBase();
|
||||
}
|
||||
|
||||
public final Value getInput() {
|
||||
@ -820,7 +821,7 @@ public class AMD64Move {
|
||||
move(lirKindTool.getObjectKind(), crb, masm);
|
||||
|
||||
Register resReg = asRegister(getResult());
|
||||
if (hasBase(crb)) {
|
||||
if (hasBase(crb.getOptions(), encoding)) {
|
||||
Register baseReg = getBaseRegister();
|
||||
if (!nonNull) {
|
||||
masm.testq(resReg, resReg);
|
||||
@ -852,15 +853,15 @@ public class AMD64Move {
|
||||
@Override
|
||||
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
|
||||
move(lirKindTool.getNarrowOopKind(), crb, masm);
|
||||
emitUncompressCode(masm, asRegister(getResult()), getShift(), hasBase(crb.getOptions(), encoding) ? getBaseRegister() : null, nonNull);
|
||||
}
|
||||
|
||||
Register resReg = asRegister(getResult());
|
||||
int shift = getShift();
|
||||
public static void emitUncompressCode(AMD64MacroAssembler masm, Register resReg, int shift, Register baseReg, boolean nonNull) {
|
||||
if (shift != 0) {
|
||||
masm.shlq(resReg, shift);
|
||||
}
|
||||
|
||||
if (hasBase(crb)) {
|
||||
Register baseReg = getBaseRegister();
|
||||
if (baseReg != null) {
|
||||
if (nonNull) {
|
||||
masm.addq(resReg, baseReg);
|
||||
return;
|
||||
|
@ -96,7 +96,11 @@ public class LIRInstructionClass<T> extends LIRIntrospection<T> {
|
||||
try {
|
||||
Field field = clazz.getDeclaredField("TYPE");
|
||||
field.setAccessible(true);
|
||||
return (LIRInstructionClass<T>) field.get(null);
|
||||
LIRInstructionClass<T> result = (LIRInstructionClass<T>) field.get(null);
|
||||
if (result == null) {
|
||||
throw GraalError.shouldNotReachHere("TYPE field not initialized for class " + clazz.getTypeName());
|
||||
}
|
||||
return result;
|
||||
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -53,7 +53,11 @@ public final class GlobalLivenessInfo {
|
||||
public final int[] emptySet;
|
||||
|
||||
public Builder(LIR lir) {
|
||||
info = new GlobalLivenessInfo(lir);
|
||||
this(lir.numVariables(), lir.getControlFlowGraph().getBlocks().length);
|
||||
}
|
||||
|
||||
public Builder(int numVariables, int numBlocks) {
|
||||
info = new GlobalLivenessInfo(numVariables, numBlocks);
|
||||
emptySet = new int[0];
|
||||
}
|
||||
|
||||
@ -97,10 +101,8 @@ public final class GlobalLivenessInfo {
|
||||
private final Value[][] blockToLocIn;
|
||||
private final Value[][] blockToLocOut;
|
||||
|
||||
private GlobalLivenessInfo(LIR lir) {
|
||||
int numVariables = lir.numVariables();
|
||||
private GlobalLivenessInfo(int numVariables, int numBlocks) {
|
||||
variables = new Variable[numVariables];
|
||||
int numBlocks = lir.getControlFlowGraph().getBlocks().length;
|
||||
blockToVarIn = new int[numBlocks][];
|
||||
blockToVarOut = new int[numBlocks][];
|
||||
blockToLocIn = new Value[numBlocks][];
|
||||
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.graalvm.compiler.lir.alloc.trace;
|
||||
|
||||
import org.graalvm.compiler.core.common.alloc.Trace;
|
||||
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
|
||||
|
||||
/**
|
||||
* A collection of assertions that are assumed to hold in various places of the Trace Register
|
||||
* Allocation framework.
|
||||
*
|
||||
* The main goal is to document pieces of code that rely on specific properties of traces. In case
|
||||
* an assumption is no longer valid, this makes it easy (assumed they are used correctly) to find
|
||||
* places that need changes.
|
||||
*/
|
||||
final class TraceAssertions {
|
||||
|
||||
/**
|
||||
* Asserts that variable indices are properly sorted.
|
||||
*/
|
||||
public static boolean liveSetsAreSorted(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> block) {
|
||||
return isSorted(livenessInfo.getBlockIn(block)) && isSorted(livenessInfo.getBlockOut(block));
|
||||
}
|
||||
|
||||
private static boolean isSorted(int[] live) {
|
||||
if (live.length == 0) {
|
||||
return true;
|
||||
}
|
||||
int current = live[0];
|
||||
for (int i = 1; i < live.length; i++) {
|
||||
int last = current;
|
||||
current = live[i];
|
||||
if (current <= last) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a trace head has only a single predecessor.
|
||||
*
|
||||
* This is not true for every trace-building algorithm (for example
|
||||
* {@link TraceBuilderPhase.TraceBuilder#SingleBlock}).
|
||||
*/
|
||||
public static boolean singleHeadPredecessor(Trace trace) {
|
||||
return trace.getBlocks()[0].getPredecessorCount() == 1;
|
||||
}
|
||||
}
|
@ -84,32 +84,58 @@ public final class TraceGlobalMoveResolutionPhase {
|
||||
DebugContext debug = lir.getDebug();
|
||||
try (Indent indent = debug.logAndIndent("Trace global move resolution")) {
|
||||
for (Trace trace : resultTraces.getTraces()) {
|
||||
for (AbstractBlockBase<?> fromBlock : trace.getBlocks()) {
|
||||
for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
|
||||
if (resultTraces.getTraceForBlock(fromBlock) != resultTraces.getTraceForBlock(toBlock)) {
|
||||
try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock,
|
||||
resultTraces.getTraceForBlock(toBlock).getId())) {
|
||||
resolveTrace(resultTraces, livenessInfo, lir, moveResolver, trace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<LIRInstruction> instructions;
|
||||
final int insertIdx;
|
||||
if (fromBlock.getSuccessorCount() == 1) {
|
||||
instructions = lir.getLIRforBlock(fromBlock);
|
||||
insertIdx = instructions.size() - 1;
|
||||
} else {
|
||||
assert toBlock.getPredecessorCount() == 1;
|
||||
instructions = lir.getLIRforBlock(toBlock);
|
||||
insertIdx = 1;
|
||||
}
|
||||
|
||||
moveResolver.setInsertPosition(instructions, insertIdx);
|
||||
resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock);
|
||||
moveResolver.resolveAndAppendMoves();
|
||||
}
|
||||
}
|
||||
private static void resolveTrace(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, Trace trace) {
|
||||
AbstractBlockBase<?>[] traceBlocks = trace.getBlocks();
|
||||
int traceLength = traceBlocks.length;
|
||||
// all but the last block
|
||||
AbstractBlockBase<?> nextBlock = traceBlocks[0];
|
||||
for (int i = 1; i < traceLength; i++) {
|
||||
AbstractBlockBase<?> fromBlock = nextBlock;
|
||||
nextBlock = traceBlocks[i];
|
||||
if (fromBlock.getSuccessorCount() > 1) {
|
||||
for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
|
||||
if (toBlock != nextBlock) {
|
||||
interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, fromBlock, toBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// last block
|
||||
assert nextBlock == traceBlocks[traceLength - 1];
|
||||
for (AbstractBlockBase<?> toBlock : nextBlock.getSuccessors()) {
|
||||
if (resultTraces.getTraceForBlock(nextBlock) != resultTraces.getTraceForBlock(toBlock)) {
|
||||
interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, nextBlock, toBlock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private static void interTraceEdge(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, AbstractBlockBase<?> fromBlock,
|
||||
AbstractBlockBase<?> toBlock) {
|
||||
DebugContext debug = lir.getDebug();
|
||||
try (Indent indent0 = debug.logAndIndent("Handle trace edge from %s (Trace%d) to %s (Trace%d)", fromBlock, resultTraces.getTraceForBlock(fromBlock).getId(), toBlock,
|
||||
resultTraces.getTraceForBlock(toBlock).getId())) {
|
||||
|
||||
final ArrayList<LIRInstruction> instructions;
|
||||
final int insertIdx;
|
||||
if (fromBlock.getSuccessorCount() == 1) {
|
||||
instructions = lir.getLIRforBlock(fromBlock);
|
||||
insertIdx = instructions.size() - 1;
|
||||
} else {
|
||||
assert toBlock.getPredecessorCount() == 1;
|
||||
instructions = lir.getLIRforBlock(toBlock);
|
||||
insertIdx = 1;
|
||||
}
|
||||
|
||||
moveResolver.setInsertPosition(instructions, insertIdx);
|
||||
resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock);
|
||||
moveResolver.resolveAndAppendMoves();
|
||||
}
|
||||
}
|
||||
|
||||
private static void resolveEdge(LIR lir, GlobalLivenessInfo livenessInfo, TraceGlobalMoveResolver moveResolver, AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock) {
|
||||
@ -129,6 +155,10 @@ public final class TraceGlobalMoveResolutionPhase {
|
||||
// GLI
|
||||
Value[] locFrom = livenessInfo.getOutLocation(fromBlock);
|
||||
Value[] locTo = livenessInfo.getInLocation(toBlock);
|
||||
if (locFrom == locTo) {
|
||||
// a strategy might reuse the locations array if locations are the same
|
||||
return;
|
||||
}
|
||||
assert locFrom.length == locTo.length;
|
||||
|
||||
for (int i = 0; i < locFrom.length; i++) {
|
||||
|
@ -36,19 +36,6 @@ import jdk.vm.ci.meta.Value;
|
||||
|
||||
public class TraceUtil {
|
||||
|
||||
public static AbstractBlockBase<?> getBestTraceInterPredecessor(TraceBuilderResult traceResult, AbstractBlockBase<?> block) {
|
||||
AbstractBlockBase<?> bestPred = null;
|
||||
int bestTraceId = traceResult.getTraceForBlock(block).getId();
|
||||
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
|
||||
int predTraceId = traceResult.getTraceForBlock(pred).getId();
|
||||
if (predTraceId < bestTraceId) {
|
||||
bestPred = pred;
|
||||
bestTraceId = predTraceId;
|
||||
}
|
||||
}
|
||||
return bestPred;
|
||||
}
|
||||
|
||||
public static boolean isShadowedRegisterValue(Value value) {
|
||||
assert value != null;
|
||||
return value instanceof ShadowedRegisterValue;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,12 +26,13 @@ import static org.graalvm.compiler.lir.LIRValueUtil.asVariable;
|
||||
import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
|
||||
import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import org.graalvm.compiler.core.common.alloc.Trace;
|
||||
import org.graalvm.compiler.core.common.alloc.TraceBuilderResult;
|
||||
import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
|
||||
import org.graalvm.compiler.lir.LIR;
|
||||
import org.graalvm.compiler.lir.LIRInstruction;
|
||||
import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
|
||||
import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
|
||||
import org.graalvm.compiler.lir.StandardOp.JumpOp;
|
||||
@ -47,68 +48,67 @@ import jdk.vm.ci.meta.Value;
|
||||
* Allocates a trivial trace i.e. a trace consisting of a single block with no instructions other
|
||||
* than the {@link LabelOp} and the {@link JumpOp}.
|
||||
*/
|
||||
final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
|
||||
public final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
|
||||
|
||||
@Override
|
||||
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
|
||||
LIR lir = lirGenRes.getLIR();
|
||||
TraceBuilderResult resultTraces = context.resultTraces;
|
||||
assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
|
||||
AbstractBlockBase<?> block = trace.getBlocks()[0];
|
||||
assert TraceAssertions.singleHeadPredecessor(trace) : "Trace head with more than one predecessor?!" + trace;
|
||||
AbstractBlockBase<?> pred = block.getPredecessors()[0];
|
||||
|
||||
AbstractBlockBase<?> pred = TraceUtil.getBestTraceInterPredecessor(resultTraces, block);
|
||||
|
||||
Value[] variableMap = new Value[lir.numVariables()];
|
||||
GlobalLivenessInfo livenessInfo = context.livenessInfo;
|
||||
collectMapping(block, pred, livenessInfo, variableMap);
|
||||
assignLocations(lir, block, livenessInfo, variableMap);
|
||||
allocate(block, pred, livenessInfo, SSAUtil.phiOutOrNull(lir, block));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the mapping from variable to location. Additionally the
|
||||
* {@link GlobalLivenessInfo#setInLocations incoming location array} is set.
|
||||
*/
|
||||
private static void collectMapping(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, Value[] variableMap) {
|
||||
public static void allocate(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, LIRInstruction jump) {
|
||||
// exploit that the live sets are sorted
|
||||
assert TraceAssertions.liveSetsAreSorted(livenessInfo, block);
|
||||
assert TraceAssertions.liveSetsAreSorted(livenessInfo, pred);
|
||||
|
||||
// setup incoming variables/locations
|
||||
final int[] blockIn = livenessInfo.getBlockIn(block);
|
||||
final Value[] predLocOut = livenessInfo.getOutLocation(pred);
|
||||
final Value[] locationIn = new Value[blockIn.length];
|
||||
for (int i = 0; i < blockIn.length; i++) {
|
||||
int varNum = blockIn[i];
|
||||
if (varNum >= 0) {
|
||||
Value location = predLocOut[i];
|
||||
variableMap[varNum] = location;
|
||||
locationIn[i] = location;
|
||||
} else {
|
||||
locationIn[i] = Value.ILLEGAL;
|
||||
int inLenght = blockIn.length;
|
||||
|
||||
// setup outgoing variables/locations
|
||||
final int[] blockOut = livenessInfo.getBlockOut(block);
|
||||
int outLength = blockOut.length;
|
||||
final Value[] locationOut = new Value[outLength];
|
||||
|
||||
assert outLength <= inLenght : "Trivial Trace! There cannot be more outgoing values than incoming.";
|
||||
for (int outIdx = 0, inIdx = 0; outIdx < outLength; inIdx++) {
|
||||
if (blockOut[outIdx] == blockIn[inIdx]) {
|
||||
// set the outgoing location to the incoming value
|
||||
locationOut[outIdx++] = predLocOut[inIdx];
|
||||
}
|
||||
}
|
||||
livenessInfo.setInLocations(block, locationIn);
|
||||
|
||||
/*
|
||||
* Since we do not change any of the location we can just use the outgoing of the
|
||||
* predecessor.
|
||||
*/
|
||||
livenessInfo.setInLocations(block, predLocOut);
|
||||
livenessInfo.setOutLocations(block, locationOut);
|
||||
if (jump != null) {
|
||||
handlePhiOut(jump, blockIn, predLocOut);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the outgoing locations according to the {@link #collectMapping variable mapping}.
|
||||
*/
|
||||
private static void assignLocations(LIR lir, AbstractBlockBase<?> block, GlobalLivenessInfo livenessInfo, Value[] variableMap) {
|
||||
final int[] blockOut = livenessInfo.getBlockOut(block);
|
||||
final Value[] locationOut = new Value[blockOut.length];
|
||||
for (int i = 0; i < blockOut.length; i++) {
|
||||
int varNum = blockOut[i];
|
||||
locationOut[i] = variableMap[varNum];
|
||||
}
|
||||
livenessInfo.setOutLocations(block, locationOut);
|
||||
|
||||
private static void handlePhiOut(LIRInstruction jump, int[] varIn, Value[] locIn) {
|
||||
// handle outgoing phi values
|
||||
ValueProcedure outputConsumer = new ValueProcedure() {
|
||||
@Override
|
||||
public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
|
||||
if (isVariable(value)) {
|
||||
return variableMap[asVariable(value).index];
|
||||
// since incoming variables are sorted, we can do a binary search
|
||||
return locIn[Arrays.binarySearch(varIn, asVariable(value).index)];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
JumpOp jump = SSAUtil.phiOut(lir, block);
|
||||
// Jumps have only alive values (outgoing phi values)
|
||||
jump.forEachAlive(outputConsumer);
|
||||
}
|
||||
|
@ -501,11 +501,12 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
|
||||
|
||||
try (Indent indent = debug.logAndIndent("handle block %s", block)) {
|
||||
currentInstructions = getLIR().getLIRforBlock(block);
|
||||
for (currentInstructionIndex = currentInstructions.size() - 1; currentInstructionIndex >= 0; currentInstructionIndex--) {
|
||||
final int lastInstIdx = currentInstructions.size() - 1;
|
||||
for (currentInstructionIndex = lastInstIdx; currentInstructionIndex >= 0; currentInstructionIndex--) {
|
||||
LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
|
||||
if (inst != null) {
|
||||
inst.setId(currentOpId);
|
||||
allocateInstruction(inst, block);
|
||||
allocateInstruction(inst, block, currentInstructionIndex == 0, currentInstructionIndex == lastInstIdx);
|
||||
}
|
||||
}
|
||||
allocatedBlocks.set(block.getId());
|
||||
@ -514,7 +515,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block) {
|
||||
private void allocateInstruction(LIRInstruction op, AbstractBlockBase<?> block, boolean isLabel, boolean isBlockEnd) {
|
||||
assert op != null && op.id() == currentOpId;
|
||||
try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
|
||||
try (Indent indent1 = debug.logAndIndent("output pos")) {
|
||||
@ -537,7 +538,8 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
|
||||
// should have
|
||||
op.forEachTemp(allocStackOrRegisterProcedure);
|
||||
op.forEachOutput(allocStackOrRegisterProcedure);
|
||||
if (op instanceof LabelOp) {
|
||||
if (isLabel) {
|
||||
assert op instanceof LabelOp;
|
||||
processIncoming(block, op);
|
||||
}
|
||||
}
|
||||
@ -551,7 +553,8 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
|
||||
op.forEachInput(allocRegisterProcedure);
|
||||
|
||||
op.forEachAlive(allocStackOrRegisterProcedure);
|
||||
if (op instanceof BlockEndOp) {
|
||||
if (isBlockEnd) {
|
||||
assert op instanceof BlockEndOp;
|
||||
processOutgoing(block, op);
|
||||
}
|
||||
op.forEachState(allocStackOrRegisterProcedure);
|
||||
|
@ -112,10 +112,6 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
|
||||
buildIntervals();
|
||||
}
|
||||
|
||||
private boolean isAllocated(AbstractBlockBase<?> currentBlock, AbstractBlockBase<?> other) {
|
||||
return traceBuilderResult.getTraceForBlock(other).getId() < traceBuilderResult.getTraceForBlock(currentBlock).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count instructions in all blocks. The numbering follows the
|
||||
* {@linkplain TraceLinearScan#sortedBlocks() register allocation order}.
|
||||
@ -621,26 +617,29 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
|
||||
assert allocator.instructionForId(opId) == op : "must match";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add register hints for incoming values, i.e., values that are not defined in the trace.
|
||||
*
|
||||
* Due to the dominance property of SSA form, all values live at some point in the trace
|
||||
* that are not defined in the trace are live at the beginning of it.
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
private void addInterTraceHints() {
|
||||
try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) {
|
||||
GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo();
|
||||
// set hints for phi/incoming intervals
|
||||
for (AbstractBlockBase<?> block : sortedBlocks()) {
|
||||
LabelOp label = (LabelOp) getLIR().getLIRforBlock(block).get(0);
|
||||
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
|
||||
addInterTraceHints(livenessInfo, pred, block, label);
|
||||
}
|
||||
AbstractBlockBase<?> traceHeadBlock = sortedBlocks()[0];
|
||||
if (traceHeadBlock.getPredecessorCount() == 0) {
|
||||
return;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
}
|
||||
assert traceHeadBlock.getPredecessorCount() == 1 : "Trace head with more than one predecessor?!" + traceHeadBlock;
|
||||
|
||||
private void addInterTraceHints(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> from, AbstractBlockBase<?> to, LabelOp label) {
|
||||
if (isAllocated(to, from)) {
|
||||
int[] liveVars = livenessInfo.getBlockIn(to);
|
||||
Value[] outLocation = livenessInfo.getOutLocation(from);
|
||||
AbstractBlockBase<?> pred = traceHeadBlock.getPredecessors()[0];
|
||||
assert traceBuilderResult.getTraceForBlock(pred).getId() < traceBuilderResult.getTraceForBlock(traceHeadBlock).getId() : "Not yet allocated? " + pred;
|
||||
|
||||
GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo();
|
||||
LabelOp label = (LabelOp) getLIR().getLIRforBlock(traceHeadBlock).get(0);
|
||||
|
||||
int[] liveVars = livenessInfo.getBlockIn(traceHeadBlock);
|
||||
Value[] outLocation = livenessInfo.getOutLocation(pred);
|
||||
|
||||
for (int i = 0; i < liveVars.length; i++) {
|
||||
int varNum = liveVars[i];
|
||||
@ -652,18 +651,20 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw debug.handle(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addInterTraceHint(LabelOp label, int varNum, Value fromValue) {
|
||||
assert isRegister(fromValue) || isVariable(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
|
||||
assert isRegister(fromValue) || isStackSlotValue(fromValue) || isShadowedRegisterValue(fromValue) : "Wrong fromValue: " + fromValue;
|
||||
TraceInterval to = allocator.intervalFor(varNum);
|
||||
if (to == null) {
|
||||
// variable not live -> do nothing
|
||||
return;
|
||||
}
|
||||
if (isVariableOrRegister(fromValue)) {
|
||||
IntervalHint from = getIntervalHint((AllocatableValue) fromValue);
|
||||
if (isRegister(fromValue)) {
|
||||
IntervalHint from = allocator.getOrCreateFixedInterval(asRegisterValue(fromValue));
|
||||
setHint(label, to, from, debug);
|
||||
} else if (isStackSlotValue(fromValue)) {
|
||||
setSpillSlot(label, to, (AllocatableValue) fromValue, debug);
|
||||
@ -672,8 +673,6 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
|
||||
IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
|
||||
setHint(label, to, from, debug);
|
||||
setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug);
|
||||
} else {
|
||||
throw GraalError.shouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,11 +252,16 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
|
||||
|
||||
Variable emitByteSwap(Value operand);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitArrayCompareTo(JavaKind kind1, JavaKind kind2, Value array1, Value array2, Value length1, Value length2) {
|
||||
throw GraalError.unimplemented("String.compareTo substitution is not implemented on this architecture");
|
||||
}
|
||||
|
||||
Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length);
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
default Variable emitStringIndexOf(Value sourcePointer, Value sourceCount, Value targetPointer, Value targetCount, int constantTargetCount) {
|
||||
throw GraalError.unimplemented();
|
||||
throw GraalError.unimplemented("String.indexOf substitution is not implemented on this architecture");
|
||||
}
|
||||
|
||||
void emitBlackhole(Value operand);
|
||||
|
@ -39,6 +39,13 @@ public class LIRPhaseSuite<C> extends LIRPhase<C> {
|
||||
phases = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an unmodifiable view on the phases in this suite.
|
||||
*/
|
||||
public List<LIRPhase<C>> getPhases() {
|
||||
return Collections.unmodifiableList(phases);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new phase at the beginning of this suite.
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user