8198969: Update Graal

Reviewed-by: kvn
This commit is contained in:
Igor Veresov 2018-03-16 22:59:32 -07:00
parent 2cfacefbb5
commit 089f83703a
189 changed files with 5747 additions and 1526 deletions

View File

@ -120,6 +120,7 @@ ifeq ($(INCLUDE_GRAAL), true)
SRC := \ SRC := \
$(SRC_DIR)/org.graalvm.word/src \ $(SRC_DIR)/org.graalvm.word/src \
$(SRC_DIR)/org.graalvm.collections/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.replacements.verifier/src \
$(SRC_DIR)/org.graalvm.compiler.api.replacements/src \ $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
$(SRC_DIR)/org.graalvm.compiler.code/src \ $(SRC_DIR)/org.graalvm.compiler.code/src \

View File

@ -195,11 +195,6 @@ public class AMD64Assembler extends Assembler {
private static final int VEX_W = 0x80; 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 class VexSimdPrefix {
private static final int VEX_SIMD_NONE = 0x0; private static final int VEX_SIMD_NONE = 0x0;
private static final int VEX_SIMD_66 = 0x1; private static final int VEX_SIMD_66 = 0x1;
@ -208,11 +203,44 @@ public class AMD64Assembler extends Assembler {
} }
private static class VexOpcode { 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 = 0x1;
private static final int VEX_OPCODE_0F_38 = 0x2; private static final int VEX_OPCODE_0F_38 = 0x2;
private static final int VEX_OPCODE_0F_3A = 0x3; 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; private AMD64InstructionAttr curAttributes;
AMD64InstructionAttr getCurAttributes() { AMD64InstructionAttr getCurAttributes() {
@ -873,6 +901,7 @@ public class AMD64Assembler extends Assembler {
opc = VexOpcode.VEX_OPCODE_0F_3A; opc = VexOpcode.VEX_OPCODE_0F_3A;
break; break;
default: default:
opc = VexOpcode.VEX_OPCODE_NONE;
isSimd = false; isSimd = false;
break; break;
} }
@ -1770,6 +1799,13 @@ public class AMD64Assembler extends Assembler {
emitOperandHelper(dst, src, 0); 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) { public final void bsrl(Register dst, Register src) {
int encode = prefixAndEncode(dst.encoding(), src.encoding()); int encode = prefixAndEncode(dst.encoding(), src.encoding());
emitByte(0x0F); emitByte(0x0F);
@ -1857,6 +1893,26 @@ public class AMD64Assembler extends Assembler {
emitByte(0xC0 | encode); 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() { public final void hlt() {
emitByte(0xF4); 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) { public final void lead(Register dst, AMD64Address src) {
prefix(src, dst); prefix(src, dst);
emitByte(0x8D); emitByte(0x8D);
@ -2050,6 +2132,15 @@ public class AMD64Assembler extends Assembler {
emitOperandHelper(dst, src, 0); 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) { public final void movl(AMD64Address dst, int imm32) {
prefix(dst); prefix(dst);
emitByte(0xC7); emitByte(0xC7);
@ -2291,6 +2382,10 @@ public class AMD64Assembler extends Assembler {
NOT.emit(this, DWORD, dst); NOT.emit(this, DWORD, dst);
} }
public final void notq(Register dst) {
NOT.emit(this, QWORD, dst);
}
@Override @Override
public final void ensureUniquePC() { public final void ensureUniquePC() {
nop(); nop();
@ -2540,7 +2635,7 @@ public class AMD64Assembler extends Assembler {
emitByte(0xC0 | encode); 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); assert supports(CPUFeature.SSE4_2);
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); 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); 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); 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); assert supports(CPUFeature.SSE4_2);
AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, target); 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); 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); 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) { public final void push(Register src) {
int encode = prefixAndEncode(src.encoding); int encode = prefixAndEncode(src.encoding);
emitByte(0x50 | encode); emitByte(0x50 | encode);
@ -2634,6 +2749,15 @@ public class AMD64Assembler extends Assembler {
emitByte(0xC0 | encode); 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) { public final void pslld(Register dst, int imm8) {
assert isUByte(imm8) : "invalid value"; assert isUByte(imm8) : "invalid value";
assert dst.getRegisterCategory().equals(AMD64.XMM); assert dst.getRegisterCategory().equals(AMD64.XMM);
@ -3843,4 +3967,11 @@ public class AMD64Assembler extends Assembler {
emitByte(0x0f); emitByte(0x0f);
emitByte(0x0b); emitByte(0x0b);
} }
public void lfence() {
emitByte(0x0f);
emitByte(0xae);
emitByte(0xe8);
}
} }

View File

@ -321,4 +321,61 @@ public class BytecodeDisassembler {
} }
// @formatter:on // @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;
}
} }

View File

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

View File

@ -25,6 +25,7 @@ package org.graalvm.compiler.core.amd64;
import org.graalvm.compiler.asm.amd64.AMD64Address.Scale; import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
import org.graalvm.compiler.core.common.LIRKind; 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.NodeClass;
import org.graalvm.compiler.graph.spi.Simplifiable; import org.graalvm.compiler.graph.spi.Simplifiable;
import org.graalvm.compiler.graph.spi.SimplifierTool; import org.graalvm.compiler.graph.spi.SimplifierTool;
@ -72,7 +73,7 @@ public class AMD64AddressNode extends AddressNode implements Simplifiable, LIRLo
} }
public void canonicalizeIndex(SimplifierTool tool) { public void canonicalizeIndex(SimplifierTool tool) {
if (index instanceof AddNode) { if (index instanceof AddNode && ((IntegerStamp) index.stamp(NodeView.DEFAULT)).getBits() == 64) {
AddNode add = (AddNode) index; AddNode add = (AddNode) index;
ValueNode valX = add.getX(); ValueNode valX = add.getX();
if (valX instanceof PhiNode) { if (valX instanceof PhiNode) {

View File

@ -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.LIRValueUtil.isJavaConstant;
import static org.graalvm.compiler.lir.amd64.AMD64Arithmetic.DREM; 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.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.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.LOG;
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.LOG10; 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.SIN;
import static org.graalvm.compiler.lir.amd64.AMD64MathIntrinsicUnaryOp.UnaryIntrinsicOpcode.TAN; 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.AMD64BinaryArithmetic;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; 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.AMD64RMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64RRMOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64Shift; 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.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp; 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.LIRKind;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.FloatConvert; import org.graalvm.compiler.core.common.calc.FloatConvert;
import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.ConstantValue; 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.AMD64SignExtendOp;
import org.graalvm.compiler.lir.amd64.AMD64Unary; import org.graalvm.compiler.lir.amd64.AMD64Unary;
import org.graalvm.compiler.lir.gen.ArithmeticLIRGenerator; 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;
import jdk.vm.ci.amd64.AMD64.CPUFeature; 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.CodeUtil;
import jdk.vm.ci.code.Register; import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterValue; import jdk.vm.ci.code.RegisterValue;
import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.JavaConstant; 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.VMConstant;
import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.Value;
import jdk.vm.ci.meta.ValueKind; import jdk.vm.ci.meta.ValueKind;
import jdk.vm.ci.code.TargetDescription;
/** /**
* This class implements the AMD64 specific portion of the LIR generator. * 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)); 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 @Override
public Variable emitNegate(Value inputVal) { public Variable emitNegate(Value inputVal) {
AllocatableValue input = getLIRGen().asAllocatable(inputVal); AllocatableValue input = getLIRGen().asAllocatable(inputVal);
@ -1042,33 +1077,49 @@ public class AMD64ArithmeticLIRGenerator extends ArithmeticLIRGenerator implemen
@Override @Override
public Value emitMathLog(Value input, boolean base10) { public Value emitMathLog(Value input, boolean base10) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); LIRGenerator gen = getLIRGen();
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); Variable result = maths.emitLog(gen, input, base10);
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input), stackSlot)); 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; return result;
} }
@Override @Override
public Value emitMathCos(Value input) { public Value emitMathCos(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); LIRGenerator gen = getLIRGen();
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); Variable result = maths.emitCos(gen, input);
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), COS, result, getLIRGen().asAllocatable(input), stackSlot)); 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; return result;
} }
@Override @Override
public Value emitMathSin(Value input) { public Value emitMathSin(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); LIRGenerator gen = getLIRGen();
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); Variable result = maths.emitSin(gen, input);
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), SIN, result, getLIRGen().asAllocatable(input), stackSlot)); 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; return result;
} }
@Override @Override
public Value emitMathTan(Value input) { public Value emitMathTan(Value input) {
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); LIRGenerator gen = getLIRGen();
AllocatableValue stackSlot = getLIRGen().getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(AMD64Kind.QWORD)); Variable result = maths.emitTan(gen, input);
getLIRGen().append(new AMD64MathIntrinsicUnaryOp(getAMD64LIRGen(), TAN, result, getLIRGen().asAllocatable(input), stackSlot)); 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; return result;
} }

View File

@ -59,6 +59,7 @@ import org.graalvm.compiler.lir.SwitchStrategy;
import org.graalvm.compiler.lir.Variable; import org.graalvm.compiler.lir.Variable;
import org.graalvm.compiler.lir.amd64.AMD64AddressValue; import org.graalvm.compiler.lir.amd64.AMD64AddressValue;
import org.graalvm.compiler.lir.amd64.AMD64ArithmeticLIRGeneratorTool; 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.AMD64ArrayEqualsOp;
import org.graalvm.compiler.lir.amd64.AMD64Binary; import org.graalvm.compiler.lir.amd64.AMD64Binary;
import org.graalvm.compiler.lir.amd64.AMD64BinaryConsumer; 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.ReturnOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp; import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.amd64.AMD64ControlFlow.TableSwitchOp; 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;
import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp; import org.graalvm.compiler.lir.amd64.AMD64Move.CompareAndSwapOp;
import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp; import org.graalvm.compiler.lir.amd64.AMD64Move.MembarOp;
@ -489,6 +491,20 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
return result; 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 @Override
public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) { public Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length) {
Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD)); Variable result = newVariable(LIRKind.value(AMD64Kind.DWORD));
@ -554,4 +570,8 @@ public abstract class AMD64LIRGenerator extends LIRGenerator {
public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) { public LIRInstruction createZapArgumentSpace(StackSlot[] zappedStack, JavaConstant[] zapValues) {
return new AMD64ZapStackOp(zappedStack, zapValues); return new AMD64ZapStackOp(zappedStack, zapValues);
} }
public void emitLFence() {
append(new AMD64LFenceOp());
}
} }

View File

@ -23,6 +23,8 @@
package org.graalvm.compiler.core.amd64; 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.core.gen.NodeLIRBuilder;
import org.graalvm.compiler.debug.GraalError; import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.LIRFrameState; 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.ValueNode;
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode; import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
import org.graalvm.compiler.nodes.calc.IntegerDivRemNode.Op; 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.amd64.AMD64;
import jdk.vm.ci.meta.AllocatableValue; import jdk.vm.ci.meta.AllocatableValue;
@ -44,6 +51,13 @@ import jdk.vm.ci.meta.Value;
public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder { 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) { public AMD64NodeLIRBuilder(StructuredGraph graph, LIRGeneratorTool gen, AMD64NodeMatchRules nodeMatchRules) {
super(graph, gen, nodeMatchRules); super(graph, gen, nodeMatchRules);
} }
@ -121,4 +135,21 @@ public abstract class AMD64NodeLIRBuilder extends NodeLIRBuilder {
public AMD64LIRGenerator getLIRGeneratorTool() { public AMD64LIRGenerator getLIRGeneratorTool() {
return (AMD64LIRGenerator) gen; 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();
}
}
}
} }

View File

@ -259,6 +259,9 @@ public final class GraalOptions {
@Option(help = "", type = OptionType.Debug) @Option(help = "", type = OptionType.Debug)
public static final OptionKey<Boolean> OptDevirtualizeInvokesOptimistically = new OptionKey<>(true); 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) @Option(help = "Allow backend to match complex expressions.", type = OptionType.Debug)
public static final OptionKey<Boolean> MatchExpressions = new OptionKey<>(true); 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) @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false); public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
@Option(help = "Enable tracing of inlining decision.", type = OptionType.Debug)
@Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug) public static final OptionKey<Boolean> TraceInlining = new OptionKey<>(false);
public static final OptionKey<TraceInliningMode> TraceInlining = new OptionKey<>(TraceInliningMode.None);
} }

View File

@ -84,7 +84,7 @@ public final class BiDirectionalTraceBuilder {
AbstractBlockBase<?> block = worklist.pollFirst(); AbstractBlockBase<?> block = worklist.pollFirst();
assert block != null; assert block != null;
if (!processed(block)) { if (!processed(block)) {
Trace trace = new Trace(startTrace(debug, block)); Trace trace = new Trace(findTrace(debug, block));
for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) { for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
blockToTrace[traceBlock.getId()] = trace; blockToTrace[traceBlock.getId()] = trace;
} }
@ -101,13 +101,13 @@ public final class BiDirectionalTraceBuilder {
* @param debug * @param debug
*/ */
@SuppressWarnings("try") @SuppressWarnings("try")
private Collection<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) { private Collection<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> initBlock) {
ArrayDeque<AbstractBlockBase<?>> trace = new ArrayDeque<>(); 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:")) { try (Indent indentFront = debug.logAndIndent("Head:")) {
for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectPredecessor(currentBlock)) { for (AbstractBlockBase<?> block = initBlock; block != null; block = selectPredecessor(block)) {
addBlockToTrace(debug, currentBlock); addBlockToTrace(debug, block);
trace.addFirst(currentBlock); trace.addFirst(block);
} }
} }
/* Number head blocks. Can not do this in the loop as we go backwards. */ /* 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:")) { try (Indent indentBack = debug.logAndIndent("Tail:")) {
for (AbstractBlockBase<?> currentBlock = selectSuccessor(block); currentBlock != null; currentBlock = selectSuccessor(currentBlock)) { for (AbstractBlockBase<?> block = selectSuccessor(initBlock); block != null; block = selectSuccessor(block)) {
addBlockToTrace(debug, currentBlock); addBlockToTrace(debug, block);
trace.addLast(currentBlock); trace.addLast(block);
/* This time we can number the blocks immediately as we go forwards. */ /* 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; return trace;
} }
private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> currentBlock) { private void addBlockToTrace(DebugContext debug, AbstractBlockBase<?> block) {
debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); debug.log("add %s (prob: %f)", block, block.probability());
processed.set(currentBlock.getId()); processed.set(block.getId());
} }
/** /**
* @return The unprocessed predecessor with the highest probability, or {@code null}. * @return The unprocessed predecessor with the highest probability, or {@code null}.
*/ */
private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> currentBlock) { private AbstractBlockBase<?> selectPredecessor(AbstractBlockBase<?> block) {
AbstractBlockBase<?> next = null; AbstractBlockBase<?> next = null;
for (AbstractBlockBase<?> pred : currentBlock.getPredecessors()) { for (AbstractBlockBase<?> pred : block.getPredecessors()) {
if (!processed(pred) && !isBackEdge(pred, currentBlock) && (next == null || pred.probability() > next.probability())) { if (!processed(pred) && !isBackEdge(pred, block) && (next == null || pred.probability() > next.probability())) {
next = pred; next = pred;
} }
} }
@ -155,9 +155,9 @@ public final class BiDirectionalTraceBuilder {
/** /**
* @return The unprocessed successor with the highest probability, or {@code null}. * @return The unprocessed successor with the highest probability, or {@code null}.
*/ */
private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> currentBlock) { private AbstractBlockBase<?> selectSuccessor(AbstractBlockBase<?> block) {
AbstractBlockBase<?> next = null; AbstractBlockBase<?> next = null;
for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) { for (AbstractBlockBase<?> succ : block.getSuccessors()) {
if (!processed(succ) && (next == null || succ.probability() > next.probability())) { if (!processed(succ) && (next == null || succ.probability() > next.probability())) {
next = succ; next = succ;
} }

View File

@ -33,7 +33,7 @@ import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.Indent; 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 { public final class UniDirectionalTraceBuilder {
@ -87,7 +87,7 @@ public final class UniDirectionalTraceBuilder {
AbstractBlockBase<?> block = worklist.poll(); AbstractBlockBase<?> block = worklist.poll();
assert block != null; assert block != null;
if (!processed(block)) { if (!processed(block)) {
Trace trace = new Trace(startTrace(debug, block)); Trace trace = new Trace(findTrace(debug, block));
for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) { for (AbstractBlockBase<?> traceBlock : trace.getBlocks()) {
blockToTrace[traceBlock.getId()] = trace; blockToTrace[traceBlock.getId()] = trace;
} }
@ -102,17 +102,17 @@ public final class UniDirectionalTraceBuilder {
* Build a new trace starting at {@code block}. * Build a new trace starting at {@code block}.
*/ */
@SuppressWarnings("try") @SuppressWarnings("try")
private List<AbstractBlockBase<?>> startTrace(DebugContext debug, AbstractBlockBase<?> block) { private List<AbstractBlockBase<?>> findTrace(DebugContext debug, AbstractBlockBase<?> traceStart) {
assert checkPredecessorsProcessed(block); assert checkPredecessorsProcessed(traceStart);
ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>(); ArrayList<AbstractBlockBase<?>> trace = new ArrayList<>();
int blockNumber = 0; int blockNumber = 0;
try (Indent i = debug.logAndIndent("StartTrace: %s", block)) { try (Indent i = debug.logAndIndent("StartTrace: %s", traceStart)) {
for (AbstractBlockBase<?> currentBlock = block; currentBlock != null; currentBlock = selectNext(currentBlock)) { for (AbstractBlockBase<?> block = traceStart; block != null; block = selectNext(block)) {
debug.log("add %s (prob: %f)", currentBlock, currentBlock.probability()); debug.log("add %s (prob: %f)", block, block.probability());
processed.set(currentBlock.getId()); processed.set(block.getId());
trace.add(currentBlock); trace.add(block);
unblock(currentBlock); unblock(block);
currentBlock.setLinearScanNumber(blockNumber++); block.setLinearScanNumber(blockNumber++);
} }
} }
return trace; return trace;
@ -120,11 +120,7 @@ public final class UniDirectionalTraceBuilder {
private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) { private boolean checkPredecessorsProcessed(AbstractBlockBase<?> block) {
for (AbstractBlockBase<?> pred : block.getPredecessors()) { for (AbstractBlockBase<?> pred : block.getPredecessors()) {
if (!processed(pred)) { assert processed(pred) : "Predecessor unscheduled: " + pred;
assert false : "Predecessor unscheduled: " + pred;
return false;
}
} }
return true; 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 * Decrease the {@link #blocked} count for all predecessors and add them to the worklist once
* the count reaches 0. * the count reaches 0.
*/ */
private void unblock(AbstractBlockBase<?> currentBlock) { private void unblock(AbstractBlockBase<?> block) {
for (AbstractBlockBase<?> successor : currentBlock.getSuccessors()) { for (AbstractBlockBase<?> successor : block.getSuccessors()) {
if (!processed(successor)) { if (!processed(successor)) {
int blockCount = --blocked[successor.getId()]; int blockCount = --blocked[successor.getId()];
assert blockCount >= 0; assert blockCount >= 0;
@ -148,11 +144,11 @@ public final class UniDirectionalTraceBuilder {
/** /**
* @return The unprocessed predecessor with the highest probability, or {@code null}. * @return The unprocessed predecessor with the highest probability, or {@code null}.
*/ */
private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> currentBlock) { private AbstractBlockBase<?> selectNext(AbstractBlockBase<?> block) {
AbstractBlockBase<?> next = null; AbstractBlockBase<?> next = null;
for (AbstractBlockBase<?> succ : currentBlock.getSuccessors()) { for (AbstractBlockBase<?> successor : block.getSuccessors()) {
if (!processed(succ) && (next == null || succ.probability() > next.probability())) { if (!processed(successor) && (next == null || successor.probability() > next.probability())) {
next = succ; next = successor;
} }
} }
return next; return next;

View File

@ -191,8 +191,6 @@ public abstract class AbstractObjectStamp extends AbstractPointerStamp {
boolean joinExactType = exactType || other.exactType; boolean joinExactType = exactType || other.exactType;
if (Objects.equals(type, other.type)) { if (Objects.equals(type, other.type)) {
joinType = type; joinType = type;
} else if (type == null && other.type == null) {
joinType = null;
} else if (type == null) { } else if (type == null) {
joinType = other.type; joinType = other.type;
} else if (other.type == null) { } else if (other.type == null) {

View File

@ -176,11 +176,15 @@ public class FloatStamp extends PrimitiveStamp {
StringBuilder str = new StringBuilder(); StringBuilder str = new StringBuilder();
str.append('f'); str.append('f');
str.append(getBits()); str.append(getBits());
str.append(nonNaN ? "!" : ""); if (hasValues()) {
if (lowerBound == upperBound) { str.append(nonNaN ? "!" : "");
str.append(" [").append(lowerBound).append(']'); if (lowerBound == upperBound) {
} else if (lowerBound != Double.NEGATIVE_INFINITY || upperBound != Double.POSITIVE_INFINITY) { str.append(" [").append(lowerBound).append(']');
str.append(" [").append(lowerBound).append(" - ").append(upperBound).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(); return str.toString();
} }
@ -200,6 +204,12 @@ public class FloatStamp extends PrimitiveStamp {
if (otherStamp == this) { if (otherStamp == this) {
return this; return this;
} }
if (isEmpty()) {
return this;
}
if (otherStamp.isEmpty()) {
return otherStamp;
}
FloatStamp other = (FloatStamp) otherStamp; FloatStamp other = (FloatStamp) otherStamp;
assert getBits() == other.getBits(); assert getBits() == other.getBits();
double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max); double meetUpperBound = meetBounds(upperBound, other.upperBound, Math::max);
@ -383,6 +393,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s) { public Stamp foldStamp(Stamp s) {
if (s.isEmpty()) {
return s;
}
FloatStamp stamp = (FloatStamp) s; FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp); Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) { if (folded != null) {
@ -412,6 +425,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -454,6 +473,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -496,6 +521,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -544,6 +575,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -586,6 +623,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -615,6 +658,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s) { public Stamp foldStamp(Stamp s) {
if (s.isEmpty()) {
return s;
}
FloatStamp stamp = (FloatStamp) s; FloatStamp stamp = (FloatStamp) s;
JavaConstant constant = stamp.asConstant(); JavaConstant constant = stamp.asConstant();
if (constant != null) { if (constant != null) {
@ -653,6 +699,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -701,6 +753,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -747,6 +805,12 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s1, Stamp s2) { public Stamp foldStamp(Stamp s1, Stamp s2) {
if (s1.isEmpty()) {
return s1;
}
if (s2.isEmpty()) {
return s2;
}
FloatStamp stamp1 = (FloatStamp) s1; FloatStamp stamp1 = (FloatStamp) s1;
FloatStamp stamp2 = (FloatStamp) s2; FloatStamp stamp2 = (FloatStamp) s2;
Stamp folded = maybeFoldConstant(this, stamp1, stamp2); Stamp folded = maybeFoldConstant(this, stamp1, stamp2);
@ -789,6 +853,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s) { public Stamp foldStamp(Stamp s) {
if (s.isEmpty()) {
return s;
}
FloatStamp stamp = (FloatStamp) s; FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp); Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) { if (folded != null) {
@ -818,6 +885,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s) { public Stamp foldStamp(Stamp s) {
if (s.isEmpty()) {
return s;
}
FloatStamp stamp = (FloatStamp) s; FloatStamp stamp = (FloatStamp) s;
Stamp folded = maybeFoldConstant(this, stamp); Stamp folded = maybeFoldConstant(this, stamp);
if (folded != null) { if (folded != null) {
@ -839,6 +909,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Int);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 32; assert floatStamp.getBits() == 32;
boolean mustHaveZero = !floatStamp.isNonNaN(); boolean mustHaveZero = !floatStamp.isNonNaN();
@ -865,6 +938,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Long);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 32; assert floatStamp.getBits() == 32;
boolean mustHaveZero = !floatStamp.isNonNaN(); boolean mustHaveZero = !floatStamp.isNonNaN();
@ -891,6 +967,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Int);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 64; assert floatStamp.getBits() == 64;
boolean mustHaveZero = !floatStamp.isNonNaN(); boolean mustHaveZero = !floatStamp.isNonNaN();
@ -917,6 +996,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Long);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 64; assert floatStamp.getBits() == 64;
boolean mustHaveZero = !floatStamp.isNonNaN(); boolean mustHaveZero = !floatStamp.isNonNaN();
@ -943,6 +1025,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Double);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 32; assert floatStamp.getBits() == 32;
return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN()); return StampFactory.forFloat(JavaKind.Double, floatStamp.lowerBound(), floatStamp.upperBound(), floatStamp.isNonNaN());
@ -959,6 +1044,9 @@ public class FloatStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return StampFactory.empty(JavaKind.Float);
}
FloatStamp floatStamp = (FloatStamp) stamp; FloatStamp floatStamp = (FloatStamp) stamp;
assert floatStamp.getBits() == 64; assert floatStamp.getBits() == 64;
return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN()); return StampFactory.forFloat(JavaKind.Float, (float) floatStamp.lowerBound(), (float) floatStamp.upperBound(), floatStamp.isNonNaN());

View File

@ -122,11 +122,11 @@ public final class IntegerStamp extends PrimitiveStamp {
return new IntegerStamp(bits, lowerBoundTmp, upperBoundTmp, defaultMask & (downMask | boundedDownMask), defaultMask & upMask & boundedUpMask); 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; 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) { if (significantBit(bits, upMask) == 0) {
// Value is always positive. Minimum value always positive. // Value is always positive. Minimum value always positive.
assert significantBit(bits, downMask) == 0; 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) { if (significantBit(bits, downMask) == 1) {
// Value is always negative. Maximum value always negative. // Value is always negative. Maximum value always negative.
assert significantBit(bits, upMask) == 1; assert significantBit(bits, upMask) == 1;
@ -330,6 +330,12 @@ public final class IntegerStamp extends PrimitiveStamp {
if (otherStamp == this) { if (otherStamp == this) {
return this; return this;
} }
if (isEmpty()) {
return otherStamp;
}
if (otherStamp.isEmpty()) {
return this;
}
IntegerStamp other = (IntegerStamp) otherStamp; IntegerStamp other = (IntegerStamp) otherStamp;
return createStamp(other, Math.max(upperBound, other.upperBound), Math.min(lowerBound, other.lowerBound), downMask & other.downMask, upMask | other.upMask); 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); 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; long mask = lowerBound | upperBound;
if (mask == 0) { if (mask == 0) {
return 0; return 0;
@ -595,6 +601,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp s) { public Stamp foldStamp(Stamp s) {
if (s.isEmpty()) {
return s;
}
IntegerStamp stamp = (IntegerStamp) s; IntegerStamp stamp = (IntegerStamp) s;
int bits = stamp.getBits(); int bits = stamp.getBits();
if (stamp.lowerBound == stamp.upperBound) { if (stamp.lowerBound == stamp.upperBound) {
@ -622,6 +631,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
@ -715,6 +730,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
@ -885,6 +906,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
JavaKind javaKind = a.getStackKind(); JavaKind javaKind = a.getStackKind();
@ -952,6 +979,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
JavaKind javaKind = a.getStackKind(); JavaKind javaKind = a.getStackKind();
@ -1046,6 +1079,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits(); assert a.getBits() == b.getBits();
@ -1083,6 +1122,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits(); assert a.getBits() == b.getBits();
@ -1121,6 +1166,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp) { public Stamp foldStamp(Stamp stamp) {
if (stamp.isEmpty()) {
return stamp;
}
IntegerStamp integerStamp = (IntegerStamp) stamp; IntegerStamp integerStamp = (IntegerStamp) stamp;
int bits = integerStamp.getBits(); int bits = integerStamp.getBits();
long defaultMask = CodeUtil.mask(bits); long defaultMask = CodeUtil.mask(bits);
@ -1140,6 +1188,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits(); assert a.getBits() == b.getBits();
@ -1167,6 +1221,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits(); assert a.getBits() == b.getBits();
@ -1192,6 +1252,12 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp stamp1, Stamp stamp2) { public Stamp foldStamp(Stamp stamp1, Stamp stamp2) {
if (stamp1.isEmpty()) {
return stamp1;
}
if (stamp2.isEmpty()) {
return stamp2;
}
IntegerStamp a = (IntegerStamp) stamp1; IntegerStamp a = (IntegerStamp) stamp1;
IntegerStamp b = (IntegerStamp) stamp2; IntegerStamp b = (IntegerStamp) stamp2;
assert a.getBits() == b.getBits(); assert a.getBits() == b.getBits();
@ -1269,8 +1335,7 @@ public final class IntegerStamp extends PrimitiveStamp {
upMask |= value.upMask() << (i & shiftMask); upMask |= value.upMask() << (i & shiftMask);
} }
} }
Stamp result = IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask); return IntegerStamp.stampForMask(bits, downMask, upMask & defaultMask);
return result;
} }
return value.unrestricted(); return value.unrestricted();
} }
@ -1392,6 +1457,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp input) { public Stamp foldStamp(Stamp input) {
if (input.isEmpty()) {
return input;
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
int bits = stamp.getBits(); int bits = stamp.getBits();
if (stamp.lowerBound == stamp.upperBound) { if (stamp.lowerBound == stamp.upperBound) {
@ -1419,6 +1487,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
if (input.isEmpty()) {
return StampFactory.forInteger(resultBits).empty();
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert inputBits == stamp.getBits(); assert inputBits == stamp.getBits();
assert inputBits <= resultBits; assert inputBits <= resultBits;
@ -1458,6 +1529,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
if (input.isEmpty()) {
return StampFactory.forInteger(resultBits).empty();
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert inputBits == stamp.getBits(); assert inputBits == stamp.getBits();
assert inputBits <= resultBits; assert inputBits <= resultBits;
@ -1487,6 +1561,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(int inputBits, int resultBits, Stamp input) { public Stamp foldStamp(int inputBits, int resultBits, Stamp input) {
if (input.isEmpty()) {
return StampFactory.forInteger(resultBits).empty();
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert inputBits == stamp.getBits(); assert inputBits == stamp.getBits();
assert resultBits <= inputBits; assert resultBits <= inputBits;
@ -1526,6 +1603,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp input) { public Stamp foldStamp(Stamp input) {
if (input.isEmpty()) {
return StampFactory.empty(JavaKind.Float);
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert stamp.getBits() == 32; assert stamp.getBits() == 32;
float lowerBound = stamp.lowerBound(); float lowerBound = stamp.lowerBound();
@ -1544,6 +1624,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp input) { public Stamp foldStamp(Stamp input) {
if (input.isEmpty()) {
return StampFactory.empty(JavaKind.Float);
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert stamp.getBits() == 64; assert stamp.getBits() == 64;
float lowerBound = stamp.lowerBound(); float lowerBound = stamp.lowerBound();
@ -1562,6 +1645,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp input) { public Stamp foldStamp(Stamp input) {
if (input.isEmpty()) {
return StampFactory.empty(JavaKind.Double);
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert stamp.getBits() == 32; assert stamp.getBits() == 32;
double lowerBound = stamp.lowerBound(); double lowerBound = stamp.lowerBound();
@ -1580,6 +1666,9 @@ public final class IntegerStamp extends PrimitiveStamp {
@Override @Override
public Stamp foldStamp(Stamp input) { public Stamp foldStamp(Stamp input) {
if (input.isEmpty()) {
return StampFactory.empty(JavaKind.Double);
}
IntegerStamp stamp = (IntegerStamp) input; IntegerStamp stamp = (IntegerStamp) input;
assert stamp.getBits() == 64; assert stamp.getBits() == 64;
double lowerBound = stamp.lowerBound(); double lowerBound = stamp.lowerBound();

View File

@ -161,6 +161,10 @@ public class StampFactory {
return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits)); 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) { public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits)); return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
} }

View File

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

View File

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

View File

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

View File

@ -30,6 +30,7 @@ import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.loop.InductionVariable; import org.graalvm.compiler.loop.InductionVariable;
import org.graalvm.compiler.loop.LoopsData; import org.graalvm.compiler.loop.LoopsData;
import org.graalvm.compiler.nodeinfo.NodeInfo; import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView; import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.ValueNode;
@ -52,25 +53,47 @@ public class CountedLoopTest extends GraalCompilerTest {
ValueNode get(InductionVariable iv); 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. * 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; return iv;
} }
private static class Result { private static class Result {
public int extremum; public long extremum;
public int exitValue; public long exitValue;
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;
int result = 1; int result = 1;
result = prime * result + exitValue; result = prime * result + Long.hashCode(exitValue);
result = prime * result + extremum; result = prime * result + Long.hashCode(extremum);
return result; return result;
} }
@ -95,7 +118,7 @@ public class CountedLoopTest extends GraalCompilerTest {
Result ret = new Result(); Result ret = new Result();
for (i = start; i < limit; i += inc) { for (i = start; i < limit; i += inc) {
GraalDirectives.controlFlowAnchor(); GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, i); ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
} }
ret.exitValue = get(InductionVariable::exitValueNode, i); ret.exitValue = get(InductionVariable::exitValueNode, i);
return ret; return ret;
@ -103,32 +126,42 @@ public class CountedLoopTest extends GraalCompilerTest {
@Test @Test
public void increment1() { public void increment1() {
test("incrementSnippet", 0, 256, 1); testCounted("incrementSnippet", 0, 256, 1);
} }
@Test @Test
public void increment2() { public void increment2() {
test("incrementSnippet", 0, 256, 2); testCounted("incrementSnippet", 0, 256, 2);
} }
@Test @Test
public void increment3() { public void increment3() {
test("incrementSnippet", 0, 256, 3); testCounted("incrementSnippet", 0, 256, 3);
} }
@Test @Test
public void increment4() { public void increment4() {
test("incrementSnippet", -10, Integer.MAX_VALUE, 1); testCounted("incrementSnippet", -10, 1, Integer.MAX_VALUE);
} }
@Test @Test
public void increment5() { public void increment5() {
test("incrementSnippet", 256, 256, 1); testCounted("incrementSnippet", 256, 256, 1);
} }
@Test @Test
public void increment6() { 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) { public static Result incrementEqSnippet(int start, int limit, int step) {
@ -137,7 +170,7 @@ public class CountedLoopTest extends GraalCompilerTest {
Result ret = new Result(); Result ret = new Result();
for (i = start; i <= limit; i += inc) { for (i = start; i <= limit; i += inc) {
GraalDirectives.controlFlowAnchor(); GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, i); ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
} }
ret.exitValue = get(InductionVariable::exitValueNode, i); ret.exitValue = get(InductionVariable::exitValueNode, i);
return ret; return ret;
@ -145,32 +178,42 @@ public class CountedLoopTest extends GraalCompilerTest {
@Test @Test
public void incrementEq1() { public void incrementEq1() {
test("incrementEqSnippet", 0, 256, 1); testCounted("incrementEqSnippet", 0, 256, 1);
} }
@Test @Test
public void incrementEq2() { public void incrementEq2() {
test("incrementEqSnippet", 0, 256, 2); testCounted("incrementEqSnippet", 0, 256, 2);
} }
@Test @Test
public void incrementEq3() { public void incrementEq3() {
test("incrementEqSnippet", 0, 256, 3); testCounted("incrementEqSnippet", 0, 256, 3);
} }
@Test @Test
public void incrementEq4() { public void incrementEq4() {
test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE); testCounted("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
} }
@Test @Test
public void incrementEq5() { public void incrementEq5() {
test("incrementEqSnippet", 256, 256, 1); testCounted("incrementEqSnippet", 256, 256, 1);
} }
@Test @Test
public void incrementEq6() { 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) { public static Result decrementSnippet(int start, int limit, int step) {
@ -179,7 +222,7 @@ public class CountedLoopTest extends GraalCompilerTest {
Result ret = new Result(); Result ret = new Result();
for (i = start; i > limit; i -= dec) { for (i = start; i > limit; i -= dec) {
GraalDirectives.controlFlowAnchor(); GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, i); ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
} }
ret.exitValue = get(InductionVariable::exitValueNode, i); ret.exitValue = get(InductionVariable::exitValueNode, i);
return ret; return ret;
@ -187,17 +230,27 @@ public class CountedLoopTest extends GraalCompilerTest {
@Test @Test
public void decrement1() { public void decrement1() {
test("decrementSnippet", 256, 0, 1); testCounted("decrementSnippet", 256, 0, 1);
} }
@Test @Test
public void decrement2() { public void decrement2() {
test("decrementSnippet", 256, 0, 2); testCounted("decrementSnippet", 256, 0, 2);
} }
@Test @Test
public void decrement3() { 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) { public static Result decrementEqSnippet(int start, int limit, int step) {
@ -206,7 +259,7 @@ public class CountedLoopTest extends GraalCompilerTest {
Result ret = new Result(); Result ret = new Result();
for (i = start; i >= limit; i -= dec) { for (i = start; i >= limit; i -= dec) {
GraalDirectives.controlFlowAnchor(); GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, i); ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, i);
} }
ret.exitValue = get(InductionVariable::exitValueNode, i); ret.exitValue = get(InductionVariable::exitValueNode, i);
return ret; return ret;
@ -214,22 +267,32 @@ public class CountedLoopTest extends GraalCompilerTest {
@Test @Test
public void decrementEq1() { public void decrementEq1() {
test("decrementEqSnippet", 256, 0, 1); testCounted("decrementEqSnippet", 256, 0, 1);
} }
@Test @Test
public void decrementEq2() { public void decrementEq2() {
test("decrementEqSnippet", 256, 0, 2); testCounted("decrementEqSnippet", 256, 0, 2);
} }
@Test @Test
public void decrementEq3() { public void decrementEq3() {
test("decrementEqSnippet", 256, 0, 3); testCounted("decrementEqSnippet", 256, 0, 3);
} }
@Test @Test
public void decrementEq4() { 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() { public static Result twoVariablesSnippet() {
@ -238,7 +301,7 @@ public class CountedLoopTest extends GraalCompilerTest {
for (int i = 0; i < 1024; i++) { for (int i = 0; i < 1024; i++) {
j += 5; j += 5;
GraalDirectives.controlFlowAnchor(); GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, j); ret.extremum = get(InductionVariable::extremumNode, InductionVariable::constantExtremum, InductionVariable::isConstantExtremum, j);
} }
ret.exitValue = get(InductionVariable::exitValueNode, j); ret.exitValue = get(InductionVariable::exitValueNode, j);
return ret; return ret;
@ -246,7 +309,83 @@ public class CountedLoopTest extends GraalCompilerTest {
@Test @Test
public void testTwoVariables() { 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) @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); public static final NodeClass<IVPropertyNode> TYPE = NodeClass.create(IVPropertyNode.class);
private final IVProperty property; private final IVProperty property;
private final StaticIVProperty staticProperty;
private final IVPredicate staticCheck;
@Input private ValueNode iv; @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()); super(TYPE, iv.stamp(NodeView.DEFAULT).unrestricted());
this.property = property; this.property = property;
this.staticProperty = staticProperty;
this.staticCheck = staticCheck;
this.iv = iv; this.iv = iv;
} }
public void rewrite(LoopsData loops) { public void rewrite(LoopsData loops) {
InductionVariable inductionVariable = loops.getInductionVariable(iv); InductionVariable inductionVariable = loops.getInductionVariable(iv);
assert inductionVariable != null; 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); replaceAtUsagesAndDelete(node);
} }
@ -279,7 +431,13 @@ public class CountedLoopTest extends GraalCompilerTest {
@Override @Override
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
Registration r = new Registration(invocationPlugins, CountedLoopTest.class); 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 @Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) { public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg1, ValueNode arg2) {
IVProperty property = null; IVProperty property = null;
@ -287,14 +445,36 @@ public class CountedLoopTest extends GraalCompilerTest {
property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant()); property = getSnippetReflection().asObject(IVProperty.class, arg1.asJavaConstant());
} }
if (property != null) { 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; return true;
} else { } else {
return false; return false;
} }
} }
}); });
super.registerInvocationPlugins(invocationPlugins);
} }
@Override @Override
@ -308,37 +488,17 @@ public class CountedLoopTest extends GraalCompilerTest {
return true; return true;
} }
public static Result incrementNeqSnippet(int limit) { private Object[] argsToBind;
int i;
int posLimit = ((limit - 1) & 0xFFFF) + 1; // make sure limit is always strictly positive @Override
Result ret = new Result(); protected Object[] getArgumentToBind() {
for (i = 0; i != posLimit; i++) { return argsToBind;
GraalDirectives.controlFlowAnchor();
ret.extremum = get(InductionVariable::extremumNode, i);
}
ret.exitValue = get(InductionVariable::exitValueNode, i);
return ret;
} }
@Test public void testCounted(String snippetName, Object... args) {
public void decrementNeq() { test(snippetName, args);
test("decrementNeqSnippet", 256); argsToBind = args;
} test(snippetName, args);
argsToBind = null;
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);
} }
} }

View File

@ -22,6 +22,7 @@
*/ */
package org.graalvm.compiler.core.test; 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 jdk.vm.ci.runtime.JVMCICompiler.INVOCATION_ENTRY_BCI;
import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; 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.Set;
import java.util.function.Supplier; import java.util.function.Supplier;
import jdk.vm.ci.meta.JavaConstant;
import org.graalvm.compiler.api.directives.GraalDirectives; import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.api.test.Graal; import org.graalvm.compiler.api.test.Graal;
@ -931,7 +933,8 @@ public abstract class GraalCompilerTest extends GraalTest {
*/ */
@SuppressWarnings("try") @SuppressWarnings("try")
protected InstalledCode getCode(final ResolvedJavaMethod installedCodeOwner, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { 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); InstalledCode cached = cache.get(installedCodeOwner);
if (cached != null) { if (cached != null) {
if (cached.isValid()) { 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)")); throw new GraalError("Could not install code for " + installedCodeOwner.format("%H.%n(%p)"));
} }
} catch (BailoutException e) { } 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) // retry (if there is no predefined graph)
TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id)); TTY.println(String.format("Restart compilation %s (%s) due to a non-permanent bailout!", installedCodeOwner, id));
continue; continue;
@ -978,7 +981,7 @@ public abstract class GraalCompilerTest extends GraalTest {
throw debug.handle(e); throw debug.handle(e);
} }
if (!forceCompile) { if (useCache) {
cache.put(installedCodeOwner, installedCode); cache.put(installedCodeOwner, installedCode);
} }
return installedCode; return installedCode;
@ -1243,12 +1246,33 @@ public abstract class GraalCompilerTest extends GraalTest {
DebugContext debug = graph.getDebug(); DebugContext debug = graph.getDebug();
try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) { try (DebugContext.Scope ds = debug.scope("Parsing", javaMethod, graph)) {
graphBuilderSuite.apply(graph, getDefaultHighTierContext()); graphBuilderSuite.apply(graph, getDefaultHighTierContext());
Object[] args = getArgumentToBind();
if (args != null) {
bindArguments(graph, args);
}
return graph; return graph;
} catch (Throwable e) { } catch (Throwable e) {
throw debug.handle(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() { protected PhaseSuite<HighTierContext> getEagerGraphBuilderSuite() {
return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true)); return getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withEagerResolving(true).withUnresolvedIsError(true));
} }

View File

@ -77,8 +77,7 @@ public class GraphEncoderTest extends GraalCompilerTest {
} }
for (StructuredGraph originalGraph : originalGraphs) { for (StructuredGraph originalGraph : originalGraphs) {
EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph.getAssumptions(), EncodedGraph encodedGraph = new EncodedGraph(encoder.getEncoding(), startOffsets.get(originalGraph), encoder.getObjects(), encoder.getNodeClasses(), originalGraph);
originalGraph.getMethods());
GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch); GraphEncoder.verifyEncoding(originalGraph, encodedGraph, getTarget().arch);
} }
} }

View File

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

View File

@ -74,9 +74,9 @@ public class TrivialInliningExplosionTest extends GraalCompilerTest {
int afterCompileSize = lastCompiledGraph.getNodeCount(); int afterCompileSize = lastCompiledGraph.getNodeCount();
// The values of afterParseSize and afterCompileSize when this // The values of afterParseSize and afterCompileSize when this
// test was written were 849 and 848 respectively. // test was written were 3223 and 3505 respectively.
Assert.assertTrue(afterParseSize < 2000); Assert.assertTrue(afterParseSize < 4000);
Assert.assertTrue(afterCompileSize < 2000); Assert.assertTrue(afterCompileSize < 4000);
} }
} }

View File

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

View File

@ -240,6 +240,7 @@ public class GraalCompiler {
debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier"); debug.dump(DebugContext.BASIC_LEVEL, graph, "After low tier");
debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule"); debug.dump(DebugContext.BASIC_LEVEL, graph.getLastSchedule(), "Final HIR schedule");
graph.logInliningTree();
} catch (Throwable e) { } catch (Throwable e) {
throw debug.handle(e); throw debug.handle(e);
} finally { } finally {

View File

@ -316,6 +316,10 @@ public abstract class NodeLIRBuilder implements NodeLIRBuilderTool, LIRGeneratio
return values.toArray(new Value[values.size()]); return values.toArray(new Value[values.size()]);
} }
public void doBlockPrologue(@SuppressWarnings("unused") Block block, @SuppressWarnings("unused") OptionValues options) {
}
@Override @Override
@SuppressWarnings("try") @SuppressWarnings("try")
public void doBlock(Block block, StructuredGraph graph, BlockMap<List<Node>> blockMap) { 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); List<Node> nodes = blockMap.get(block);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.options.OptionValues;
import org.graalvm.compiler.phases.PhaseSuite; import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.common.CanonicalizerPhase; 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.ConvertDeoptimizeToGuardPhase;
import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase; import org.graalvm.compiler.phases.common.IncrementalCanonicalizerPhase;
@ -74,6 +75,10 @@ public class HighTier extends PhaseSuite<HighTierContext> {
appendPhase(canonicalizer); appendPhase(canonicalizer);
if (NodeCounterPhase.Options.NodeCounters.getValue(options)) {
appendPhase(new NodeCounterPhase());
}
if (Options.Inline.getValue(options)) { if (Options.Inline.getValue(options)) {
appendPhase(new InliningPhase(canonicalizer)); appendPhase(new InliningPhase(canonicalizer));
appendPhase(new DeadCodeEliminationPhase(Optional)); appendPhase(new DeadCodeEliminationPhase(Optional));

View File

@ -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 * @param method the method compiled to produce {@code compiledCode} or {@code null} if the
* input to {@code compResult} was not a {@link ResolvedJavaMethod} * input to {@code compResult} was not a {@link ResolvedJavaMethod}
* @param compilationRequest the compilation request or {@code null} * @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 * @param predefinedInstalledCode a pre-allocated {@link InstalledCode} object to use as a
* reference to the installed code. If {@code null}, a new {@link InstalledCode} * reference to the installed code. If {@code null}, a new {@link InstalledCode}
* object will be created. * object will be created.
@ -204,12 +204,13 @@ public abstract class Backend implements TargetProvider, ValueKindFactory<LIRKin
} }
try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext); try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
DebugContext.Activation a = debug.activate()) { DebugContext.Activation a = debug.activate()) {
preCodeInstallationTasks(tasks, compilationResult);
InstalledCode installedCode; InstalledCode installedCode;
try { try {
preCodeInstallationTasks(tasks, compilationResult, predefinedInstalledCode);
CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult); CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault); installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
assert predefinedInstalledCode == null || installedCode == predefinedInstalledCode;
} catch (Throwable t) { } catch (Throwable t) {
failCodeInstallationTasks(tasks, t); failCodeInstallationTasks(tasks, t);
throw 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) { 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 { public abstract static class CodeInstallationTask {
/** /**
* Task to run before code installation. * 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, InstalledCode predefinedInstalledCode) {
public void preProcess(CompilationResult compilationResult) {
} }
/** /**
* Task to run after the code is installed. * Task to run after the code is installed.
*
* @param installedCode a reference to the installed code
*/ */
@SuppressWarnings("unused")
public void postProcess(InstalledCode installedCode) { public void postProcess(InstalledCode installedCode) {
} }
/** /**
* Invoked after {@link #preProcess} when code installation fails. * Invoked after {@link #preProcess} when code installation fails.
*
* @param cause the cause of the installation failure
*/ */
@SuppressWarnings("unused") public void installFailed(Throwable cause) {
public void installFailed(Throwable t) {
} }
} }

View File

@ -116,7 +116,7 @@
<metadata name="net.sf.eclipsecs.core.comment" value="Illegal trailing whitespace(s) at the end of the line."/> <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="format" value="\s$"/>
<property name="message" value="Illegal trailing whitespace(s) at the end of the line."/> <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"/> <metadata name="com.atlassw.tools.eclipse.checkstyle.comment" value="Checks for trailing spaces at the end of a line"/>
</module> </module>
<module name="RegexpSinglelineJava"> <module name="RegexpSinglelineJava">

View File

@ -22,6 +22,9 @@
*/ */
package org.graalvm.compiler.graph; 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.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_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.EconomicMap;
import org.graalvm.collections.Equivalence; import org.graalvm.collections.Equivalence;
import org.graalvm.collections.UnmodifiableEconomicMap; import org.graalvm.collections.UnmodifiableEconomicMap;
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.debug.CounterKey; import org.graalvm.compiler.debug.CounterKey;
import org.graalvm.compiler.debug.DebugCloseable; import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext;
@ -65,6 +69,13 @@ public class Graph {
DeepFreeze DeepFreeze
} }
public enum SourcePositionTracking {
Default,
Ignore,
UpdateOnly,
Track
}
public final String name; public final String name;
/** /**
@ -80,7 +91,7 @@ public class Graph {
/** /**
* Records if updating of node source information is required when performing inlining. * 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}. * The number of valid entries in {@link #nodes}.
@ -195,7 +206,7 @@ public class Graph {
* was opened * was opened
*/ */
public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) { 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 * to short circuit logic for updating those positions after inlining since that requires
* visiting every node in the graph. * visiting every node in the graph.
*/ */
public boolean mayHaveNodeSourcePosition() { public boolean updateNodeSourcePosition() {
assert seenNodeSourcePosition || verifyHasNoSourcePosition(); return trackNodeSourcePosition == Track || trackNodeSourcePosition == UpdateOnly;
return seenNodeSourcePosition;
} }
private boolean verifyHasNoSourcePosition() { public boolean trackNodeSourcePosition() {
for (Node node : getNodes()) { return trackNodeSourcePosition == Track;
assert node.getNodeSourcePosition() == null; }
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()); iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
this.name = name; this.name = name;
this.options = options; this.options = options;
this.trackNodeSourcePosition = trackNodeSourcePositionDefault(options, debug);
assert debug != null; assert debug != null;
this.debug = debug; this.debug = debug;
@ -358,6 +380,9 @@ public class Graph {
*/ */
protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) { protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) {
Graph copy = new Graph(newName, options, 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); UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (EconomicMap<Node, Node>) null);
if (duplicationMapCallback != null) { if (duplicationMapCallback != null) {
duplicationMapCallback.accept(duplicates); duplicationMapCallback.accept(duplicates);
@ -1069,10 +1094,9 @@ public class Graph {
int id = nodesSize++; int id = nodesSize++;
nodes[id] = node; nodes[id] = node;
node.id = id; node.id = id;
if (currentNodeSourcePosition != null) { if (currentNodeSourcePosition != null && trackNodeSourcePosition()) {
node.setNodeSourcePosition(currentNodeSourcePosition); node.setNodeSourcePosition(currentNodeSourcePosition);
} }
seenNodeSourcePosition = seenNodeSourcePosition || node.getNodeSourcePosition() != null;
updateNodeCaches(node); updateNodeCaches(node);

View File

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

View File

@ -593,10 +593,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
* Set the source position to {@code sourcePosition}. * Set the source position to {@code sourcePosition}.
*/ */
public void setNodeSourcePosition(NodeSourcePosition 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; this.sourcePosition = sourcePosition;
if (sourcePosition != null && graph != null && !graph.seenNodeSourcePosition) { // assert sourcePosition == null || graph == null || graph.trackNodeSourcePosition;
graph.seenNodeSourcePosition = true;
}
} }
/** /**
@ -920,6 +919,9 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
} }
newNode.graph = into; newNode.graph = into;
newNode.id = INITIAL_ID; newNode.id = INITIAL_ID;
if (sourcePosition != null && (into == null || into.updateNodeSourcePosition())) {
newNode.setNodeSourcePosition(sourcePosition);
}
if (into != null) { if (into != null) {
into.register(newNode); into.register(newNode);
} }
@ -928,9 +930,6 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
if (into != null && useIntoLeafNodeCache) { if (into != null && useIntoLeafNodeCache) {
into.putNodeIntoCache(newNode); into.putNodeIntoCache(newNode);
} }
if (graph != null && into != null && sourcePosition != null) {
newNode.setNodeSourcePosition(sourcePosition);
}
newNode.afterClone(this); newNode.afterClone(this);
return newNode; return newNode;
} }
@ -1195,6 +1194,15 @@ public abstract class Node implements Cloneable, Formattable, NodeInterface {
return getNodeClass().dataEquals(this, other); 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) { public final void pushInputs(NodeStack stack) {
getNodeClass().pushInputs(this, stack); getNodeClass().pushInputs(this, stack);
} }

View File

@ -104,7 +104,7 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
* Gets the {@link NodeClass} associated with a given {@link Class}. * Gets the {@link NodeClass} associated with a given {@link Class}.
*/ */
public static <T> NodeClass<T> create(Class<T> c) { public static <T> NodeClass<T> create(Class<T> c) {
assert get(c) == null; assert getUnchecked(c) == null;
Class<? super T> superclass = c.getSuperclass(); Class<? super T> superclass = c.getSuperclass();
NodeClass<? super T> nodeSuperclass = null; NodeClass<? super T> nodeSuperclass = null;
if (superclass != NODE_CLASS) { if (superclass != NODE_CLASS) {
@ -114,9 +114,9 @@ public final class NodeClass<T> extends FieldIntrospection<T> {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> NodeClass<T> get(Class<T> superclass) { private static <T> NodeClass<T> getUnchecked(Class<T> clazz) {
try { try {
Field field = superclass.getDeclaredField("TYPE"); Field field = clazz.getDeclaredField("TYPE");
field.setAccessible(true); field.setAccessible(true);
return (NodeClass<T>) field.get(null); return (NodeClass<T>) field.get(null);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) { } 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<?> NODE_CLASS = Node.class;
private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class; private static final Class<?> INPUT_LIST_CLASS = NodeInputList.class;
private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class; private static final Class<?> SUCCESSOR_LIST_CLASS = NodeSuccessorList.class;

View File

@ -22,31 +22,100 @@
*/ */
package org.graalvm.compiler.graph; 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 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.BytecodePosition;
import jdk.vm.ci.code.CodeUtil; 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.MetaUtil;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
public class NodeSourcePosition extends BytecodePosition { public class NodeSourcePosition extends BytecodePosition {
/** private static final boolean STRICT_SOURCE_POSITION = Boolean.getBoolean("debug.graal.SourcePositionStrictChecks");
* The receiver of the method this frame refers to. private static final boolean SOURCE_POSITION_BYTECODES = Boolean.getBoolean("debug.graal.SourcePositionDisassemble");
*/
private final JavaConstant receiver;
private final int hashCode;
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); super(caller, method, bci);
if (caller == null) { if (caller == null) {
this.hashCode = 31 * bci + method.hashCode(); this.hashCode = 31 * bci + method.hashCode();
} else { } else {
this.hashCode = caller.hashCode * 7 + 31 * bci + method.hashCode(); this.hashCode = caller.hashCode * 7 + 31 * bci + method.hashCode();
} }
this.receiver = receiver; this.marker = marker;
assert receiver == null || method.getDeclaringClass().isInstance(receiver); 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 @Override
@ -60,7 +129,7 @@ public class NodeSourcePosition extends BytecodePosition {
return false; return false;
} }
if (this.getBCI() == that.getBCI() && Objects.equals(this.getMethod(), that.getMethod()) && Objects.equals(this.getCaller(), that.getCaller()) && 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; return true;
} }
} }
@ -72,8 +141,18 @@ public class NodeSourcePosition extends BytecodePosition {
return hashCode; return hashCode;
} }
public JavaConstant getReceiver() { public int depth() {
return receiver; int d = 0;
NodeSourcePosition pos = this;
while (pos != null) {
d++;
pos = pos.getCaller();
}
return d;
}
public SourceLanguagePosition getSourceLanauage() {
return sourceLanguagePosition;
} }
@Override @Override
@ -81,17 +160,29 @@ public class NodeSourcePosition extends BytecodePosition {
return (NodeSourcePosition) super.getCaller(); return (NodeSourcePosition) super.getCaller();
} }
public NodeSourcePosition addCaller(JavaConstant newCallerReceiver, NodeSourcePosition link) { public NodeSourcePosition addCaller(SourceLanguagePosition newSourceLanguagePosition, NodeSourcePosition link) {
if (getCaller() == null) { return addCaller(newSourceLanguagePosition, link, false);
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(NodeSourcePosition link) { 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 @Override
@ -99,9 +190,9 @@ public class NodeSourcePosition extends BytecodePosition {
StringBuilder sb = new StringBuilder(100); StringBuilder sb = new StringBuilder(100);
NodeSourcePosition pos = this; NodeSourcePosition pos = this;
while (pos != null) { while (pos != null) {
MetaUtil.appendLocation(sb.append("at "), pos.getMethod(), pos.getBCI()); format(sb, pos);
if (pos.receiver != null) { if (pos.sourceLanguagePosition != null) {
sb.append("receiver=" + pos.receiver + " "); sb.append(" source=" + pos.sourceLanguagePosition.toShortString());
} }
pos = pos.getCaller(); pos = pos.getCaller();
if (pos != null) { if (pos != null) {
@ -110,4 +201,55 @@ public class NodeSourcePosition extends BytecodePosition {
} }
return sb.toString(); 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;
}
} }

View File

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

View File

@ -20,20 +20,13 @@
* or visit www.oracle.com if you need additional information or have any * or visit www.oracle.com if you need additional information or have any
* questions. * questions.
*/ */
package org.graalvm.compiler.core.common; package org.graalvm.compiler.graph;
public enum TraceInliningMode { import jdk.vm.ci.meta.JavaConstant;
None(false),
Linear(true),
Tree(true);
private final boolean tracing; /**
* Provider of {@link SourceLanguagePosition} for a constant if it represents an AST node.
TraceInliningMode(boolean tracing) { */
this.tracing = tracing; public interface SourceLanguagePositionProvider {
} SourceLanguagePosition getPosition(JavaConstant node);
public boolean isTracing() {
return tracing;
}
} }

View File

@ -288,33 +288,37 @@ public class AArch64HotSpotBackend extends HotSpotHostBackend {
} }
private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) { private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
/* emitInvalidatePlaceholder(crb, masm);
* Insert a nop at the start of the prolog so we can patch in a branch if we need to crb.emit(lir);
* invalidate the method later. }
*/
/**
* 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]"); crb.blockComment("[nop for method invalidation]");
masm.nop(); masm.nop();
crb.emit(lir);
} }
private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) { private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
HotSpotProviders providers = getProviders(); HotSpotProviders providers = getProviders();
HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext; HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
if (!frameContext.isStub) { if (!frameContext.isStub) {
HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
try (ScratchRegister sc = masm.getScratchRegister()) { try (ScratchRegister sc = masm.getScratchRegister()) {
Register scratch = sc.getRegister(); Register scratch = sc.getRegister();
HotSpotForeignCallsProvider foreignCalls = providers.getForeignCalls();
crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY); crb.recordMark(config.MARKID_EXCEPTION_HANDLER_ENTRY);
ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER); ForeignCallLinkage linkage = foreignCalls.lookupForeignCall(EXCEPTION_HANDLER);
Register helper = AArch64Call.isNearCall(linkage) ? null : scratch; Register helper = AArch64Call.isNearCall(linkage) ? null : scratch;
AArch64Call.directCall(crb, masm, linkage, helper, null); 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 { } else {
// No need to emit the stubs for entries back into the method since // No need to emit the stubs for entries back into the method since
// it has no calls that can cause such "return" entries // it has no calls that can cause such "return" entries

View File

@ -46,7 +46,9 @@ public class AArch64HotSpotDeoptimizeOp extends AArch64BlockEndOp implements Blo
@Override @Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { 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);
}
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -155,22 +155,24 @@ public class AArch64HotSpotMove {
@Override @Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) { public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
Register ptr = asRegister(input); Register inputRegister = asRegister(input);
Register resultRegister = asRegister(result); 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) // result = base + (ptr << shift)
if (nonNull) { if (nonNull || baseReg == null) {
masm.add(64, resultRegister, base, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift()); masm.add(64, resReg, baseReg == null ? zr : baseReg, inputRegister, AArch64Assembler.ShiftType.LSL, shift);
} else if (!encoding.hasBase()) {
masm.add(64, resultRegister, zr, ptr, AArch64Assembler.ShiftType.LSL, encoding.getShift());
} else { } else {
// if ptr is null it has to be null after decompression // if ptr is null it has to be null after decompression
Label done = new Label(); Label done = new Label();
if (!resultRegister.equals(ptr)) { if (!resReg.equals(inputRegister)) {
masm.mov(32, resultRegister, ptr); masm.mov(32, resReg, inputRegister);
} }
masm.cbz(32, resultRegister, done); masm.cbz(32, resReg, done);
masm.add(64, resultRegister, base, resultRegister, AArch64Assembler.ShiftType.LSL, encoding.getShift()); masm.add(64, resReg, baseReg, resReg, AArch64Assembler.ShiftType.LSL, shift);
masm.bind(done); masm.bind(done);
} }
} }

View File

@ -65,6 +65,7 @@ import jdk.vm.ci.meta.AllocatableValue;
import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.Value; import jdk.vm.ci.meta.Value;
import org.graalvm.compiler.hotspot.HotSpotBackend;
public class StubAVXTest extends LIRTest { public class StubAVXTest extends LIRTest {
@ -72,6 +73,10 @@ public class StubAVXTest extends LIRTest {
public void checkAMD64() { public void checkAMD64() {
Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64); Assume.assumeTrue("skipping AMD64 specific test", getTarget().arch instanceof AMD64);
Assume.assumeTrue("skipping AVX test", ((AMD64) getTarget().arch).getFeatures().contains(CPUFeature.AVX)); 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); private static final DataPointerConstant avxConstant = new ArrayDataPointerConstant(new float[]{1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f}, 32);

View File

@ -204,7 +204,7 @@ public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering {
if (init >= 0 && extremum >= 0) { if (init >= 0 && extremum >= 0) {
long shortestTrip = (extremum - init) / stride + 1; 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)); return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true));
} }
} }

View File

@ -25,13 +25,13 @@ package org.graalvm.compiler.hotspot.amd64;
import static jdk.vm.ci.amd64.AMD64.rbp; import static jdk.vm.ci.amd64.AMD64.rbp;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; 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.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_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_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_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.INITIALIZE;
import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS; 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.ArrayList;
import java.util.List; 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) { 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, protected AMD64HotSpotLIRGenerator(LIRKindTool lirKindTool, AMD64ArithmeticLIRGenerator arithmeticLIRGen, MoveFactory moveFactory, HotSpotProviders providers, GraalHotSpotVMConfig config,

View File

@ -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.amd64.AMD64ArithmeticLIRGenerator;
import org.graalvm.compiler.core.common.LIRKind; 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.Variable;
import org.graalvm.compiler.lir.gen.LIRGenerator;
import jdk.vm.ci.meta.Value; 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 @Override
public Value emitMathLog(Value input, boolean base10) { public Variable emitLog(LIRGenerator gen, Value input, boolean base10) {
if (GraalArithmeticStubs.getValue(getOptions())) { if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
return super.emitMathLog(input, base10); return null;
} }
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); Variable result = gen.newVariable(LIRKind.combine(input));
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, getLIRGen().asAllocatable(input))); gen.append(new AMD64HotSpotMathIntrinsicOp(base10 ? LOG10 : LOG, result, gen.asAllocatable(input)));
return result; return result;
} }
@Override @Override
public Value emitMathCos(Value input) { public Variable emitCos(LIRGenerator gen, Value input) {
if (GraalArithmeticStubs.getValue(getOptions())) { if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
return super.emitMathCos(input); return null;
} }
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); Variable result = gen.newVariable(LIRKind.combine(input));
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(COS, result, getLIRGen().asAllocatable(input))); gen.append(new AMD64HotSpotMathIntrinsicOp(COS, result, gen.asAllocatable(input)));
return result; return result;
} }
@Override @Override
public Value emitMathSin(Value input) { public Variable emitSin(LIRGenerator gen, Value input) {
if (GraalArithmeticStubs.getValue(getOptions())) { if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
return super.emitMathSin(input); return null;
} }
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); Variable result = gen.newVariable(LIRKind.combine(input));
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(SIN, result, getLIRGen().asAllocatable(input))); gen.append(new AMD64HotSpotMathIntrinsicOp(SIN, result, gen.asAllocatable(input)));
return result; return result;
} }
@Override @Override
public Value emitMathTan(Value input) { public Variable emitTan(LIRGenerator gen, Value input) {
if (GraalArithmeticStubs.getValue(getOptions())) { if (GraalArithmeticStubs.getValue(gen.getResult().getLIR().getOptions())) {
return super.emitMathTan(input); return null;
} }
Variable result = getLIRGen().newVariable(LIRKind.combine(input)); Variable result = gen.newVariable(LIRKind.combine(input));
getLIRGen().append(new AMD64HotSpotMathIntrinsicOp(TAN, result, getLIRGen().asAllocatable(input))); gen.append(new AMD64HotSpotMathIntrinsicOp(TAN, result, gen.asAllocatable(input)));
return result; return result;
} }

View File

@ -187,21 +187,26 @@ public class SPARCHotSpotMove {
public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) { public void emitCode(CompilationResultBuilder crb, SPARCMacroAssembler masm) {
Register inputRegister = asRegister(input); Register inputRegister = asRegister(input);
Register resReg = asRegister(result); 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; Register secondaryInput;
if (encoding.getShift() != 0) { if (shift != 0) {
masm.sll(inputRegister, encoding.getShift(), resReg); masm.sll(inputRegister, shift, resReg);
secondaryInput = resReg; secondaryInput = resReg;
} else { } else {
secondaryInput = inputRegister; secondaryInput = inputRegister;
} }
if (encoding.hasBase()) { if (baseReg != null) {
if (nonNull) { if (nonNull) {
masm.add(secondaryInput, asRegister(baseRegister), resReg); masm.add(secondaryInput, baseReg, resReg);
} else { } else {
Label done = new Label(); Label done = new Label();
BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done); BPR.emit(masm, Rc_z, ANNUL, PREDICT_TAKEN, secondaryInput, done);
masm.add(asRegister(baseRegister), secondaryInput, resReg); masm.add(baseReg, secondaryInput, resReg);
masm.bind(done); masm.bind(done);
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -553,6 +553,7 @@ public final class CompileTheWorld {
classFileCounter++; classFileCounter++;
if (className.startsWith("jdk.management.") || if (className.startsWith("jdk.management.") ||
className.startsWith("jdk.internal.cmm.*") ||
// GR-5881: The class initializer for // GR-5881: The class initializer for
// sun.tools.jconsole.OutputViewer // sun.tools.jconsole.OutputViewer
// spawns non-daemon threads for redirecting sysout and syserr. // spawns non-daemon threads for redirecting sysout and syserr.

View File

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

View File

@ -24,17 +24,25 @@ package org.graalvm.compiler.hotspot;
import static jdk.vm.ci.common.InitTimer.timer; import static jdk.vm.ci.common.InitTimer.timer;
import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicMap;
import org.graalvm.compiler.debug.GraalError; 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.Option;
import org.graalvm.compiler.options.OptionKey; import org.graalvm.compiler.options.OptionKey;
import org.graalvm.compiler.options.OptionType; import org.graalvm.compiler.options.OptionType;
import org.graalvm.compiler.options.OptionValues; 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.phases.tiers.CompilerConfiguration;
import org.graalvm.compiler.serviceprovider.GraalServices; import org.graalvm.compiler.serviceprovider.GraalServices;
@ -48,12 +56,20 @@ import jdk.vm.ci.common.InitTimer;
*/ */
public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> { public abstract class CompilerConfigurationFactory implements Comparable<CompilerConfigurationFactory> {
enum ShowConfigurationLevel {
none,
info,
verbose
}
static class Options { static class Options {
// @formatter:off // @formatter:off
@Option(help = "Names the Graal compiler configuration to use. If ommitted, the compiler configuration " + @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, " + "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) "supply the value 'help' to this option.", type = OptionType.Expert)
public static final OptionKey<String> CompilerConfiguration = new OptionKey<>(null); 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 // @formatter:on
} }
@ -192,6 +208,52 @@ public abstract class CompilerConfigurationFactory implements Comparable<Compile
factory = candidates.get(0); 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; 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;
}
} }

View File

@ -45,8 +45,9 @@ public class GraalHotSpotVMConfig extends HotSpotVMConfigAccess {
*/ */
public static final GraalHotSpotVMConfig INJECTED_VMCONFIG = null; 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 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 osName = getHostOSName();
public final String osArch = getHostArchitectureName(); public final String osArch = getHostArchitectureName();
public final boolean windowsOs = System.getProperty("os.name", "").startsWith("Windows"); 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 boolean forceUnreachable = getFlag("ForceUnreachable", Boolean.class);
public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class); public final int codeSegmentSize = getFlag("CodeCacheSegmentSize", Integer.class);
public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.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 useTLAB = getFlag("UseTLAB", Boolean.class);
public final boolean useBiasedLocking = getFlag("UseBiasedLocking", 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 int logOfHRGrainBytes = getFieldValue("HeapRegion::LogOfHRGrainBytes", Integer.class, "int");
public final byte dirtyCardValue = JDKVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class) : public final byte dirtyCardValue = jdkVersion >= 11 ? getConstant("CardTable::dirty_card", Byte.class)
(JDKVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : : (jdkVersion > 8 ? getConstant("CardTableModRefBS::dirty_card", Byte.class) : getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int"));
getFieldValue("CompilerToVM::Data::dirty_card", Byte.class, "int")); public final byte g1YoungCardValue = jdkVersion >= 11 ? getConstant("G1CardTable::g1_young_gen", Byte.class)
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"));
(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 long cardtableStartAddress = getFieldValue("CompilerToVM::Data::cardtable_start_address", Long.class, "jbyte*");
public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int"); public final int cardtableShift = getFieldValue("CompilerToVM::Data::cardtable_shift", Integer.class, "int");

View File

@ -91,7 +91,7 @@ public abstract class HotSpotBackend extends Backend implements FrameMap.Referen
public static class Options { public static class Options {
// @formatter:off // @formatter:off
@Option(help = "Use Graal arithmetic stubs instead of HotSpot stubs where possible") @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." + @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) " Compare with subclasses of Assembler.InstructionCounter.", type = OptionType.Debug)
public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null); public static final OptionKey<String> ASMInstructionProfiling = new OptionKey<>(null);

View File

@ -22,6 +22,8 @@
*/ */
package org.graalvm.compiler.hotspot; package org.graalvm.compiler.hotspot;
import static org.graalvm.util.CollectionsUtil.anyMatch;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; 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.CodeAnnotation;
import org.graalvm.compiler.code.CompilationResult.CodeComment; import org.graalvm.compiler.code.CompilationResult.CodeComment;
import org.graalvm.compiler.code.CompilationResult.JumpTable; import org.graalvm.compiler.code.CompilationResult.JumpTable;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.code.DataSection; import org.graalvm.compiler.code.DataSection;
import org.graalvm.compiler.code.SourceMapping; import org.graalvm.compiler.code.SourceMapping;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.NodeSourcePosition; import org.graalvm.compiler.graph.NodeSourcePosition;
import jdk.vm.ci.code.CodeCacheProvider; 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;
import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment; import jdk.vm.ci.hotspot.HotSpotCompiledCode.Comment;
import jdk.vm.ci.hotspot.HotSpotCompiledNmethod; import jdk.vm.ci.hotspot.HotSpotCompiledNmethod;
import jdk.vm.ci.hotspot.HotSpotObjectConstant;
import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
import jdk.vm.ci.meta.Assumptions.Assumption; import jdk.vm.ci.meta.Assumptions.Assumption;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
@ -210,16 +211,31 @@ public class HotSpotCompiledCodeBuilder {
sites.addAll(target.getDataPatches()); sites.addAll(target.getDataPatches());
sites.addAll(target.getMarks()); 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()) { 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()) { for (SourceMapping source : target.getSourceMappings()) {
sites.add(new Infopoint(source.getEndOffset(), new DebugInfo(source.getSourcePosition()), InfopointReason.BYTECODE_POSITION)); NodeSourcePosition sourcePosition = source.getSourcePosition();
assert verifySourcePositionReceivers(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(); SiteComparator c = new SiteComparator();
@ -245,18 +261,4 @@ public class HotSpotCompiledCodeBuilder {
} }
return sites.toArray(new Site[sites.size()]); 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;
}
} }

View File

@ -26,8 +26,8 @@ import static jdk.vm.ci.common.InitTimer.timer;
import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX; import static org.graalvm.compiler.hotspot.HotSpotGraalOptionValues.GRAAL_OPTION_PROPERTY_PREFIX;
import java.io.PrintStream; import java.io.PrintStream;
import java.util.Map;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import org.graalvm.compiler.debug.MethodFilter; import org.graalvm.compiler.debug.MethodFilter;
import org.graalvm.compiler.options.Option; 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.OptionValues;
import org.graalvm.compiler.options.OptionsParser; import org.graalvm.compiler.options.OptionsParser;
import org.graalvm.compiler.phases.tiers.CompilerConfiguration; import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
import org.graalvm.compiler.serviceprovider.JDK9Method;
import jdk.vm.ci.common.InitTimer; import jdk.vm.ci.common.InitTimer;
import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory; import jdk.vm.ci.hotspot.HotSpotJVMCICompilerFactory;
@ -48,6 +49,22 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
private static MethodFilter[] graalCompileOnlyFilter; private static MethodFilter[] graalCompileOnlyFilter;
private static boolean compileGraalWithC1Only; 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; private final HotSpotGraalJVMCIServiceLocator locator;
HotSpotGraalCompilerFactory(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"; assert options == null : "cannot select " + getClass() + " service more than once";
options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS; options = HotSpotGraalOptionValues.HOTSPOT_OPTIONS;
initializeGraalCompilePolicyFields(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 * 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. * 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) @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); 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); public static final OptionKey<String> GraalCompileOnly = new OptionKey<>(null);
// @formatter:on // @formatter:on
@ -110,7 +133,11 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
@Override @Override
public HotSpotGraalCompiler createCompiler(JVMCIRuntime runtime) { 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 // Only the HotSpotGraalRuntime associated with the compiler created via
// jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving // jdk.vm.ci.runtime.JVMCIRuntime.getCompiler() is registered for receiving
// VM events. // VM events.
@ -160,15 +187,54 @@ public final class HotSpotGraalCompilerFactory extends HotSpotJVMCICompilerFacto
assert HotSpotGraalCompilerFactory.class.getName().equals("org.graalvm.compiler.hotspot.HotSpotGraalCompilerFactory"); 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. * 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 (compileGraalWithC1Only) {
if (level.ordinal() > CompilationLevel.Simple.ordinal()) { if (level.ordinal() > CompilationLevel.Simple.ordinal()) {
String declaringClassName = declaringClass.getName(); if (JDK9Method.Java8OrEarlier) {
if (declaringClassName.startsWith("jdk.vm.ci") || declaringClassName.startsWith("org.graalvm") || declaringClassName.startsWith("com.oracle.graal")) { if (JVMCI_LOADER != null) {
return CompilationLevel.Simple; // 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);
}
} }
} }
} }

View File

@ -24,7 +24,6 @@ package org.graalvm.compiler.hotspot;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI; import java.net.URI;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
@ -114,14 +113,9 @@ public class NodeCostDumpUtil {
} }
System.err.printf("Loaded %s node classes...\n", nodeClasses.size()); System.err.printf("Loaded %s node classes...\n", nodeClasses.size());
List<NodeClass<?>> nc = new ArrayList<>(); List<NodeClass<?>> nc = new ArrayList<>();
for (Class<?> nodeClass : nodeClasses) { for (Class<?> c : nodeClasses) {
Field f;
try { try {
f = nodeClass.getField("TYPE"); nc.add(NodeClass.get(c));
f.setAccessible(true);
Object val = f.get(null);
NodeClass<?> nodeType = (NodeClass<?>) val;
nc.add(nodeType);
} catch (Throwable t) { } catch (Throwable t) {
// Silently ignore problems here // Silently ignore problems here
} }

View File

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

View File

@ -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.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp; import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory; 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.InitializeKlassNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
import org.graalvm.compiler.nodes.ConstantNode; 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.hotspot.HotSpotResolvedObjectType;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType; 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 { public final class HotSpotClassInitializationPlugin implements ClassInitializationPlugin {
@Override @Override
@ -73,4 +79,47 @@ public final class HotSpotClassInitializationPlugin implements ClassInitializati
result.setStateBefore(frameState); result.setStateBefore(frameState);
return result; 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);
}
}
} }

View File

@ -234,7 +234,7 @@ public class HotSpotGraphBuilderPlugins {
b.addPush(JavaKind.Object, object); b.addPush(JavaKind.Object, object);
} else { } else {
FixedGuardNode fixedGuard = b.add(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false)); 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; return true;
} }

View File

@ -24,6 +24,7 @@ package org.graalvm.compiler.hotspot.meta;
import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier; import static org.graalvm.compiler.serviceprovider.JDK9Method.Java8OrEarlier;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Set; import java.util.Set;
@ -129,7 +130,7 @@ final class HotSpotInvocationPlugins extends InvocationPlugins {
ClassLoader cl = javaClass.getClassLoader(); ClassLoader cl = javaClass.getClassLoader();
return cl == null || cl == getClass().getClassLoader() || cl == extLoader; return cl == null || cl == getClass().getClassLoader() || cl == extLoader;
} else { } else {
Object module = JDK9Method.getModule.invoke(javaClass); Object module = JDK9Method.getModule(javaClass);
return trustedModules.contains(module); 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 { private static EconomicSet<Object> initTrustedModules(CompilerConfiguration compilerConfiguration) throws GraalError {
try { try {
EconomicSet<Object> res = EconomicSet.create(); EconomicSet<Object> res = EconomicSet.create();
Object compilerConfigurationModule = JDK9Method.getModule.invoke(compilerConfiguration.getClass()); Object compilerConfigurationModule = JDK9Method.getModule(compilerConfiguration.getClass());
res.add(compilerConfigurationModule); res.add(compilerConfigurationModule);
Class<?> moduleClass = compilerConfigurationModule.getClass(); 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(); Class<? extends Object> layerClass = layer.getClass();
JDK9Method getName = new JDK9Method(moduleClass, "getName"); MethodHandle getName = JDK9Method.lookupMethodHandle(moduleClass, "getName");
Set<Object> modules = new JDK9Method(layerClass, "modules").invoke(layer); Set<Object> modules = (Set<Object>) JDK9Method.lookupMethodHandle(layerClass, "modules").invoke(layer);
Object descriptor = new JDK9Method(moduleClass, "getDescriptor").invoke(compilerConfigurationModule); Object descriptor = JDK9Method.lookupMethodHandle(moduleClass, "getDescriptor").invoke(compilerConfigurationModule);
Class<?> moduleDescriptorClass = descriptor.getClass(); Class<?> moduleDescriptorClass = descriptor.getClass();
Set<Object> requires = new JDK9Method(moduleDescriptorClass, "requires").invoke(descriptor); Set<Object> requires = (Set<Object>) JDK9Method.lookupMethodHandle(moduleDescriptorClass, "requires").invoke(descriptor);
JDK9Method requireNameGetter = null; 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) { for (Object require : requires) {
if (requireNameGetter == null) { 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) { for (Object module : modules) {
String moduleName = getName.invoke(module); String moduleName = (String) getName.invoke(module);
if (moduleName.equals(name)) { if (moduleName.equals(name)) {
res.add(module); res.add(module);
} }
} }
} }
return res; return res;
} catch (Exception e) { } catch (Throwable e) {
throw new GraalError(e); throw new GraalError(e);
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 static org.graalvm.compiler.core.phases.HighTier.Options.Inline;
import java.util.ListIterator; import java.util.ListIterator;
import org.graalvm.compiler.debug.Assertions;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig; import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotBackend; import org.graalvm.compiler.hotspot.HotSpotBackend;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider; import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotInstructionProfiling; 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.AheadOfTimeVerificationPhase;
import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase; import org.graalvm.compiler.hotspot.phases.LoadJavaMirrorWithKlassPhase;
import org.graalvm.compiler.hotspot.phases.WriteBarrierAdditionPhase; 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(); 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(), SimplifyingGraphDecoder graphDecoder = new SimplifyingGraphDecoder(runtime.getTarget().arch, targetGraph, context.getMetaAccess(), context.getConstantReflection(),
context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions())); context.getConstantFieldProvider(), context.getStampProvider(), !ImmutableCode.getValue(graph.getOptions()));
if (graph.trackNodeSourcePosition()) {
targetGraph.setTrackNodeSourcePosition();
}
graphDecoder.decode(encodedGraph); graphDecoder.decode(encodedGraph);
} }
@ -171,6 +177,9 @@ public class HotSpotSuitesProvider extends SuitesProviderBase {
if (profileInstructions != null) { if (profileInstructions != null) {
suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions)); suites.getPostAllocationOptimizationStage().appendPhase(new HotSpotInstructionProfiling(profileInstructions));
} }
if (Assertions.detailedAssertionsEnabled(options)) {
suites.getPostAllocationOptimizationStage().appendPhase(new VerifyMaxRegisterSizePhase(config.maxVectorSize));
}
return suites; return suites;
} }
} }

View File

@ -76,17 +76,17 @@ public class AOTInliningPolicy extends GreedyInliningPolicy {
OptionValues options = info.graph().getOptions(); OptionValues options = info.graph().getOptions();
if (InlineEverything.getValue(options)) { if (InlineEverything.getValue(options)) {
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything"); InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "inline everything");
return true; return true;
} }
if (isIntrinsic(replacements, info)) { if (isIntrinsic(replacements, info)) {
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic"); InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "intrinsic");
return true; return true;
} }
if (info.shouldInline()) { if (info.shouldInline()) {
InliningUtil.logInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining"); InliningUtil.traceInlinedMethod(info, inliningDepth, fullyProcessed, "forced inlining");
return true; return true;
} }
@ -94,18 +94,18 @@ public class AOTInliningPolicy extends GreedyInliningPolicy {
int nodes = info.determineNodeCount(); int nodes = info.determineNodeCount();
if (nodes < TrivialInliningSize.getValue(options) * inliningBonus) { 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; return true;
} }
double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus)); double maximumNodes = computeMaximumSize(relevance, (int) (maxInliningSize(inliningDepth, options) * inliningBonus));
if (nodes <= maximumNodes) { 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); nodes, maximumNodes);
return true; 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; return false;
} }
} }

View File

@ -86,7 +86,7 @@ public class AssertionSnippets implements Snippets {
args.add("condition", assertionNode.condition()); args.add("condition", assertionNode.condition());
args.addConst("message", "failed runtime assertion in snippet/stub: " + assertionNode.message() + " (" + graph.method() + ")"); 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);
} }
} }
} }

View File

@ -87,7 +87,7 @@ public class HashCodeSnippets implements Snippets {
StructuredGraph graph = node.graph(); StructuredGraph graph = node.graph();
Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(identityHashCodeSnippet, graph.getGuardsStage(), tool.getLoweringStage());
args.add("thisObj", node.object); 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); template.instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
} }

View File

@ -101,7 +101,7 @@ public class LoadExceptionObjectSnippets implements Snippets {
} else { } else {
Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(loadException, loadExceptionObject.graph().getGuardsStage(), tool.getLoweringStage());
args.addConst("threadRegister", registers.getThreadRegister()); 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);
} }
} }
} }

View File

@ -759,7 +759,7 @@ public class MonitorSnippets implements Snippets {
args.addConst("counters", counters); 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) { 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("options", graph.getOptions());
args.addConst("counters", counters); 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) { public static boolean isTracingEnabledForType(ValueNode object) {
@ -828,7 +828,7 @@ public class MonitorSnippets implements Snippets {
invoke.setStateAfter(graph.start().stateAfter()); invoke.setStateAfter(graph.start().stateAfter());
graph.addAfterFixed(graph.start(), invoke); 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); InliningUtil.inline(invoke, inlineeGraph, false, null);
List<ReturnNode> rets = graph.getNodes(ReturnNode.TYPE).snapshot(); 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()); Arguments args = new Arguments(checkCounter, graph.getGuardsStage(), tool.getLoweringStage());
args.addConst("errMsg", msg); 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); InliningUtil.inline(invoke, inlineeGraph, false, null);
} }
} }

View File

@ -626,7 +626,7 @@ public class NewObjectSnippets implements Snippets {
args.addConst("options", localOptions); args.addConst("options", localOptions);
args.addConst("counters", counters); 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); 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); 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("typeContext", ProfileAllocations.getValue(localOptions) ? arrayType.toJavaName(false) : "");
args.addConst("options", localOptions); args.addConst("options", localOptions);
args.addConst("counters", counters); 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); 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); template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
} }
@ -686,7 +686,7 @@ public class NewObjectSnippets implements Snippets {
args.addConst("options", localOptions); args.addConst("options", localOptions);
args.addConst("counters", counters); args.addConst("counters", counters);
SnippetTemplate template = template(newInstanceNode.getDebug(), args); SnippetTemplate template = template(newInstanceNode, args);
template.instantiate(providers.getMetaAccess(), newInstanceNode, DEFAULT_REPLACER, 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.add("prototypeMarkWord", lookupArrayClass(tool, JavaKind.Object).prototypeMarkWord());
args.addConst("options", localOptions); args.addConst("options", localOptions);
args.addConst("counters", counters); args.addConst("counters", counters);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(newArrayNode, args);
template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
} }
@ -739,7 +739,7 @@ public class NewObjectSnippets implements Snippets {
args.add("hub", hub); args.add("hub", hub);
args.addConst("rank", rank); args.addConst("rank", rank);
args.addVarargs("dimensions", int.class, StampFactory.forKind(JavaKind.Int), dims); 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) { 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()); Arguments args = new Arguments(verifyHeap, verifyHeapNode.graph().getGuardsStage(), tool.getLoweringStage());
args.addConst("threadRegister", registers.getThreadRegister()); args.addConst("threadRegister", registers.getThreadRegister());
SnippetTemplate template = template(verifyHeapNode.getDebug(), args); SnippetTemplate template = template(verifyHeapNode, args);
template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), verifyHeapNode, DEFAULT_REPLACER, args);
} else { } else {
GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode); GraphUtil.removeFixedWithUnusedInputs(verifyHeapNode);

View File

@ -86,7 +86,7 @@ public final class ObjectCloneNode extends BasicObjectCloneNode implements Virtu
StructuredGraph snippetGraph = null; StructuredGraph snippetGraph = null;
DebugContext debug = getDebug(); DebugContext debug = getDebug();
try (DebugContext.Scope s = debug.scope("ArrayCloneSnippet", snippetMethod)) { 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) { } catch (Throwable e) {
throw debug.handle(e); throw debug.handle(e);
} }

View File

@ -83,7 +83,7 @@ public class StringToBytesSnippets implements Snippets {
public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) { public void lower(StringToBytesNode stringToBytesNode, LoweringTool tool) {
Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(create, stringToBytesNode.graph().getGuardsStage(), tool.getLoweringStage());
args.addConst("compilationTimeString", stringToBytesNode.getValue()); args.addConst("compilationTimeString", stringToBytesNode.getValue());
SnippetTemplate template = template(stringToBytesNode.getDebug(), args); SnippetTemplate template = template(stringToBytesNode, args);
template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), stringToBytesNode, DEFAULT_REPLACER, args);
} }

View File

@ -65,7 +65,7 @@ public class UnsafeLoadSnippets implements Snippets {
Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(unsafeLoad, load.graph().getGuardsStage(), tool.getLoweringStage());
args.add("object", load.object()); args.add("object", load.object());
args.add("offset", load.offset()); 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);
} }
} }
} }

View File

@ -434,7 +434,7 @@ public class WriteBarrierSnippets implements Snippets {
args.add("object", address.getBase()); args.add("object", address.getBase());
} }
args.addConst("counters", counters); 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) { public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
@ -442,7 +442,7 @@ public class WriteBarrierSnippets implements Snippets {
args.add("address", arrayRangeWriteBarrier.getAddress()); args.add("address", arrayRangeWriteBarrier.getAddress());
args.add("length", arrayRangeWriteBarrier.getLength()); args.add("length", arrayRangeWriteBarrier.getLength());
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); 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) { 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("threadRegister", registers.getThreadRegister());
args.addConst("trace", traceBarrier(writeBarrierPre.graph())); args.addConst("trace", traceBarrier(writeBarrierPre.graph()));
args.addConst("counters", counters); 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) { 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("threadRegister", registers.getThreadRegister());
args.addConst("trace", traceBarrier(readBarrier.graph())); args.addConst("trace", traceBarrier(readBarrier.graph()));
args.addConst("counters", counters); 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) { 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("threadRegister", registers.getThreadRegister());
args.addConst("trace", traceBarrier(writeBarrierPost.graph())); args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
args.addConst("counters", counters); 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) { public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
@ -531,7 +531,7 @@ public class WriteBarrierSnippets implements Snippets {
args.add("length", arrayRangeWriteBarrier.getLength()); args.add("length", arrayRangeWriteBarrier.getLength());
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
args.addConst("threadRegister", registers.getThreadRegister()); 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) { public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
@ -540,7 +540,7 @@ public class WriteBarrierSnippets implements Snippets {
args.add("length", arrayRangeWriteBarrier.getLength()); args.add("length", arrayRangeWriteBarrier.getLength());
args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride()); args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
args.addConst("threadRegister", registers.getThreadRegister()); 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);
} }
} }

View File

@ -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.InitializeKlassStubCall;
import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersIndirectlyNode; 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.ResolveConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveDynamicConstantNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantStubCall; 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.ResolveMethodAndLoadCountersNode;
import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall; import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersStubCall;
import org.graalvm.compiler.hotspot.nodes.type.MethodPointerStamp; 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()); Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args.add("constant", value); args.add("constant", value);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(resolveConstantNode, args);
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
assert resolveConstantNode.hasNoUsages(); assert resolveConstantNode.hasNoUsages();
@ -180,7 +180,7 @@ public class ResolveConstantSnippets implements Snippets {
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args.add("constant", value); args.add("constant", value);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(resolveConstantNode, args);
template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), resolveConstantNode, DEFAULT_REPLACER, args);
assert resolveConstantNode.hasNoUsages(); assert resolveConstantNode.hasNoUsages();
@ -200,7 +200,7 @@ public class ResolveConstantSnippets implements Snippets {
Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(initializeKlass, graph.getGuardsStage(), tool.getLoweringStage());
args.add("constant", value); args.add("constant", value);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(initializeKlassNode, args);
template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), initializeKlassNode, DEFAULT_REPLACER, args);
assert initializeKlassNode.hasNoUsages(); assert initializeKlassNode.hasNoUsages();
if (!initializeKlassNode.isDeleted()) { if (!initializeKlassNode.isDeleted()) {
@ -218,7 +218,7 @@ public class ResolveConstantSnippets implements Snippets {
Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage()); Arguments args = new Arguments(resolveMethodAndLoadCounters, graph.getGuardsStage(), tool.getLoweringStage());
args.add("method", method); args.add("method", method);
args.add("klassHint", resolveMethodAndLoadCountersNode.getHub()); args.add("klassHint", resolveMethodAndLoadCountersNode.getHub());
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(resolveMethodAndLoadCountersNode, args);
template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), resolveMethodAndLoadCountersNode, DEFAULT_REPLACER, args);
assert resolveMethodAndLoadCountersNode.hasNoUsages(); assert resolveMethodAndLoadCountersNode.hasNoUsages();

View File

@ -524,7 +524,7 @@ public class ArrayCopySnippets implements Snippets {
*/ */
private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) { private void instantiate(Arguments args, BasicArrayCopyNode arraycopy) {
StructuredGraph graph = arraycopy.graph(); 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); UnmodifiableEconomicMap<Node, Node> replacements = template.instantiate(providers.getMetaAccess(), arraycopy, SnippetTemplate.DEFAULT_REPLACER, args, false);
for (Node originalNode : replacements.getKeys()) { for (Node originalNode : replacements.getKeys()) {
if (originalNode instanceof Invoke) { if (originalNode instanceof Invoke) {

View File

@ -150,7 +150,7 @@ public class ProbabilisticProfileSnippets implements Snippets {
args.add("bci", bci); args.add("bci", bci);
args.add("targetBci", targetBci); args.add("targetBci", targetBci);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(profileNode, args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
} else if (profileNode instanceof ProfileInvokeNode) { } else if (profileNode instanceof ProfileInvokeNode) {
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
@ -163,7 +163,7 @@ public class ProbabilisticProfileSnippets implements Snippets {
args.add("stepLog", stepLog); args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
args.addConst("probLog", profileInvokeNode.getProbabilityLog()); args.addConst("probLog", profileInvokeNode.getProbabilityLog());
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(profileNode, args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
} else { } else {
throw new GraalError("Unsupported profile node type: " + profileNode); throw new GraalError("Unsupported profile node type: " + profileNode);

View File

@ -132,7 +132,7 @@ public class ProfileSnippets implements Snippets {
args.add("bci", bci); args.add("bci", bci);
args.add("targetBci", targetBci); args.add("targetBci", targetBci);
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(profileNode, args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
} else if (profileNode instanceof ProfileInvokeNode) { } else if (profileNode instanceof ProfileInvokeNode) {
ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode; ProfileInvokeNode profileInvokeNode = (ProfileInvokeNode) profileNode;
@ -142,7 +142,7 @@ public class ProfileSnippets implements Snippets {
args.add("step", step); args.add("step", step);
args.add("stepLog", stepLog); args.add("stepLog", stepLog);
args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog()); args.addConst("freqLog", profileInvokeNode.getNotificationFreqLog());
SnippetTemplate template = template(graph.getDebug(), args); SnippetTemplate template = template(profileNode, args);
template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args); template.instantiate(providers.getMetaAccess(), profileNode, DEFAULT_REPLACER, args);
} else { } else {
throw new GraalError("Unsupported profile node type: " + profileNode); throw new GraalError("Unsupported profile node type: " + profileNode);

View File

@ -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.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory; import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.StampPair; 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.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.debug.JavaMethodContext; import org.graalvm.compiler.debug.JavaMethodContext;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition; import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition;
import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkageImpl; 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. * %r15 on AMD64) and is only prepended if {@link #prependThread} is true.
*/ */
@Override @Override
@SuppressWarnings("try")
protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) { protected StructuredGraph getGraph(DebugContext debug, CompilationIdentifier compilationId) {
WordTypes wordTypes = providers.getWordTypes(); WordTypes wordTypes = providers.getWordTypes();
Class<?>[] args = linkage.getDescriptor().getArgumentTypes(); Class<?>[] args = linkage.getDescriptor().getArgumentTypes();
boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn()); boolean isObjectResult = !LIRKind.isValue(linkage.getOutgoingCallingConvention().getReturn());
StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build(); StructuredGraph graph = new StructuredGraph.Builder(options, debug).name(toString()).compilationId(compilationId).build();
graph.disableUnsafeAccessTracking(); 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()); kit.inlineInvokes();
ParameterNode[] params = createParameters(kit, args); new RemoveValueProxyPhase().apply(graph);
ReadRegisterNode thread = kit.append(new ReadRegisterNode(providers.getRegisters().getThreadRegister(), wordTypes.getWordKind(), true, false)); debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
ValueNode result = createTargetCall(kit, params, thread); }
kit.createInvoke(StubUtil.class, "handlePendingException", thread, ConstantNode.forBoolean(isObjectResult, graph)); } catch (Exception e) {
if (isObjectResult) { throw GraalError.shouldNotReachHere(e);
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");
kit.inlineInvokes();
new RemoveValueProxyPhase().apply(graph);
debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Stub graph before compilation");
return graph; return graph;
} }

View File

@ -279,6 +279,7 @@ import org.graalvm.compiler.bytecode.Bytecodes;
import org.graalvm.compiler.bytecode.Bytes; import org.graalvm.compiler.bytecode.Bytes;
import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider; 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.PermanentBailoutException;
import org.graalvm.compiler.core.common.calc.CanonicalCondition; import org.graalvm.compiler.core.common.calc.CanonicalCondition;
import org.graalvm.compiler.core.common.calc.Condition; import org.graalvm.compiler.core.common.calc.Condition;
@ -678,6 +679,8 @@ public class BytecodeParser implements GraphBuilderContext {
private boolean finalBarrierRequired; private boolean finalBarrierRequired;
private ValueNode originalReceiver; private ValueNode originalReceiver;
private final boolean eagerInitializing;
private final boolean uninitializedIsError;
protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, protected BytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method,
int entryBCI, IntrinsicContext intrinsicContext) { int entryBCI, IntrinsicContext intrinsicContext) {
@ -701,6 +704,14 @@ public class BytecodeParser implements GraphBuilderContext {
this.entryBCI = entryBCI; this.entryBCI = entryBCI;
this.parent = parent; 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; assert code.getCode() != null : "method must contain bytecodes: " + method;
if (TraceBytecodeParserLevel.getValue(options) != 0) { if (TraceBytecodeParserLevel.getValue(options) != 0) {
@ -713,6 +724,11 @@ public class BytecodeParser implements GraphBuilderContext {
lnt = code.getLineNumberTable(); lnt = code.getLineNumberTable();
previousLineNumber = -1; previousLineNumber = -1;
} }
assert !GraalOptions.TrackNodeSourcePosition.getValue(options) || graph.trackNodeSourcePosition();
if (graphBuilderConfig.trackNodeSourcePosition() || (parent != null && parent.graph.trackNodeSourcePosition())) {
graph.setTrackNodeSourcePosition();
}
} }
protected GraphBuilderPhase.Instance getGraphBuilderInstance() { protected GraphBuilderPhase.Instance getGraphBuilderInstance() {
@ -807,26 +823,28 @@ public class BytecodeParser implements GraphBuilderContext {
} }
} }
if (method.isSynchronized()) { try (DebugCloseable context = openNodeContext()) {
finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI); if (method.isSynchronized()) {
finishPrepare(lastInstr, BytecodeFrame.BEFORE_BCI);
// add a monitor enter to the start block // add a monitor enter to the start block
methodSynchronizedObject = synchronizedObject(frameState, method); methodSynchronizedObject = synchronizedObject(frameState, method);
frameState.clearNonLiveLocals(startBlock, liveness, true); frameState.clearNonLiveLocals(startBlock, liveness, true);
assert bci() == 0; assert bci() == 0;
genMonitorEnter(methodSynchronizedObject, bci()); 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(); currentBlock = blockMap.getStartBlock();
setEntryState(startBlock, frameState); setEntryState(startBlock, frameState);
if (startBlock.isLoopHeader) { if (startBlock.isLoopHeader) {
@ -1338,6 +1356,8 @@ public class BytecodeParser implements GraphBuilderContext {
protected void genInvokeStatic(int cpi, int opcode) { protected void genInvokeStatic(int cpi, int opcode) {
JavaMethod target = lookupMethod(cpi, opcode); JavaMethod target = lookupMethod(cpi, opcode);
assert !uninitializedIsError ||
(target instanceof ResolvedJavaMethod && ((ResolvedJavaMethod) target).getDeclaringClass().isInitialized()) : target;
genInvokeStatic(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) { protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType, JavaType returnType) {
InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod); InvocationPlugin plugin = graphBuilderConfig.getPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
if (plugin != null) { if (plugin != null) {
@ -2041,11 +2062,13 @@ public class BytecodeParser implements GraphBuilderContext {
} }
InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null; InvocationPluginAssertions assertions = Assertions.assertionsEnabled() ? new InvocationPluginAssertions(plugin, args, targetMethod, resultType) : null;
if (plugin.execute(this, targetMethod, pluginReceiver, args)) { try (DebugCloseable context = openNodeContext(targetMethod)) {
afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
return true; afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
} else { return true;
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType); } else {
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
}
} }
} }
return false; 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 * 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. * overhead of creating and using a nested {@link BytecodeParser} object.
*/ */
@SuppressWarnings("try")
private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) { private boolean tryFastInlineAccessor(ValueNode[] args, ResolvedJavaMethod targetMethod) {
byte[] bytecode = targetMethod.getCode(); byte[] bytecode = targetMethod.getCode();
if (bytecode != null && bytecode.length == ACCESSOR_BYTECODE_LENGTH && if (bytecode != null && bytecode.length == ACCESSOR_BYTECODE_LENGTH &&
@ -2124,10 +2148,12 @@ public class BytecodeParser implements GraphBuilderContext {
if (field instanceof ResolvedJavaField) { if (field instanceof ResolvedJavaField) {
ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get(); ValueNode receiver = invocationPluginReceiver.init(targetMethod, args).get();
ResolvedJavaField resolvedField = (ResolvedJavaField) field; ResolvedJavaField resolvedField = (ResolvedJavaField) field;
genGetField(resolvedField, receiver); try (DebugCloseable context = openNodeContext(targetMethod, 1)) {
notifyBeforeInline(targetMethod); genGetField(resolvedField, receiver);
printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)"); notifyBeforeInline(targetMethod);
notifyAfterInline(targetMethod); printInlining(targetMethod, targetMethod, true, "inline accessor method (bytecode parsing)");
notifyAfterInline(targetMethod);
}
return true; return true;
} }
} }
@ -2562,6 +2588,7 @@ public class BytecodeParser implements GraphBuilderContext {
@Override @Override
public <T extends ValueNode> T append(T v) { public <T extends ValueNode> T append(T v) {
assert !graph.trackNodeSourcePosition() || graph.currentNodeSourcePosition() != null || currentBlock == blockMap.getUnwindBlock() || currentBlock instanceof ExceptionDispatchBlock;
if (v.graph() != null) { if (v.graph() != null) {
return v; return v;
} }
@ -2670,93 +2697,97 @@ public class BytecodeParser implements GraphBuilderContext {
return createTarget(block, state, false, false); return createTarget(block, state, false, false);
} }
@SuppressWarnings("try")
private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) { private FixedNode createTarget(BciBlock block, FrameStateBuilder state, boolean canReuseInstruction, boolean canReuseState) {
assert block != null && state != null; assert block != null && state != null;
assert !block.isExceptionEntry || state.stackSize() == 1; assert !block.isExceptionEntry || state.stackSize() == 1;
if (getFirstInstruction(block) == null) { 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. * 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
FixedNode targetNode; * again.
if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) { */
setFirstInstruction(block, lastInstr); FixedNode targetNode;
lastInstr = null; if (canReuseInstruction && (block.getPredecessorCount() == 1 || !controlFlowSplit) && !block.isLoopHeader && (currentBlock.loops & ~block.loops) == 0) {
} else { setFirstInstruction(block, lastInstr);
setFirstInstruction(block, graph.add(new BeginNode())); lastInstr = null;
} } else {
targetNode = getFirstInstruction(block); setFirstInstruction(block, graph.add(new BeginNode()));
Target target = checkLoopExit(targetNode, block, state); }
FixedNode result = target.fixed; targetNode = getFirstInstruction(block);
FrameStateBuilder currentEntryState = target.state == state ? (canReuseState ? state : state.copy()) : target.state; Target target = checkLoopExit(targetNode, block, state);
setEntryState(block, currentEntryState); FixedNode result = target.fixed;
currentEntryState.clearNonLiveLocals(block, liveness, true); 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); debug.log("createTarget %s: first visit, result: %s", block, targetNode);
return result; 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();
} }
mergeNode.addForwardEnd(end); // We already saw this block before, so we have to merge states.
mergeNode.setNext(next); 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) { 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()) { 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); processBytecode(bci, opcode);
} catch (BailoutException e) { } catch (BailoutException e) {
// Don't wrap bailouts as parser errors // Don't wrap bailouts as parser errors
@ -3017,13 +3048,28 @@ public class BytecodeParser implements GraphBuilderContext {
} }
} }
private DebugCloseable openNodeContext() { private DebugCloseable openNodeContext(FrameStateBuilder state, int startBci) {
if ((graphBuilderConfig.trackNodeSourcePosition() || debug.isDumpEnabledForMethod()) && !parsingIntrinsic()) { if (graph.trackNodeSourcePosition()) {
return graph.withNodeSourcePosition(createBytecodePosition()); return graph.withNodeSourcePosition(state.createBytecodePosition(startBci));
} }
return null; 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. */ /* Also a hook for subclasses. */
protected boolean forceLoopPhis() { protected boolean forceLoopPhis() {
return graph.isOSR(); return graph.isOSR();
@ -3133,7 +3179,7 @@ public class BytecodeParser implements GraphBuilderContext {
genIf(condition, trueSuccessor, falseSuccessor, probability); genIf(condition, trueSuccessor, falseSuccessor, probability);
} }
private double getProfileProbability(boolean negate) { protected double getProfileProbability(boolean negate) {
double probability; double probability;
if (profilingInfo == null) { if (profilingInfo == null) {
probability = 0.5; probability = 0.5;
@ -3433,7 +3479,8 @@ public class BytecodeParser implements GraphBuilderContext {
} }
protected NodeSourcePosition createBytecodePosition() { protected NodeSourcePosition createBytecodePosition() {
return frameState.createBytecodePosition(bci()); NodeSourcePosition bytecodePosition = frameState.createBytecodePosition(bci());
return bytecodePosition;
} }
public void setCurrentFrameState(FrameStateBuilder frameState) { public void setCurrentFrameState(FrameStateBuilder frameState) {
@ -3454,6 +3501,7 @@ public class BytecodeParser implements GraphBuilderContext {
frameState.push(kind, value); frameState.push(kind, value);
} }
@SuppressWarnings("try")
public void loadLocalObject(int index) { public void loadLocalObject(int index) {
ValueNode value = frameState.loadLocal(index, JavaKind.Object); ValueNode value = frameState.loadLocal(index, JavaKind.Object);
@ -3461,7 +3509,9 @@ public class BytecodeParser implements GraphBuilderContext {
int nextBC = stream.readUByte(nextBCI); int nextBC = stream.readUByte(nextBCI);
if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) { if (nextBCI <= currentBlock.endBci && nextBC == Bytecodes.GETFIELD) {
stream.next(); stream.next();
genGetField(stream.readCPI(), Bytecodes.GETFIELD, value); try (DebugCloseable ignored = openNodeContext()) {
genGetField(stream.readCPI(), Bytecodes.GETFIELD, value);
}
} else { } else {
frameState.push(JavaKind.Object, value); frameState.push(JavaKind.Object, value);
} }
@ -3689,6 +3739,17 @@ public class BytecodeParser implements GraphBuilderContext {
genIf(x, cond, y); 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) { protected JavaType lookupType(int cpi, int bytecode) {
maybeEagerlyResolve(cpi, bytecode); maybeEagerlyResolve(cpi, bytecode);
JavaType result = constantPool.lookupType(cpi, bytecode); JavaType result = constantPool.lookupType(cpi, bytecode);
@ -3699,32 +3760,26 @@ public class BytecodeParser implements GraphBuilderContext {
private JavaMethod lookupMethod(int cpi, int opcode) { private JavaMethod lookupMethod(int cpi, int opcode) {
maybeEagerlyResolve(cpi, opcode); maybeEagerlyResolve(cpi, opcode);
JavaMethod result = constantPool.lookupMethod(cpi, opcode); JavaMethod result = constantPool.lookupMethod(cpi, opcode);
/* assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaMethod : result;
* 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;
return result; return result;
} }
protected JavaField lookupField(int cpi, int opcode) { protected JavaField lookupField(int cpi, int opcode) {
maybeEagerlyResolve(cpi, opcode); maybeEagerlyResolve(cpi, opcode);
JavaField result = constantPool.lookupField(cpi, method, opcode); JavaField result = constantPool.lookupField(cpi, method, opcode);
assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
if (graphBuilderConfig.eagerResolving()) { if (parsingIntrinsic() || eagerInitializing) {
assert !graphBuilderConfig.unresolvedIsError() || result instanceof ResolvedJavaField : "Not resolved: " + result;
if (result instanceof ResolvedJavaField) { if (result instanceof ResolvedJavaField) {
ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass(); ResolvedJavaType declaringClass = ((ResolvedJavaField) result).getDeclaringClass();
if (!declaringClass.isInitialized()) { if (!declaringClass.isInitialized()) {
assert declaringClass.isInterface() : "Declaring class not initialized but not an interface? " + declaringClass; // Even with eager initialization, superinterfaces are not always initialized.
declaringClass.initialize(); // 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; 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). * the compiler (e.g., https://github.com/graalvm/graal-core/pull/232/files#r90788550).
*/ */
synchronized (BytecodeParser.class) { 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) { void genNewInstance(JavaType type) {
if (!(type instanceof ResolvedJavaType) || !((ResolvedJavaType) type).isInitialized()) { if (!(type instanceof ResolvedJavaType)) {
handleUnresolvedNewInstance(type); handleUnresolvedNewInstance(type);
return; return;
} }
ResolvedJavaType resolvedType = (ResolvedJavaType) type; ResolvedJavaType resolvedType = (ResolvedJavaType) type;
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
if (!resolvedType.isInitialized() && classInitializationPlugin == null) {
handleUnresolvedNewInstance(type);
return;
}
ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes(); ResolvedJavaType[] skippedExceptionTypes = this.graphBuilderConfig.getSkippedExceptionTypes();
if (skippedExceptionTypes != null) { if (skippedExceptionTypes != null) {
@ -3888,7 +3953,6 @@ public class BytecodeParser implements GraphBuilderContext {
} }
} }
ClassInitializationPlugin classInitializationPlugin = graphBuilderConfig.getPlugins().getClassInitializationPlugin();
if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) { if (classInitializationPlugin != null && classInitializationPlugin.shouldApply(this, resolvedType)) {
FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null); FrameState stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
classInitializationPlugin.apply(this, resolvedType, stateBefore); classInitializationPlugin.apply(this, resolvedType, stateBefore);
@ -4078,7 +4142,7 @@ public class BytecodeParser implements GraphBuilderContext {
} }
} }
private boolean needsExplicitException() { protected boolean needsExplicitException() {
BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode(); BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode();
if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) { if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) {
return true; return true;
@ -4163,7 +4227,7 @@ public class BytecodeParser implements GraphBuilderContext {
private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) { private ResolvedJavaField resolveStaticFieldAccess(JavaField field, ValueNode value) {
if (field instanceof ResolvedJavaField) { if (field instanceof ResolvedJavaField) {
ResolvedJavaField resolvedField = (ResolvedJavaField) field; ResolvedJavaField resolvedField = (ResolvedJavaField) field;
if (resolvedField.getDeclaringClass().isInitialized()) { if (resolvedField.getDeclaringClass().isInitialized() || graphBuilderConfig.getPlugins().getClassInitializationPlugin() != null) {
return resolvedField; return resolvedField;
} }
/* /*

View File

@ -58,7 +58,7 @@ public class BytecodeParserOptions {
public static final OptionKey<Boolean> TraceParserPlugins = new OptionKey<>(false); public static final OptionKey<Boolean> TraceParserPlugins = new OptionKey<>(false);
@Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug) @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) @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false); public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);

View File

@ -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.POP2;
import static org.graalvm.compiler.bytecode.Bytecodes.SWAP; import static org.graalvm.compiler.bytecode.Bytecodes.SWAP;
import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; 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 static org.graalvm.compiler.nodes.FrameState.TWO_SLOT_MARKER;
import java.util.ArrayList; 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.code.BytecodeFrame;
import jdk.vm.ci.meta.Assumptions; import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
@ -112,8 +110,6 @@ public final class FrameStateBuilder implements SideEffectsState {
*/ */
private List<StateSplit> sideEffects; private List<StateSplit> sideEffects;
private JavaConstant constantReceiver;
/** /**
* Creates a new frame state builder for the given method and the given target graph. * 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]; locals[javaIndex] = arguments[index];
javaIndex = 1; javaIndex = 1;
index = 1; index = 1;
constantReceiver = locals[0].asJavaConstant();
} }
Signature sig = getMethod().getSignature(); Signature sig = getMethod().getSignature();
int max = sig.getParameterCount(false); int max = sig.getParameterCount(false);
@ -310,7 +305,7 @@ public final class FrameStateBuilder implements SideEffectsState {
public FrameState create(int bci, StateSplit forStateSplit) { public FrameState create(int bci, StateSplit forStateSplit) {
if (parser != null && parser.parsingIntrinsic()) { 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); return parser.intrinsicContext.createFrameState(parser.getGraph(), this, forStateSplit, sourcePosition);
} }
@ -354,25 +349,14 @@ public final class FrameStateBuilder implements SideEffectsState {
} }
public NodeSourcePosition createBytecodePosition(int bci) { public NodeSourcePosition createBytecodePosition(int bci) {
return createBytecodePosition(bci, HideSubstitutionStates.getValue(parser.graph.getOptions()));
}
private NodeSourcePosition createBytecodePosition(int bci, boolean hideSubstitutionStates) {
BytecodeParser parent = parser.getParent(); BytecodeParser parent = parser.getParent();
if (hideSubstitutionStates) { NodeSourcePosition position = create(bci, parent);
if (parser.parsingIntrinsic()) { return position;
// 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);
} }
private NodeSourcePosition create(JavaConstant receiver, int bci, BytecodeParser parent, boolean hideSubstitutionStates) { private NodeSourcePosition create(int bci, BytecodeParser parent) {
if (outerSourcePosition == null && parent != null) { 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) { if (bci == BytecodeFrame.AFTER_EXCEPTION_BCI && parent != null) {
return FrameState.toSourcePosition(outerFrameState); return FrameState.toSourcePosition(outerFrameState);
@ -380,7 +364,7 @@ public final class FrameStateBuilder implements SideEffectsState {
if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) { if (bci == BytecodeFrame.INVALID_FRAMESTATE_BCI) {
throw shouldNotReachHere(); throw shouldNotReachHere();
} }
return new NodeSourcePosition(receiver, outerSourcePosition, code.getMethod(), bci); return new NodeSourcePosition(outerSourcePosition, code.getMethod(), bci);
} }
public FrameStateBuilder copy() { public FrameStateBuilder copy() {

View File

@ -22,25 +22,14 @@
*/ */
package org.graalvm.compiler.jtt; package org.graalvm.compiler.jtt;
import static java.lang.reflect.Modifier.isStatic;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.graalvm.compiler.core.test.GraalCompilerTest; 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.options.OptionValues;
import org.graalvm.compiler.phases.PhaseSuite;
import org.graalvm.compiler.phases.tiers.HighTierContext;
import org.junit.Assert; import org.junit.Assert;
import jdk.vm.ci.code.InstalledCode;
import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaMethod;
/** /**
@ -66,45 +55,35 @@ public class JTTTest extends GraalCompilerTest {
} }
@Override @Override
protected StructuredGraph parse(Builder builder, PhaseSuite<HighTierContext> graphBuilderSuite) { protected Object[] getArgumentToBind() {
StructuredGraph graph = super.parse(builder, graphBuilderSuite); return argsToBind;
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;
} }
@Override /**
protected InstalledCode getCode(ResolvedJavaMethod method, StructuredGraph graph, boolean forceCompile, boolean installAsDefault, OptionValues options) { * If non-null, then this is a test for a method returning a {@code double} value that must be
return super.getCode(method, graph, argsToBind != null, installAsDefault, options); * within {@code ulpDelta}s of the expected value.
} */
protected Double ulpDelta;
Double delta;
@Override @Override
protected void assertDeepEquals(Object expected, Object actual) { protected void assertDeepEquals(Object expected, Object actual) {
if (delta != null) { if (ulpDelta != null) {
Assert.assertEquals(((Number) expected).doubleValue(), ((Number) actual).doubleValue(), delta); 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 { } else {
super.assertDeepEquals(expected, actual); 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) { protected void runTest(String name, Object... args) {
runTest(getInitialOptions(), name, args); runTest(getInitialOptions(), name, args);
} }

View File

@ -24,10 +24,8 @@
package org.graalvm.compiler.jtt.hotpath; package org.graalvm.compiler.jtt.hotpath;
import org.junit.Ignore;
import org.junit.Test;
import org.graalvm.compiler.jtt.JTTTest; import org.graalvm.compiler.jtt.JTTTest;
import org.junit.Test;
/* /*
*/ */
@ -101,17 +99,16 @@ public class HP_series extends JTTTest {
return (0.0); return (0.0);
} }
/* /**
* This test is sensible to the implementation of Math.pow, cos and sin. Since for these * This test is sensitive to the implementation of {@link Math#pow}, {@link Math#cos} and
* functions, the specs says "The computed result must be within 1 ulp of the exact result", * {@link Math#sin(double)}. Since for these functions, the specs says "The computed result must
* different implementation may return different results. The 11 ulp delta allowed for test(100) * be within 1 ulp of the exact result", different implementation may return different results.
* tries to account for that but is not guaranteed to work forever. * 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 @Test
public void run0() throws Throwable { public void run0() throws Throwable {
double expected = 0.6248571921291398d; ulpDelta = 11.0D;
runTestWithDelta(11 * Math.ulp(expected), "test", 100); runTest("test", 100);
} }
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -78,4 +79,10 @@ public class Math_abs extends JTTTest {
runTest("test", java.lang.Double.NaN); runTest("test", java.lang.Double.NaN);
} }
@Test
public void run7() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -58,4 +59,10 @@ public class Math_cos extends JTTTest {
runTest("test", java.lang.Double.POSITIVE_INFINITY); runTest("test", java.lang.Double.POSITIVE_INFINITY);
} }
@Test
public void run3() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

@ -22,14 +22,12 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.junit.Ignore; import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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) { public static double test(double arg) {
return Math.exp(arg); return Math.exp(arg);
@ -65,9 +63,19 @@ public class Math_exp extends JTTTest {
runTest("test", 0.0D); runTest("test", 0.0D);
} }
@Ignore("java.lang.AssertionError: expected:<2.718281828459045> but was:<2.7182818284590455>")
@Test @Test
public void run6() { public void run6() {
runTest("test", 1.0D); runTest("test", 1.0D);
} }
@Test
public void run7() {
runTest("test", -1024D);
}
@Test
public void run8() {
OptionValues options = getInitialOptions();
testManyValues(options, getResolvedJavaMethod("test"));
}
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -78,4 +79,10 @@ public class Math_log extends JTTTest {
runTest("test", -0.0d); runTest("test", -0.0d);
} }
@Test
public void run7() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

@ -22,9 +22,11 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.jtt.JTTTest;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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 { public void run10() throws Throwable {
runTest("test", 0.999998, 1500000.0); 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);
}
}
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -83,4 +84,10 @@ public class Math_sin extends JTTTest {
runTest("test", 0.0d); runTest("test", 0.0d);
} }
@Test
public void run5() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -78,4 +79,10 @@ public class Math_sqrt extends JTTTest {
runTest("test", -0.0d); runTest("test", -0.0d);
} }
@Test
public void run7() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

@ -22,13 +22,14 @@
*/ */
package org.graalvm.compiler.jtt.lang; package org.graalvm.compiler.jtt.lang;
import org.graalvm.compiler.options.OptionValues;
import org.junit.Test; 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") @SuppressWarnings("serial")
public static class NaN extends Throwable { public static class NaN extends Throwable {
@ -68,4 +69,10 @@ public class Math_tan extends JTTTest {
runTest("test", 0.0d); runTest("test", 0.0d);
} }
@Test
public void run5() {
OptionValues options = getInitialOptions();
ResolvedJavaMethod method = getResolvedJavaMethod("test");
testManyValues(options, method);
}
} }

View File

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

View File

@ -227,13 +227,15 @@ public class AArch64Call {
masm.ensureUniquePC(); masm.ensureUniquePC();
} }
public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget target) { public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) {
int before = masm.position(); try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
// Address is fixed up later by c++ code. int before = masm.position();
masm.jmp(); masm.movNativeAddress(scratch.getRegister(), 0L);
int after = masm.position(); masm.jmp(scratch.getRegister());
crb.recordDirectCall(before, after, target, null); int after = masm.position();
masm.ensureUniquePC(); crb.recordDirectCall(before, after, callTarget, null);
masm.ensureUniquePC();
}
} }
public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) { public static void indirectJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register dst, InvokeTarget target) {

View File

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

View File

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

View File

@ -22,6 +22,11 @@
*/ */
package org.graalvm.compiler.lir.amd64; 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.asm.amd64.AMD64Assembler.ConditionFlag.Equal;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC; import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE; 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.LIRInstruction.OperandFlag.UNINITIALIZED;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant; import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant; 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.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.AMD64Address;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MIOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp; import org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64MOp;
import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize; import org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize;
import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler; 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.spi.LIRKindTool;
import org.graalvm.compiler.core.common.type.DataPointerConstant; import org.graalvm.compiler.core.common.type.DataPointerConstant;
import org.graalvm.compiler.debug.GraalError; 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.StandardOp.ValueMoveOp;
import org.graalvm.compiler.lir.VirtualStackSlot; import org.graalvm.compiler.lir.VirtualStackSlot;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
import org.graalvm.compiler.options.OptionValues;
import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.amd64.AMD64;
import jdk.vm.ci.amd64.AMD64Kind; import jdk.vm.ci.amd64.AMD64Kind;
@ -763,7 +764,7 @@ public class AMD64Move {
@Def({REG, HINT}) private AllocatableValue result; @Def({REG, HINT}) private AllocatableValue result;
@Use({REG, CONST}) private Value input; @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, protected PointerCompressionOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) { AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
@ -777,8 +778,8 @@ public class AMD64Move {
this.lirKindTool = lirKindTool; this.lirKindTool = lirKindTool;
} }
protected boolean hasBase(CompilationResultBuilder crb) { public static boolean hasBase(OptionValues options, CompressEncoding encoding) {
return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase(); return GeneratePIC.getValue(options) || encoding.hasBase();
} }
public final Value getInput() { public final Value getInput() {
@ -820,7 +821,7 @@ public class AMD64Move {
move(lirKindTool.getObjectKind(), crb, masm); move(lirKindTool.getObjectKind(), crb, masm);
Register resReg = asRegister(getResult()); Register resReg = asRegister(getResult());
if (hasBase(crb)) { if (hasBase(crb.getOptions(), encoding)) {
Register baseReg = getBaseRegister(); Register baseReg = getBaseRegister();
if (!nonNull) { if (!nonNull) {
masm.testq(resReg, resReg); masm.testq(resReg, resReg);
@ -852,15 +853,15 @@ public class AMD64Move {
@Override @Override
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) { public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
move(lirKindTool.getNarrowOopKind(), crb, masm); move(lirKindTool.getNarrowOopKind(), crb, masm);
emitUncompressCode(masm, asRegister(getResult()), getShift(), hasBase(crb.getOptions(), encoding) ? getBaseRegister() : null, nonNull);
}
Register resReg = asRegister(getResult()); public static void emitUncompressCode(AMD64MacroAssembler masm, Register resReg, int shift, Register baseReg, boolean nonNull) {
int shift = getShift();
if (shift != 0) { if (shift != 0) {
masm.shlq(resReg, shift); masm.shlq(resReg, shift);
} }
if (hasBase(crb)) { if (baseReg != null) {
Register baseReg = getBaseRegister();
if (nonNull) { if (nonNull) {
masm.addq(resReg, baseReg); masm.addq(resReg, baseReg);
return; return;

View File

@ -96,7 +96,11 @@ public class LIRInstructionClass<T> extends LIRIntrospection<T> {
try { try {
Field field = clazz.getDeclaredField("TYPE"); Field field = clazz.getDeclaredField("TYPE");
field.setAccessible(true); 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) { } catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -53,7 +53,11 @@ public final class GlobalLivenessInfo {
public final int[] emptySet; public final int[] emptySet;
public Builder(LIR lir) { 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]; emptySet = new int[0];
} }
@ -97,10 +101,8 @@ public final class GlobalLivenessInfo {
private final Value[][] blockToLocIn; private final Value[][] blockToLocIn;
private final Value[][] blockToLocOut; private final Value[][] blockToLocOut;
private GlobalLivenessInfo(LIR lir) { private GlobalLivenessInfo(int numVariables, int numBlocks) {
int numVariables = lir.numVariables();
variables = new Variable[numVariables]; variables = new Variable[numVariables];
int numBlocks = lir.getControlFlowGraph().getBlocks().length;
blockToVarIn = new int[numBlocks][]; blockToVarIn = new int[numBlocks][];
blockToVarOut = new int[numBlocks][]; blockToVarOut = new int[numBlocks][];
blockToLocIn = new Value[numBlocks][]; blockToLocIn = new Value[numBlocks][];

View File

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

View File

@ -84,32 +84,58 @@ public final class TraceGlobalMoveResolutionPhase {
DebugContext debug = lir.getDebug(); DebugContext debug = lir.getDebug();
try (Indent indent = debug.logAndIndent("Trace global move resolution")) { try (Indent indent = debug.logAndIndent("Trace global move resolution")) {
for (Trace trace : resultTraces.getTraces()) { for (Trace trace : resultTraces.getTraces()) {
for (AbstractBlockBase<?> fromBlock : trace.getBlocks()) { resolveTrace(resultTraces, livenessInfo, lir, moveResolver, trace);
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())) {
final ArrayList<LIRInstruction> instructions; private static void resolveTrace(TraceBuilderResult resultTraces, GlobalLivenessInfo livenessInfo, LIR lir, TraceGlobalMoveResolver moveResolver, Trace trace) {
final int insertIdx; AbstractBlockBase<?>[] traceBlocks = trace.getBlocks();
if (fromBlock.getSuccessorCount() == 1) { int traceLength = traceBlocks.length;
instructions = lir.getLIRforBlock(fromBlock); // all but the last block
insertIdx = instructions.size() - 1; AbstractBlockBase<?> nextBlock = traceBlocks[0];
} else { for (int i = 1; i < traceLength; i++) {
assert toBlock.getPredecessorCount() == 1; AbstractBlockBase<?> fromBlock = nextBlock;
instructions = lir.getLIRforBlock(toBlock); nextBlock = traceBlocks[i];
insertIdx = 1; if (fromBlock.getSuccessorCount() > 1) {
} for (AbstractBlockBase<?> toBlock : fromBlock.getSuccessors()) {
if (toBlock != nextBlock) {
moveResolver.setInsertPosition(instructions, insertIdx); interTraceEdge(resultTraces, livenessInfo, lir, moveResolver, fromBlock, toBlock);
resolveEdge(lir, livenessInfo, moveResolver, fromBlock, toBlock);
moveResolver.resolveAndAppendMoves();
}
}
} }
} }
} }
} }
// 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) { private static void resolveEdge(LIR lir, GlobalLivenessInfo livenessInfo, TraceGlobalMoveResolver moveResolver, AbstractBlockBase<?> fromBlock, AbstractBlockBase<?> toBlock) {
@ -129,6 +155,10 @@ public final class TraceGlobalMoveResolutionPhase {
// GLI // GLI
Value[] locFrom = livenessInfo.getOutLocation(fromBlock); Value[] locFrom = livenessInfo.getOutLocation(fromBlock);
Value[] locTo = livenessInfo.getInLocation(toBlock); 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; assert locFrom.length == locTo.length;
for (int i = 0; i < locFrom.length; i++) { for (int i = 0; i < locFrom.length; i++) {

View File

@ -36,19 +36,6 @@ import jdk.vm.ci.meta.Value;
public class TraceUtil { 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) { public static boolean isShadowedRegisterValue(Value value) {
assert value != null; assert value != null;
return value instanceof ShadowedRegisterValue; return value instanceof ShadowedRegisterValue;

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.LIRValueUtil.isVariable;
import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace; import static org.graalvm.compiler.lir.alloc.trace.TraceUtil.isTrivialTrace;
import java.util.Arrays;
import java.util.EnumSet; import java.util.EnumSet;
import org.graalvm.compiler.core.common.alloc.Trace; 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.core.common.cfg.AbstractBlockBase;
import org.graalvm.compiler.lir.LIR; 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.OperandFlag;
import org.graalvm.compiler.lir.LIRInstruction.OperandMode; import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
import org.graalvm.compiler.lir.StandardOp.JumpOp; 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 * 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}. * than the {@link LabelOp} and the {@link JumpOp}.
*/ */
final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> { public final class TrivialTraceAllocator extends TraceAllocationPhase<TraceAllocationPhase.TraceAllocationContext> {
@Override @Override
protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) { protected void run(TargetDescription target, LIRGenerationResult lirGenRes, Trace trace, TraceAllocationContext context) {
LIR lir = lirGenRes.getLIR(); LIR lir = lirGenRes.getLIR();
TraceBuilderResult resultTraces = context.resultTraces;
assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace; assert isTrivialTrace(lir, trace) : "Not a trivial trace! " + trace;
AbstractBlockBase<?> block = trace.getBlocks()[0]; 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; GlobalLivenessInfo livenessInfo = context.livenessInfo;
collectMapping(block, pred, livenessInfo, variableMap); allocate(block, pred, livenessInfo, SSAUtil.phiOutOrNull(lir, block));
assignLocations(lir, block, livenessInfo, variableMap);
} }
/** public static void allocate(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, LIRInstruction jump) {
* Collects the mapping from variable to location. Additionally the // exploit that the live sets are sorted
* {@link GlobalLivenessInfo#setInLocations incoming location array} is set. assert TraceAssertions.liveSetsAreSorted(livenessInfo, block);
*/ assert TraceAssertions.liveSetsAreSorted(livenessInfo, pred);
private static void collectMapping(AbstractBlockBase<?> block, AbstractBlockBase<?> pred, GlobalLivenessInfo livenessInfo, Value[] variableMap) {
// setup incoming variables/locations
final int[] blockIn = livenessInfo.getBlockIn(block); final int[] blockIn = livenessInfo.getBlockIn(block);
final Value[] predLocOut = livenessInfo.getOutLocation(pred); final Value[] predLocOut = livenessInfo.getOutLocation(pred);
final Value[] locationIn = new Value[blockIn.length]; int inLenght = blockIn.length;
for (int i = 0; i < blockIn.length; i++) {
int varNum = blockIn[i]; // setup outgoing variables/locations
if (varNum >= 0) { final int[] blockOut = livenessInfo.getBlockOut(block);
Value location = predLocOut[i]; int outLength = blockOut.length;
variableMap[varNum] = location; final Value[] locationOut = new Value[outLength];
locationIn[i] = location;
} else { assert outLength <= inLenght : "Trivial Trace! There cannot be more outgoing values than incoming.";
locationIn[i] = Value.ILLEGAL; 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);
}
} }
/** private static void handlePhiOut(LIRInstruction jump, int[] varIn, Value[] locIn) {
* 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);
// handle outgoing phi values // handle outgoing phi values
ValueProcedure outputConsumer = new ValueProcedure() { ValueProcedure outputConsumer = new ValueProcedure() {
@Override @Override
public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) { public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
if (isVariable(value)) { 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; return value;
} }
}; };
JumpOp jump = SSAUtil.phiOut(lir, block);
// Jumps have only alive values (outgoing phi values) // Jumps have only alive values (outgoing phi values)
jump.forEachAlive(outputConsumer); jump.forEachAlive(outputConsumer);
} }

View File

@ -501,11 +501,12 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
try (Indent indent = debug.logAndIndent("handle block %s", block)) { try (Indent indent = debug.logAndIndent("handle block %s", block)) {
currentInstructions = getLIR().getLIRforBlock(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); LIRInstruction inst = currentInstructions.get(currentInstructionIndex);
if (inst != null) { if (inst != null) {
inst.setId(currentOpId); inst.setId(currentOpId);
allocateInstruction(inst, block); allocateInstruction(inst, block, currentInstructionIndex == 0, currentInstructionIndex == lastInstIdx);
} }
} }
allocatedBlocks.set(block.getId()); allocatedBlocks.set(block.getId());
@ -514,7 +515,7 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
} }
@SuppressWarnings("try") @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; assert op != null && op.id() == currentOpId;
try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) { try (Indent indent = debug.logAndIndent("handle inst: %d: %s", op.id(), op)) {
try (Indent indent1 = debug.logAndIndent("output pos")) { try (Indent indent1 = debug.logAndIndent("output pos")) {
@ -537,7 +538,8 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
// should have // should have
op.forEachTemp(allocStackOrRegisterProcedure); op.forEachTemp(allocStackOrRegisterProcedure);
op.forEachOutput(allocStackOrRegisterProcedure); op.forEachOutput(allocStackOrRegisterProcedure);
if (op instanceof LabelOp) { if (isLabel) {
assert op instanceof LabelOp;
processIncoming(block, op); processIncoming(block, op);
} }
} }
@ -551,7 +553,8 @@ public final class BottomUpAllocator extends TraceAllocationPhase<TraceAllocatio
op.forEachInput(allocRegisterProcedure); op.forEachInput(allocRegisterProcedure);
op.forEachAlive(allocStackOrRegisterProcedure); op.forEachAlive(allocStackOrRegisterProcedure);
if (op instanceof BlockEndOp) { if (isBlockEnd) {
assert op instanceof BlockEndOp;
processOutgoing(block, op); processOutgoing(block, op);
} }
op.forEachState(allocStackOrRegisterProcedure); op.forEachState(allocStackOrRegisterProcedure);

View File

@ -112,10 +112,6 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
buildIntervals(); 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 * Count instructions in all blocks. The numbering follows the
* {@linkplain TraceLinearScan#sortedBlocks() register allocation order}. * {@linkplain TraceLinearScan#sortedBlocks() register allocation order}.
@ -621,26 +617,29 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
assert allocator.instructionForId(opId) == op : "must match"; 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") @SuppressWarnings("try")
private void addInterTraceHints() { private void addInterTraceHints() {
try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) { try (DebugContext.Scope s = debug.scope("InterTraceHints", allocator)) {
GlobalLivenessInfo livenessInfo = allocator.getGlobalLivenessInfo(); AbstractBlockBase<?> traceHeadBlock = sortedBlocks()[0];
// set hints for phi/incoming intervals if (traceHeadBlock.getPredecessorCount() == 0) {
for (AbstractBlockBase<?> block : sortedBlocks()) { return;
LabelOp label = (LabelOp) getLIR().getLIRforBlock(block).get(0);
for (AbstractBlockBase<?> pred : block.getPredecessors()) {
addInterTraceHints(livenessInfo, pred, block, label);
}
} }
} catch (Throwable e) { assert traceHeadBlock.getPredecessorCount() == 1 : "Trace head with more than one predecessor?!" + traceHeadBlock;
throw debug.handle(e);
}
}
private void addInterTraceHints(GlobalLivenessInfo livenessInfo, AbstractBlockBase<?> from, AbstractBlockBase<?> to, LabelOp label) { AbstractBlockBase<?> pred = traceHeadBlock.getPredecessors()[0];
if (isAllocated(to, from)) { assert traceBuilderResult.getTraceForBlock(pred).getId() < traceBuilderResult.getTraceForBlock(traceHeadBlock).getId() : "Not yet allocated? " + pred;
int[] liveVars = livenessInfo.getBlockIn(to);
Value[] outLocation = livenessInfo.getOutLocation(from); 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++) { for (int i = 0; i < liveVars.length; i++) {
int varNum = liveVars[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) { 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); TraceInterval to = allocator.intervalFor(varNum);
if (to == null) { if (to == null) {
// variable not live -> do nothing // variable not live -> do nothing
return; return;
} }
if (isVariableOrRegister(fromValue)) { if (isRegister(fromValue)) {
IntervalHint from = getIntervalHint((AllocatableValue) fromValue); IntervalHint from = allocator.getOrCreateFixedInterval(asRegisterValue(fromValue));
setHint(label, to, from, debug); setHint(label, to, from, debug);
} else if (isStackSlotValue(fromValue)) { } else if (isStackSlotValue(fromValue)) {
setSpillSlot(label, to, (AllocatableValue) fromValue, debug); setSpillSlot(label, to, (AllocatableValue) fromValue, debug);
@ -672,8 +673,6 @@ public final class TraceLinearScanLifetimeAnalysisPhase extends TraceLinearScanA
IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister()); IntervalHint from = getIntervalHint(shadowedRegisterValue.getRegister());
setHint(label, to, from, debug); setHint(label, to, from, debug);
setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug); setSpillSlot(label, to, shadowedRegisterValue.getStackSlot(), debug);
} else {
throw GraalError.shouldNotReachHere();
} }
} }

View File

@ -252,11 +252,16 @@ public interface LIRGeneratorTool extends DiagnosticLIRGeneratorTool, ValueKindF
Variable emitByteSwap(Value operand); 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); Variable emitArrayEquals(JavaKind kind, Value array1, Value array2, Value length);
@SuppressWarnings("unused") @SuppressWarnings("unused")
default Variable emitStringIndexOf(Value sourcePointer, Value sourceCount, Value targetPointer, Value targetCount, int constantTargetCount) { 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); void emitBlackhole(Value operand);

View File

@ -39,6 +39,13 @@ public class LIRPhaseSuite<C> extends LIRPhase<C> {
phases = new ArrayList<>(); 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. * 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