--- a/make/CompileJavaModules.gmk Thu May 31 10:14:41 2018 -0700
+++ b/make/CompileJavaModules.gmk Thu May 31 10:38:05 2018 -0700
@@ -444,11 +444,13 @@
jdk.internal.vm.compiler_EXCLUDES += \
jdk.internal.vm.compiler.collections.test \
+ org.graalvm.compiler.processor \
org.graalvm.compiler.core.match.processor \
org.graalvm.compiler.nodeinfo.processor \
org.graalvm.compiler.options.processor \
org.graalvm.compiler.serviceprovider.processor \
- org.graalvm.compiler.replacements.verifier \
+ org.graalvm.compiler.replacements.processor \
+ org.graalvm.compiler.replacements.jdk9.test \
org.graalvm.compiler.api.directives.test \
org.graalvm.compiler.api.test \
org.graalvm.compiler.asm.aarch64.test \
--- a/make/CompileToolsHotspot.gmk Thu May 31 10:14:41 2018 -0700
+++ b/make/CompileToolsHotspot.gmk Thu May 31 10:38:05 2018 -0700
@@ -47,34 +47,8 @@
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_MATCH_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
- $(SRC_DIR)/jdk.internal.vm.compiler.word/src \
- $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
- $(SRC_DIR)/org.graalvm.compiler.core/src \
- $(SRC_DIR)/org.graalvm.compiler.core.common/src \
+ $(SRC_DIR)/org.graalvm.compiler.processor/src \
$(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
- $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
- $(SRC_DIR)/org.graalvm.compiler.asm/src \
- $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
- $(SRC_DIR)/org.graalvm.compiler.code/src \
- $(SRC_DIR)/org.graalvm.compiler.debug/src \
- $(SRC_DIR)/org.graalvm.compiler.graph/src \
- $(SRC_DIR)/org.graalvm.compiler.lir/src \
- $(SRC_DIR)/org.graalvm.compiler.loop/src \
- $(SRC_DIR)/org.graalvm.compiler.loop.phases/src \
- $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
- $(SRC_DIR)/org.graalvm.compiler.nodes/src \
- $(SRC_DIR)/org.graalvm.compiler.options/src \
- $(SRC_DIR)/org.graalvm.compiler.phases/src \
- $(SRC_DIR)/org.graalvm.compiler.phases.common/src \
- $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
- $(SRC_DIR)/org.graalvm.compiler.virtual/src \
- $(SRC_DIR)/org.graalvm.graphio/src \
- $(SRC_DIR)/org.graalvm.util/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
, \
EXCLUDE_FILES := $(EXCLUDE_FILES), \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.match.processor, \
@@ -88,7 +62,7 @@
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_NODEINFO_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
- $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
+ $(SRC_DIR)/org.graalvm.compiler.processor/src \
$(SRC_DIR)/org.graalvm.compiler.nodeinfo.processor/src \
, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.nodeinfo.processor, \
@@ -102,10 +76,8 @@
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
- $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
- $(SRC_DIR)/org.graalvm.compiler.options/src \
+ $(SRC_DIR)/org.graalvm.compiler.processor/src \
$(SRC_DIR)/org.graalvm.compiler.options.processor/src \
- $(SRC_DIR)/org.graalvm.util/src \
, \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor, \
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.options.processor.jar, \
@@ -115,44 +87,26 @@
##############################################################################
- $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER, \
+ $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
- $(SRC_DIR)/jdk.internal.vm.compiler.word/src \
- $(SRC_DIR)/jdk.internal.vm.compiler.collections/src \
- $(SRC_DIR)/org.graalvm.compiler.bytecode/src \
- $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
- $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
- $(SRC_DIR)/org.graalvm.compiler.code/src \
- $(SRC_DIR)/org.graalvm.compiler.core.common/src \
- $(SRC_DIR)/org.graalvm.compiler.debug/src \
- $(SRC_DIR)/org.graalvm.compiler.graph/src \
- $(SRC_DIR)/org.graalvm.compiler.nodeinfo/src \
- $(SRC_DIR)/org.graalvm.compiler.options/src \
- $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
- $(SRC_DIR)/org.graalvm.graphio/src \
- $(SRC_DIR)/org.graalvm.util/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.code/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.common/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.meta/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.runtime/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
+ $(SRC_DIR)/org.graalvm.compiler.processor/src \
+ $(SRC_DIR)/org.graalvm.compiler.replacements.processor/src \
, \
EXCLUDE_FILES := $(EXCLUDE_FILES), \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier, \
JAR := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.replacements.verifier.jar, \
))
- TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_VERIFIER)
+ TARGETS += $(BUILD_VM_COMPILER_REPLACEMENTS_PROCESSOR)
##############################################################################
$(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_SERVICEPROVIDER_PROCESSOR, \
SETUP := GENERATE_OLDBYTECODE, \
SRC := \
- $(SRC_DIR)/org.graalvm.compiler.serviceprovider/src \
+ $(SRC_DIR)/org.graalvm.compiler.processor/src \
$(SRC_DIR)/org.graalvm.compiler.serviceprovider.processor/src \
- $(VM_CI_SRC_DIR)/jdk.vm.ci.services/src \
, \
EXCLUDE_FILES := $(EXCLUDE_FILES), \
BIN := $(BUILDTOOLS_OUTPUTDIR)/jdk.vm.compiler.serviceprovider.processor, \
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/AOTBackend.java Thu May 31 10:38:05 2018 -0700
@@ -139,7 +139,7 @@
CompilationResult compilationResult = new CompilationResult(id, isImmutablePIC);
return GraalCompiler.compileGraph(graph, resolvedMethod, providers, backend, graphBuilderSuite, OptimisticOptimizations.ALL, profilingInfo, getSuites(), getLirSuites(),
- compilationResult, CompilationResultBuilderFactory.Default);
+ compilationResult, CompilationResultBuilderFactory.Default, true);
} catch (Throwable e) {
main.handleError(resolvedMethod, e, " (compiling graph)");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64Assembler.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -63,11 +63,15 @@
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMSUB;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FMUL;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FNEG;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTM;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTN;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTP;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FRINTZ;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSQRT;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.FSUB;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HINT;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.HLT;
+import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDADD;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAR;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDAXR;
import static org.graalvm.compiler.asm.aarch64.AArch64Assembler.Instruction.LDP;
@@ -480,6 +484,9 @@
private static final int CASAcquireOffset = 22;
private static final int CASReleaseOffset = 15;
+ private static final int LDADDAcquireOffset = 23;
+ private static final int LDADDReleaseOffset = 22;
+
/**
* Encoding for all instructions.
*/
@@ -511,6 +518,7 @@
STP(0b0 << 22),
CAS(0x08A07C00),
+ LDADD(0x38200000),
ADR(0x00000000),
ADRP(0x80000000),
@@ -573,6 +581,9 @@
FSQRT(0x00018000),
FNEG(0x00010000),
+ FRINTM(0x00050000),
+ FRINTN(0x00040000),
+ FRINTP(0x00048000),
FRINTZ(0x00058000),
FADD(0x00002000),
@@ -1330,7 +1341,18 @@
emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt));
}
- /* Compare And Swap */
+ /**
+ * Compare And Swap word or doubleword in memory. This reads a value from an address rn,
+ * compares it against a given value rs, and, if equal, stores the value rt to memory. The value
+ * read from address rn is stored in register rs.
+ *
+ * @param size size of bits read from memory. Must be 32 or 64.
+ * @param rs general purpose register to be compared and loaded. May not be null.
+ * @param rt general purpose register to be conditionally stored. May not be null.
+ * @param rn general purpose register containing the address from which to read.
+ * @param acquire boolean value signifying if the load should use acquire semantics.
+ * @param release boolean value signifying if the store should use release semantics.
+ */
public void cas(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) {
assert size == 32 || size == 64;
int transferSize = NumUtil.log2Ceil(size / 8);
@@ -1344,17 +1366,42 @@
emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << CASAcquireOffset | (release ? 1 : 0) << CASReleaseOffset);
}
+ /**
+ * Atomic add. This reads a value from an address rn, stores the value in rt, and adds the value
+ * in rs to it, and stores the result back at address rn. The initial value read from memory is
+ * stored in rt.
+ *
+ * @param size size of operand to read from memory. Must be 8, 16, 32, or 64.
+ * @param rs general purpose register to be added to contents. May not be null.
+ * @param rt general purpose register to be loaded. May not be null.
+ * @param rn general purpose register or stack pointer holding an address from which to load.
+ * @param acquire boolean value signifying if the load should use acquire semantics.
+ * @param release boolean value signifying if the store should use release semantics.
+ */
+ public void ldadd(int size, Register rs, Register rt, Register rn, boolean acquire, boolean release) {
+ assert size == 8 || size == 16 || size == 32 || size == 64;
+ int transferSize = NumUtil.log2Ceil(size / 8);
+ loadAndAddInstruction(LDADD, rs, rt, rn, transferSize, acquire, release);
+ }
+
+ private void loadAndAddInstruction(Instruction instr, Register rs, Register rt, Register rn, int log2TransferSize, boolean acquire, boolean release) {
+ assert log2TransferSize >= 0 && log2TransferSize < 4;
+ assert rt.getRegisterCategory().equals(CPU) && rs.getRegisterCategory().equals(CPU) && !rs.equals(rt);
+ int transferSizeEncoding = log2TransferSize << LoadStoreTransferSizeOffset;
+ emitInt(transferSizeEncoding | instr.encoding | rs2(rs) | rn(rn) | rt(rt) | (acquire ? 1 : 0) << LDADDAcquireOffset | (release ? 1 : 0) << LDADDReleaseOffset);
+ }
+
/* PC-relative Address Calculation (5.4.4) */
/**
* Address of page: sign extends 21-bit offset, shifts if left by 12 and adds it to the value of
- * the PC with its bottom 12-bits cleared, writing the result to dst.
- * No offset is emiited; the instruction will be patched later.
+ * the PC with its bottom 12-bits cleared, writing the result to dst. No offset is emitted; the
+ * instruction will be patched later.
*
* @param dst general purpose register. May not be null, zero-register or stackpointer.
*/
public void adrp(Register dst) {
- emitInt(ADRP.encoding | PcRelImmOp | rd(dst) );
+ emitInt(ADRP.encoding | PcRelImmOp | rd(dst));
}
/**
@@ -1367,14 +1414,17 @@
emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21));
}
+ /**
+ * Adds a 21-bit signed offset to the program counter and writes the result to dst.
+ *
+ * @param dst general purpose register. May not be null, zero-register or stackpointer.
+ * @param imm21 Signed 21-bit offset.
+ * @param pos the position in the code that the instruction is emitted.
+ */
public void adr(Register dst, int imm21, int pos) {
emitInt(ADR.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(imm21), pos);
}
- public void adrp(Register dst, int pageOffset) {
- emitInt(ADRP.encoding | PcRelImmOp | rd(dst) | getPcRelativeImmEncoding(pageOffset));
- }
-
private static int getPcRelativeImmEncoding(int imm21) {
assert NumUtil.isSignedNbit(21, imm21);
int imm = imm21 & NumUtil.getNbitNumberInt(21);
@@ -2432,6 +2482,39 @@
fpDataProcessing1Source(FRINTZ, dst, src, floatFromSize(size));
}
+ /**
+ * Rounds floating-point to integral. Rounds towards nearest with ties to even.
+ *
+ * @param size register size.
+ * @param dst floating point register. May not be null.
+ * @param src floating point register. May not be null.
+ */
+ public void frintn(int size, Register dst, Register src) {
+ fpDataProcessing1Source(FRINTN, dst, src, floatFromSize(size));
+ }
+
+ /**
+ * Rounds floating-point to integral. Rounds towards minus infinity.
+ *
+ * @param size register size.
+ * @param dst floating point register. May not be null.
+ * @param src floating point register. May not be null.
+ */
+ public void frintm(int size, Register dst, Register src) {
+ fpDataProcessing1Source(FRINTM, dst, src, floatFromSize(size));
+ }
+
+ /**
+ * Rounds floating-point to integral. Rounds towards plus infinity.
+ *
+ * @param size register size.
+ * @param dst floating point register. May not be null.
+ * @param src floating point register. May not be null.
+ */
+ public void frintp(int size, Register dst, Register src) {
+ fpDataProcessing1Source(FRINTP, dst, src, floatFromSize(size));
+ }
+
/* Floating-point Arithmetic (1 source) (5.7.6) */
/**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.aarch64/src/org/graalvm/compiler/asm/aarch64/AArch64MacroAssembler.java Thu May 31 10:38:05 2018 -0700
@@ -1,6 +1,5 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2018, Red Hat Inc. 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
@@ -38,7 +37,6 @@
import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.aarch64.AArch64.zr;
-import org.graalvm.compiler.asm.AbstractAddress;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.debug.GraalError;
@@ -307,9 +305,10 @@
case EXTENDED_REGISTER_OFFSET:
add(64, dst, address.getBase(), address.getOffset(), address.getExtendType(), address.isScaled() ? shiftAmt : 0);
break;
- case PC_LITERAL:
- super.adr(dst, address.getImmediateRaw());
+ case PC_LITERAL: {
+ addressOf(dst);
break;
+ }
case BASE_REGISTER_ONLY:
movx(dst, address.getBase());
break;
@@ -1561,7 +1560,7 @@
}
@Override
- public AbstractAddress getPlaceholder(int instructionStartPosition) {
+ public AArch64Address getPlaceholder(int instructionStartPosition) {
return AArch64Address.PLACEHOLDER;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java Thu May 31 10:38:05 2018 -0700
@@ -1853,9 +1853,36 @@
CMP.getMIOpcode(DWORD, isByte(imm32)).emit(this, DWORD, dst, imm32);
}
- // The 32-bit cmpxchg compares the value at adr with the contents of X86.rax,
- // and stores reg into adr if so; otherwise, the value at adr is loaded into X86.rax,.
- // The ZF is set if the compared values were equal, and cleared otherwise.
+ /**
+ * The 8-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg into
+ * adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the compared
+ * values were equal, and cleared otherwise.
+ */
+ public final void cmpxchgb(Register reg, AMD64Address adr) { // cmpxchg
+ prefix(adr, reg);
+ emitByte(0x0F);
+ emitByte(0xB0);
+ emitOperandHelper(reg, adr, 0);
+ }
+
+ /**
+ * The 16-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg
+ * into adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the
+ * compared values were equal, and cleared otherwise.
+ */
+ public final void cmpxchgw(Register reg, AMD64Address adr) { // cmpxchg
+ emitByte(0x66); // Switch to 16-bit mode.
+ prefix(adr, reg);
+ emitByte(0x0F);
+ emitByte(0xB1);
+ emitOperandHelper(reg, adr, 0);
+ }
+
+ /**
+ * The 32-bit cmpxchg compares the value at adr with the contents of X86.rax, and stores reg
+ * into adr if so; otherwise, the value at adr is loaded into X86.rax,. The ZF is set if the
+ * compared values were equal, and cleared otherwise.
+ */
public final void cmpxchgl(Register reg, AMD64Address adr) { // cmpxchg
prefix(adr, reg);
emitByte(0x0F);
@@ -3677,6 +3704,21 @@
emitByte(imm8);
}
+ public final void xaddb(AMD64Address dst, Register src) {
+ prefix(dst, src);
+ emitByte(0x0F);
+ emitByte(0xC0);
+ emitOperandHelper(src, dst, 0);
+ }
+
+ public final void xaddw(AMD64Address dst, Register src) {
+ emitByte(0x66); // Switch to 16-bit mode.
+ prefix(dst, src);
+ emitByte(0x0F);
+ emitByte(0xC1);
+ emitOperandHelper(src, dst, 0);
+ }
+
public final void xaddl(AMD64Address dst, Register src) {
prefix(dst, src);
emitByte(0x0F);
@@ -3691,6 +3733,19 @@
emitOperandHelper(src, dst, 0);
}
+ public final void xchgb(Register dst, AMD64Address src) {
+ prefix(src, dst);
+ emitByte(0x86);
+ emitOperandHelper(dst, src, 0);
+ }
+
+ public final void xchgw(Register dst, AMD64Address src) {
+ emitByte(0x66);
+ prefix(src, dst);
+ emitByte(0x87);
+ emitOperandHelper(dst, src, 0);
+ }
+
public final void xchgl(Register dst, AMD64Address src) {
prefix(src, dst);
emitByte(0x87);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.bytecode/src/org/graalvm/compiler/bytecode/Bytecodes.java Thu May 31 10:38:05 2018 -0700
@@ -837,4 +837,27 @@
assert !isConditionalBranch(opcode) || isBranch(opcode) : "a conditional branch must also be a branch";
}
+
+ public static boolean isIfBytecode(int bytecode) {
+ switch (bytecode) {
+ case IFEQ:
+ case IFNE:
+ case IFLT:
+ case IFGE:
+ case IFGT:
+ case IFLE:
+ case IF_ICMPEQ:
+ case IF_ICMPNE:
+ case IF_ICMPLT:
+ case IF_ICMPGE:
+ case IF_ICMPGT:
+ case IF_ICMPLE:
+ case IF_ACMPEQ:
+ case IF_ACMPNE:
+ case IFNULL:
+ case IFNONNULL:
+ return true;
+ }
+ return false;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64ArithmeticLIRGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -32,9 +32,9 @@
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CLZ;
import static org.graalvm.compiler.lir.aarch64.AArch64BitManipulationOp.BitManipulationOpCode.CTZ;
-import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.NumUtil;
import org.graalvm.compiler.core.common.calc.FloatConvert;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.lir.ConstantValue;
@@ -491,4 +491,23 @@
throw GraalError.unimplemented();
}
+ @Override
+ public Value emitRound(Value value, RoundingMode mode) {
+ AArch64ArithmeticOp op;
+ switch (mode) {
+ case NEAREST:
+ op = AArch64ArithmeticOp.FRINTN;
+ break;
+ case UP:
+ op = AArch64ArithmeticOp.FRINTP;
+ break;
+ case DOWN:
+ op = AArch64ArithmeticOp.FRINTM;
+ break;
+ default:
+ throw GraalError.shouldNotReachHere();
+ }
+
+ return emitUnary(op, value);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.aarch64/src/org/graalvm/compiler/core/aarch64/AArch64LIRGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -52,6 +52,7 @@
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.StrategySwitchOp;
import org.graalvm.compiler.lir.aarch64.AArch64ControlFlow.TableSwitchOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move;
+import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.AtomicReadAndAddOp;
import org.graalvm.compiler.lir.aarch64.AArch64AtomicMove.CompareAndSwapOp;
import org.graalvm.compiler.lir.aarch64.AArch64Move.MembarOp;
import org.graalvm.compiler.lir.aarch64.AArch64PauseOp;
@@ -127,7 +128,7 @@
}
@Override
- public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+ public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
Variable prevValue = newVariable(expectedValue.getValueKind());
Variable scratch = newVariable(LIRKind.value(AArch64Kind.DWORD));
append(new CompareAndSwapOp(prevValue, loadReg(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
@@ -138,7 +139,7 @@
}
@Override
- public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
+ public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
Variable result = newVariable(newValue.getValueKind());
Variable scratch = newVariable(LIRKind.value(AArch64Kind.WORD));
append(new CompareAndSwapOp(result, loadNonCompareConst(expectedValue), loadReg(newValue), asAllocatable(address), scratch));
@@ -146,6 +147,16 @@
}
@Override
+ public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
+ Variable result = newVariable(kind);
+ Variable scratch1 = newVariable(kind);
+ Variable scratch2 = newVariable(kind);
+
+ append(new AtomicReadAndAddOp((AArch64Kind) kind.getPlatformKind(), asAllocatable(result), asAllocatable(address), asAllocatable(delta), asAllocatable(scratch1), asAllocatable(scratch2)));
+ return result;
+ }
+
+ @Override
public void emitMembar(int barriers) {
int necessaryBarriers = target().arch.requiredBarriers(barriers);
if (target().isMP && necessaryBarriers != 0) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64LIRGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -23,13 +23,16 @@
package org.graalvm.compiler.core.amd64;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isAllocatableValue;
+import static jdk.vm.ci.code.ValueUtil.isRegister;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.AMD64BinaryArithmetic.CMP;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.DWORD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PD;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.PS;
import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.asConstantValue;
import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
@@ -190,36 +193,68 @@
}
}
- @Override
- public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+ private AllocatableValue asAllocatable(Value value, ValueKind<?> kind) {
+ if (value.getValueKind().equals(kind)) {
+ return asAllocatable(value);
+ } else if (isRegister(value)) {
+ return asRegister(value).asValue(kind);
+ } else if (isConstantValue(value)) {
+ return emitLoadConstant(kind, asConstant(value));
+ } else {
+ Variable variable = newVariable(kind);
+ emitMove(variable, value);
+ return variable;
+ }
+ }
+
+ private Value emitCompareAndSwap(boolean isLogic, LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
ValueKind<?> kind = newValue.getValueKind();
assert kind.equals(expectedValue.getValueKind());
- AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
AMD64AddressValue addressValue = asAddressValue(address);
- RegisterValue raxRes = AMD64.rax.asValue(kind);
- emitMove(raxRes, expectedValue);
- append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
+ LIRKind integralAccessKind = accessKind;
+ Value reinterpretedExpectedValue = expectedValue;
+ Value reinterpretedNewValue = newValue;
+ boolean isXmm = ((AMD64Kind) accessKind.getPlatformKind()).isXMM();
+ if (isXmm) {
+ if (accessKind.getPlatformKind().equals(AMD64Kind.SINGLE)) {
+ integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Int);
+ } else {
+ integralAccessKind = LIRKind.fromJavaKind(target().arch, JavaKind.Long);
+ }
+ reinterpretedExpectedValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, expectedValue);
+ reinterpretedNewValue = arithmeticLIRGen.emitReinterpret(integralAccessKind, newValue);
+ }
+ AMD64Kind memKind = (AMD64Kind) integralAccessKind.getPlatformKind();
+ RegisterValue aRes = AMD64.rax.asValue(integralAccessKind);
+ AllocatableValue allocatableNewValue = asAllocatable(reinterpretedNewValue, integralAccessKind);
+ emitMove(aRes, reinterpretedExpectedValue);
+ append(new CompareAndSwapOp(memKind, aRes, addressValue, aRes, allocatableNewValue));
- assert trueValue.getValueKind().equals(falseValue.getValueKind());
- Variable result = newVariable(trueValue.getValueKind());
- append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
- return result;
+ if (isLogic) {
+ assert trueValue.getValueKind().equals(falseValue.getValueKind());
+ Variable result = newVariable(trueValue.getValueKind());
+ append(new CondMoveOp(result, Condition.EQ, asAllocatable(trueValue), falseValue));
+ return result;
+ } else {
+ if (isXmm) {
+ return arithmeticLIRGen.emitReinterpret(accessKind, aRes);
+ } else {
+ Variable result = newVariable(kind);
+ emitMove(result, aRes);
+ return result;
+ }
+ }
}
@Override
- public Value emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
- ValueKind<?> kind = newValue.getValueKind();
- assert kind.equals(expectedValue.getValueKind());
- AMD64Kind memKind = (AMD64Kind) kind.getPlatformKind();
+ public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+ return (Variable) emitCompareAndSwap(true, accessKind, address, expectedValue, newValue, trueValue, falseValue);
+ }
- AMD64AddressValue addressValue = asAddressValue(address);
- RegisterValue raxRes = AMD64.rax.asValue(kind);
- emitMove(raxRes, expectedValue);
- append(new CompareAndSwapOp(memKind, raxRes, addressValue, raxRes, asAllocatable(newValue)));
- Variable result = newVariable(kind);
- emitMove(result, raxRes);
- return result;
+ @Override
+ public Value emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
+ return emitCompareAndSwap(false, accessKind, address, expectedValue, newValue, null, null);
}
public void emitCompareAndSwapBranch(ValueKind<?> kind, AMD64AddressValue address, Value expectedValue, Value newValue, Condition condition, LabelRef trueLabel, LabelRef falseLabel,
@@ -235,8 +270,7 @@
}
@Override
- public Value emitAtomicReadAndAdd(Value address, Value delta) {
- ValueKind<?> kind = delta.getValueKind();
+ public Value emitAtomicReadAndAdd(Value address, ValueKind<?> kind, Value delta) {
Variable result = newVariable(kind);
AMD64AddressValue addressValue = asAddressValue(address);
append(new AMD64Move.AtomicReadAndAddOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(delta)));
@@ -244,8 +278,7 @@
}
@Override
- public Value emitAtomicReadAndWrite(Value address, Value newValue) {
- ValueKind<?> kind = newValue.getValueKind();
+ public Value emitAtomicReadAndWrite(Value address, ValueKind<?> kind, Value newValue) {
Variable result = newVariable(kind);
AMD64AddressValue addressValue = asAddressValue(address);
append(new AMD64Move.AtomicReadAndWriteOp((AMD64Kind) kind.getPlatformKind(), result, addressValue, asAllocatable(newValue)));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalBailoutException.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+import jdk.vm.ci.code.BailoutException;
+import org.graalvm.compiler.debug.CausableByCompilerAssert;
+
+@SuppressWarnings("serial")
+public class GraalBailoutException extends BailoutException implements CausableByCompilerAssert {
+
+ public GraalBailoutException(String format, Object... args) {
+ super(format, args);
+ }
+
+ public GraalBailoutException(Throwable cause, String format, Object... args) {
+ super(cause, format, args);
+ }
+
+ public GraalBailoutException(boolean permanent, String format, Object... args) {
+ super(permanent, format, args);
+ }
+
+ @Override
+ public boolean isCausedByCompilerAssert() {
+ return false;
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/PermanentBailoutException.java Thu May 31 10:38:05 2018 -0700
@@ -22,9 +22,7 @@
*/
package org.graalvm.compiler.core.common;
-import jdk.vm.ci.code.BailoutException;
-
-public class PermanentBailoutException extends BailoutException {
+public class PermanentBailoutException extends GraalBailoutException {
private static final long serialVersionUID = -2683649650135362549L;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/RetryableBailoutException.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/RetryableBailoutException.java Thu May 31 10:38:05 2018 -0700
@@ -22,9 +22,7 @@
*/
package org.graalvm.compiler.core.common;
-import jdk.vm.ci.code.BailoutException;
-
-public class RetryableBailoutException extends BailoutException {
+public class RetryableBailoutException extends GraalBailoutException {
private static final long serialVersionUID = -7145365025679144525L;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/IntegerStamp.java Thu May 31 10:38:05 2018 -0700
@@ -1545,6 +1545,9 @@
@Override
public Stamp invertStamp(int inputBits, int resultBits, Stamp outStamp) {
+ if (outStamp.isEmpty()) {
+ return StampFactory.forInteger(inputBits).empty();
+ }
IntegerStamp stamp = (IntegerStamp) outStamp;
long mask = CodeUtil.mask(inputBits);
return StampFactory.forIntegerWithMask(inputBits, stamp.lowerBound(), stamp.upperBound(), stamp.downMask() & mask, stamp.upMask() & mask);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -27,19 +27,20 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
@@ -48,9 +49,7 @@
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.AbstractAnnotationValueVisitor7;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
@@ -58,24 +57,10 @@
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
-import jdk.internal.vm.compiler.collections.EconomicMap;
-import jdk.internal.vm.compiler.collections.EconomicSet;
-import jdk.internal.vm.compiler.collections.Equivalence;
-import org.graalvm.compiler.core.gen.NodeMatchRules;
-import org.graalvm.compiler.core.match.ComplexMatchResult;
-import org.graalvm.compiler.core.match.MatchRule;
-import org.graalvm.compiler.core.match.MatchRules;
-import org.graalvm.compiler.core.match.MatchStatement;
-import org.graalvm.compiler.core.match.MatchStatementSet;
-import org.graalvm.compiler.core.match.MatchableNode;
-import org.graalvm.compiler.core.match.MatchableNodes;
-import org.graalvm.compiler.debug.GraalError;
-import org.graalvm.compiler.graph.Position;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.serviceprovider.ServiceProvider;
+import org.graalvm.compiler.processor.AbstractProcessor;
/**
- * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
+ * Processes classes annotated with {@code MatchRule}. A {@code MatchStatementSet} service is
* generated for each top level class containing at least one such field. These service objects can
* be retrieved as follows:
*
@@ -90,6 +75,13 @@
"org.graalvm.compiler.core.match.MatchableNodes"})
public class MatchProcessor extends AbstractProcessor {
+ private static final String VALUE_NODE_CLASS_NAME = "org.graalvm.compiler.nodes.ValueNode";
+ private static final String COMPLEX_MATCH_RESULT_CLASS_NAME = "org.graalvm.compiler.core.match.ComplexMatchResult";
+ private static final String MATCHABLE_NODES_CLASS_NAME = "org.graalvm.compiler.core.match.MatchableNodes";
+ private static final String MATCHABLE_NODE_CLASS_NAME = "org.graalvm.compiler.core.match.MatchableNode";
+ private static final String MATCH_RULE_CLASS_NAME = "org.graalvm.compiler.core.match.MatchRule";
+ private static final String MATCH_RULES_CLASS_NAME = "org.graalvm.compiler.core.match.MatchRules";
+
public MatchProcessor() {
}
@@ -98,8 +90,8 @@
return SourceVersion.latest();
}
- private final Set<Element> processedMatchRule = new HashSet<>();
- private final Set<Element> processedMatchableNode = new HashSet<>();
+ private final Set<Element> processedMatchRules = new HashSet<>();
+ private final Set<Element> processedMatchableNodes = new HashSet<>();
private static class RuleParseError extends RuntimeException {
private static final long serialVersionUID = 6456128283609257490L;
@@ -170,14 +162,14 @@
if (peek("(").equals("(")) {
next();
MatchDescriptor descriptor = parseType(true);
- for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+ for (int n = 0; n < descriptor.nodeType.inputs.size(); n++) {
if (peek("(").equals("(")) {
descriptor.inputs[n] = parseExpression();
} else {
descriptor.inputs[n] = parseType(false);
}
}
- for (int n = 0; n < descriptor.nodeType.inputs.length; n++) {
+ for (int n = 0; n < descriptor.nodeType.inputs.size(); n++) {
if (descriptor.inputs[n] == null) {
throw new RuleParseError("not enough inputs for " + descriptor.name);
}
@@ -233,7 +225,7 @@
/**
* Recursively accumulate any required Position declarations.
*/
- void generatePositionDeclarations(EconomicSet<String> declarations) {
+ void generatePositionDeclarations(Set<String> declarations) {
matchDescriptor.generatePositionDeclarations(declarations);
}
@@ -251,9 +243,8 @@
}
/**
- * Set to true to enable logging to a local file during annotation processing. There's no normal
- * channel for any debug messages and debugging annotation processors requires some special
- * setup.
+ * Set to true to enable logging during annotation processing. There's no normal channel for any
+ * debug messages and debugging annotation processors requires some special setup.
*/
private static final boolean DEBUG = false;
@@ -265,14 +256,21 @@
private PrintWriter getLog() {
if (log == null) {
- try {
- // Create the log file within the generated source directory so it's easy to find.
- // /tmp isn't platform independent and java.io.tmpdir can map anywhere, particularly
- // on the mac.
- FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
- log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
- } catch (IOException e) {
- // Do nothing
+ if (processingEnv.getClass().getName().contains(".javac.")) {
+ // For javac, just log to System.err
+ log = new PrintWriter(System.err);
+ } else {
+ try {
+ // Create the log file within the generated source directory so it's easy to
+ // find.
+ // /tmp isn't platform independent and java.io.tmpdir can map anywhere,
+ // particularly
+ // on the mac.
+ FileObject file = processingEnv.getFiler().createResource(StandardLocation.SOURCE_OUTPUT, "", getClass().getSimpleName() + "log");
+ log = new PrintWriter(new FileWriter(file.toUri().getPath(), true));
+ } catch (IOException e) {
+ // Do nothing
+ }
}
}
return log;
@@ -309,7 +307,7 @@
logMessage("throw for %s:\n", element);
}
logException(t);
- errorMessage(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
+ printError(element, "Exception throw during processing: %s %s", t, Arrays.toString(Arrays.copyOf(t.getStackTrace(), 4)));
}
static class TypeDescriptor {
@@ -321,19 +319,19 @@
final String shortName;
/**
- * The simple name of the {@link ValueNode} class represented by this type.
+ * The simple name of the {@code ValueNode} class represented by this type.
*/
final String nodeClass;
/**
- * The package of {@link ValueNode} class represented by this type.
+ * The package of {@code ValueNode} class represented by this type.
*/
final String nodePackage;
/**
* The matchable inputs of the node.
*/
- final String[] inputs;
+ final List<String> inputs;
/**
* Should swapped variants of this match be generated. The user of the match is expected to
@@ -350,7 +348,7 @@
final Set<Element> originatingElements = new HashSet<>();
- TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable) {
+ TypeDescriptor(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable) {
this.mirror = mirror;
this.shortName = shortName;
this.nodeClass = nodeClass;
@@ -358,26 +356,18 @@
this.inputs = inputs;
this.commutative = commutative;
this.shareable = shareable;
- assert !commutative || inputs.length == 2;
+ assert !commutative || inputs.size() == 2;
}
}
/**
* The types which are know for purpose of parsing MatchRule expressions.
*/
- EconomicMap<String, TypeDescriptor> knownTypes = EconomicMap.create(Equivalence.DEFAULT);
+ Map<String, TypeDescriptor> knownTypes = new HashMap<>();
private TypeDescriptor valueType;
- private TypeMirror matchRulesTypeMirror;
-
- private TypeMirror matchRuleTypeMirror;
-
- private TypeMirror matchableNodeTypeMirror;
-
- private TypeMirror matchableNodesTypeMirror;
-
- private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, String[] inputs, boolean commutative, boolean shareable, Element element) {
+ private void declareType(TypeMirror mirror, String shortName, String nodeClass, String nodePackage, List<String> inputs, boolean commutative, boolean shareable, Element element) {
TypeDescriptor descriptor = new TypeDescriptor(mirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable);
descriptor.originatingElements.add(element);
knownTypes.put(shortName, descriptor);
@@ -388,7 +378,7 @@
if (p != null) {
return p.getQualifiedName().toString();
}
- throw new GraalError("can't find package for %s", type);
+ throw new InternalError("Can't find package for " + type);
}
class MatchDescriptor {
@@ -400,13 +390,13 @@
this.nodeType = nodeType;
this.name = name;
if (forExpression) {
- this.inputs = new MatchDescriptor[nodeType.inputs.length];
+ this.inputs = new MatchDescriptor[nodeType.inputs.size()];
} else {
this.inputs = new MatchDescriptor[0];
}
}
- public void generatePositionDeclarations(EconomicSet<String> declarations) {
+ public void generatePositionDeclarations(Set<String> declarations) {
if (inputs.length == 0) {
return;
}
@@ -469,10 +459,10 @@
private String formatSuffix() {
if (nodeType != null) {
- if (inputs.length != nodeType.inputs.length) {
+ if (inputs.length != nodeType.inputs.size()) {
return ", true)";
} else {
- if (nodeType.inputs.length > 0) {
+ if (nodeType.inputs.size() > 0) {
return ", " + nodeType.nodeClass + "_positions, " + !nodeType.shareable + ")";
}
if (nodeType.shareable) {
@@ -502,7 +492,7 @@
String pkg = ((PackageElement) info.topDeclaringType.getEnclosingElement()).getQualifiedName().toString();
Name topDeclaringClass = info.topDeclaringType.getSimpleName();
- String matchStatementClassName = topDeclaringClass + "_" + MatchStatementSet.class.getSimpleName();
+ String matchStatementClassName = topDeclaringClass + "_MatchStatementSet";
Element[] originatingElements = info.originatingElements.toArray(new Element[info.originatingElements.size()]);
Types typeUtils = typeUtils();
@@ -516,22 +506,20 @@
out.println("package " + pkg + ";");
out.println("");
out.println("import java.util.*;");
- out.println("import " + MatchStatementSet.class.getPackage().getName() + ".*;");
- out.println("import " + NodeMatchRules.class.getName() + ";");
- out.println("import " + Position.class.getName() + ";");
- out.println("import " + ServiceProvider.class.getName() + ";");
+ out.println("import org.graalvm.compiler.core.match.*;");
+ out.println("import org.graalvm.compiler.core.gen.NodeMatchRules;");
+ out.println("import org.graalvm.compiler.graph.Position;");
for (String p : info.requiredPackages) {
out.println("import " + p + ".*;");
}
out.println("");
- out.println("@" + ServiceProvider.class.getSimpleName() + "(" + MatchStatementSet.class.getSimpleName() + ".class)");
- out.println("public class " + matchStatementClassName + " implements " + MatchStatementSet.class.getSimpleName() + " {");
+ out.println("public class " + matchStatementClassName + " implements MatchStatementSet {");
out.println();
// Generate declarations for the wrapper class to invoke the code generation methods.
- for (MethodInvokerItem invoker : info.invokers.getValues()) {
+ for (MethodInvokerItem invoker : info.invokers.values()) {
StringBuilder args = new StringBuilder();
StringBuilder types = new StringBuilder();
int count = invoker.fields.size();
@@ -562,7 +550,7 @@
}
- String desc = MatchStatement.class.getSimpleName();
+ String desc = "MatchStatement";
out.println(" @Override");
out.println(" public Class<? extends NodeMatchRules> forClass() {");
@@ -595,6 +583,7 @@
out.println("}");
}
+ this.createProviderFile(pkg + "." + matchStatementClassName, "org.graalvm.compiler.core.match.MatchStatementSet", originatingElements);
}
protected PrintWriter createSourceFile(String pkg, String relativeName, Filer filer, Element... originatingElements) {
@@ -662,17 +651,17 @@
final TypeElement topDeclaringType;
final List<MatchRuleItem> matchRules = new ArrayList<>();
- private final EconomicSet<Element> originatingElements = EconomicSet.create(Equivalence.DEFAULT);
- public EconomicSet<String> positionDeclarations = EconomicSet.create(Equivalence.DEFAULT);
+ private final Set<Element> originatingElements = new HashSet<>();
+ public Set<String> positionDeclarations = new HashSet<>();
/**
* The mapping between elements with MatchRules and the wrapper class used invoke the code
* generation after the match.
*/
- EconomicMap<String, MethodInvokerItem> invokers = EconomicMap.create(Equivalence.DEFAULT);
+ Map<String, MethodInvokerItem> invokers = new HashMap<>();
/**
- * The set of packages which must be imported to refer the classes mention in matchRules.
+ * The set of packages which must be imported to refer the classes mentioned in matchRules.
*/
Set<String> requiredPackages = new HashSet<>();
@@ -690,14 +679,15 @@
return topDeclaringType(enclosing);
}
- private AnnotationMirror findAnnotationMirror(Element element, TypeMirror typeMirror) {
- for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
- if (typeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
- return mirror;
- }
- }
- return null;
- }
+ /**
+ * The element currently being processed.
+ */
+ private Element currentElement;
+
+ /**
+ * The current processing round.
+ */
+ private RoundEnvironment currentRound;
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
@@ -706,45 +696,58 @@
}
logMessage("Starting round %s\n", roundEnv);
- matchRulesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRules.class.getCanonicalName()).asType();
- matchRuleTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchRule.class.getCanonicalName()).asType();
+
+ TypeElement matchRulesTypeElement = getTypeElement(MATCH_RULES_CLASS_NAME);
+ TypeElement matchRuleTypeElement = getTypeElement(MATCH_RULE_CLASS_NAME);
- matchableNodeTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNode.class.getCanonicalName()).asType();
- matchableNodesTypeMirror = processingEnv.getElementUtils().getTypeElement(MatchableNodes.class.getCanonicalName()).asType();
+ TypeMirror matchRulesTypeMirror = matchRulesTypeElement.asType();
+ TypeMirror matchRuleTypeMirror = matchRuleTypeElement.asType();
- Element currentElement = null;
+ TypeElement matchableNodeTypeElement = getTypeElement(MATCHABLE_NODE_CLASS_NAME);
+ TypeElement matchableNodesTypeElement = getTypeElement(MATCHABLE_NODES_CLASS_NAME);
+
+ currentRound = roundEnv;
try {
- for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNode.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(matchableNodeTypeElement)) {
+ currentElement = element;
logMessage("%s\n", element);
- processMatchableNode(element);
+ processMatchableNodes(element);
}
- for (Element element : roundEnv.getElementsAnnotatedWith(MatchableNodes.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(matchableNodesTypeElement)) {
+ currentElement = element;
logMessage("%s\n", element);
- processMatchableNode(element);
+ processMatchableNodes(element);
}
// Define a TypeDescriptor for the generic node but don't enter it into the nodeTypes
// table since it shouldn't be mentioned in match rules.
- TypeMirror valueTypeMirror = processingEnv.getElementUtils().getTypeElement(ValueNode.class.getName()).asType();
- valueType = new TypeDescriptor(valueTypeMirror, "Value", ValueNode.class.getSimpleName(), ValueNode.class.getPackage().getName(), new String[0], false, false);
+ TypeMirror valueTypeMirror = getTypeElement(VALUE_NODE_CLASS_NAME).asType();
+ valueType = new TypeDescriptor(valueTypeMirror, "Value", "ValueNode", "org.graalvm.compiler.nodes", Collections.emptyList(), false, false);
- EconomicMap<TypeElement, MatchRuleDescriptor> map = EconomicMap.create(Equivalence.DEFAULT);
+ Map<TypeElement, MatchRuleDescriptor> map = new HashMap<>();
- for (Element element : roundEnv.getElementsAnnotatedWith(MatchRule.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(matchRuleTypeElement)) {
currentElement = element;
- processMatchRule(map, element, findAnnotationMirror(element, matchRuleTypeMirror));
+ AnnotationMirror matchRule = getAnnotation(element, matchRuleTypeMirror);
+ List<AnnotationMirror> matchRuleAnnotations = Collections.singletonList(matchRule);
+ processMatchRules(map, element, matchRuleAnnotations);
}
- for (Element element : roundEnv.getElementsAnnotatedWith(MatchRules.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(matchRulesTypeElement)) {
currentElement = element;
- processMatchRule(map, element, findAnnotationMirror(element, matchRulesTypeMirror));
+ AnnotationMirror matchRules = getAnnotation(element, matchRulesTypeMirror);
+ List<AnnotationMirror> matchRuleAnnotations = getAnnotationValueList(matchRules, "value", AnnotationMirror.class);
+ processMatchRules(map, element, matchRuleAnnotations);
}
currentElement = null;
- for (MatchRuleDescriptor info : map.getValues()) {
+ for (MatchRuleDescriptor info : map.values()) {
createFiles(info);
}
} catch (Throwable t) {
reportExceptionThrow(currentElement, t);
+ } finally {
+ currentElement = null;
+ currentRound = null;
}
return true;
@@ -753,27 +756,27 @@
/**
* Build up the type table to be used during parsing of the MatchRule.
*/
- private void processMatchableNode(Element element) {
- if (!processedMatchableNode.contains(element)) {
+ private void processMatchableNodes(Element element) {
+ if (!processedMatchableNodes.contains(element)) {
try {
- processedMatchableNode.add(element);
+ processedMatchableNodes.add(element);
- AnnotationMirror mirror = findAnnotationMirror(element, matchableNodesTypeMirror);
- if (mirror == null) {
- mirror = findAnnotationMirror(element, matchableNodeTypeMirror);
+ List<AnnotationMirror> matchableNodeAnnotations;
+ AnnotationMirror mirror = getAnnotation(element, getType(MATCHABLE_NODES_CLASS_NAME));
+ if (mirror != null) {
+ matchableNodeAnnotations = getAnnotationValueList(mirror, "value", AnnotationMirror.class);
+ } else {
+ mirror = getAnnotation(element, getType(MATCHABLE_NODES_CLASS_NAME));
+ if (mirror != null) {
+ matchableNodeAnnotations = Collections.singletonList(mirror);
+ } else {
+ return;
+ }
}
- if (mirror == null) {
- return;
- }
+
TypeElement topDeclaringType = topDeclaringType(element);
- List<AnnotationMirror> mirrors = null;
- if (typeUtils().isSameType(mirror.getAnnotationType(), matchableNodesTypeMirror)) {
- // Unpack the mirrors for a repeatable annotation
- mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
- }
- int i = 0;
- for (MatchableNode matchableNode : element.getAnnotationsByType(MatchableNode.class)) {
- processMatchableNode(element, topDeclaringType, matchableNode, mirrors != null ? mirrors.get(i++) : mirror);
+ for (AnnotationMirror matchableNode : matchableNodeAnnotations) {
+ processMatchableNode(element, topDeclaringType, matchableNode);
}
} catch (Throwable t) {
reportExceptionThrow(element, t);
@@ -781,27 +784,22 @@
}
}
- private void processMatchableNode(Element element, TypeElement topDeclaringType, MatchableNode matchable, AnnotationMirror mirror) throws GraalError {
+ private void processMatchableNode(Element element, TypeElement topDeclaringType, AnnotationMirror matchable) {
logMessage("processMatchableNode %s %s %s\n", topDeclaringType, element, matchable);
String nodeClass;
String nodePackage;
- TypeMirror nodeClassMirror = null;
- try {
- matchable.nodeClass();
- } catch (MirroredTypeException e) {
- nodeClassMirror = e.getTypeMirror();
+ TypeMirror nodeClassMirror = getAnnotationValue(matchable, "nodeClass", TypeMirror.class);
+ if (nodeClassMirror == null) {
+ throw new InternalError("Can't get mirror for node class " + element);
}
- if (nodeClassMirror == null) {
- throw new GraalError("Can't get mirror for node class %s", element);
- }
- if (nodeClassMirror.toString().equals(MatchableNode.class.getName())) {
+ if (nodeClassMirror.toString().equals(MATCHABLE_NODE_CLASS_NAME)) {
nodeClass = topDeclaringType.getQualifiedName().toString();
} else {
nodeClass = nodeClassMirror.toString();
}
TypeElement typeElement = processingEnv.getElementUtils().getTypeElement(nodeClass);
if (typeElement == null) {
- errorMessage(element, mirror, "Class \"%s\" cannot be resolved to a type", nodeClass);
+ printError(element, matchable, "Class \"%s\" cannot be resolved to a type", nodeClass);
return;
}
nodePackage = findPackage(typeElement);
@@ -812,7 +810,8 @@
Types typeUtils = processingEnv.getTypeUtils();
TypeElement nodeClassElement = (TypeElement) typeUtils.asElement(nodeClassMirror);
- for (String input : matchable.inputs()) {
+ List<String> inputs = getAnnotationValueList(matchable, "inputs", String.class);
+ for (String input : inputs) {
boolean ok = false;
TypeElement current = nodeClassElement;
while (!ok && current != null) {
@@ -826,17 +825,19 @@
current = (TypeElement) typeUtils.asElement(theSuper);
}
if (!ok) {
- errorMessage(element, mirror, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
+ printError(element, matchable, "Input named \"%s\" doesn't exist in %s", input, nodeClassElement.getSimpleName());
}
}
- declareType(nodeClassMirror, shortName, nodeClass, nodePackage, matchable.inputs(), matchable.commutative(), matchable.shareable(), element);
+ boolean commutative = getAnnotationValue(matchable, "commutative", Boolean.class);
+ boolean shareable = getAnnotationValue(matchable, "shareable", Boolean.class);
+ declareType(nodeClassMirror, shortName, nodeClass, nodePackage, inputs, commutative, shareable, element);
}
- private void processMatchRule(EconomicMap<TypeElement, MatchRuleDescriptor> map, Element element, AnnotationMirror mirror) {
- if (!processedMatchRule.contains(element)) {
+ private void processMatchRules(Map<TypeElement, MatchRuleDescriptor> map, Element element, List<AnnotationMirror> matchRules) {
+ if (!processedMatchRules.contains(element)) {
try {
- processedMatchRule.add(element);
+ processedMatchRules.add(element);
// The annotation element type should ensure this is true.
assert element instanceof ExecutableElement;
@@ -849,14 +850,8 @@
info = new MatchRuleDescriptor(topDeclaringType);
map.put(topDeclaringType, info);
}
- List<AnnotationMirror> mirrors = null;
- if (typeUtils().isSameType(mirror.getAnnotationType(), matchRulesTypeMirror)) {
- // Unpack the mirrors for a repeatable annotation
- mirrors = getAnnotationValueList(AnnotationMirror.class, mirror, "value");
- }
- int i = 0;
- for (MatchRule matchRule : element.getAnnotationsByType(MatchRule.class)) {
- processMethodMatchRule((ExecutableElement) element, info, matchRule, mirrors != null ? mirrors.get(i++) : mirror);
+ for (AnnotationMirror matchRule : matchRules) {
+ processMatchRule((ExecutableElement) element, info, matchRule);
}
} catch (Throwable t) {
reportExceptionThrow(element, t);
@@ -871,16 +866,16 @@
* @param element
*/
private void findMatchableNodes(Element element) {
- processMatchableNode(element);
+ processMatchableNodes(element);
Element enclosing = element.getEnclosingElement();
while (enclosing != null) {
if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
TypeElement current = (TypeElement) enclosing;
while (current != null) {
- processMatchableNode(current);
+ processMatchableNodes(current);
for (TypeMirror intf : current.getInterfaces()) {
Element interfaceElement = typeUtils().asElement(intf);
- processMatchableNode(interfaceElement);
+ processMatchableNodes(interfaceElement);
// Recurse
findMatchableNodes(interfaceElement);
}
@@ -896,34 +891,34 @@
return processingEnv.getTypeUtils();
}
- private void processMethodMatchRule(ExecutableElement method, MatchRuleDescriptor info, MatchRule matchRule, AnnotationMirror mirror) {
- logMessage("processMethodMatchRule %s %s\n", method, mirror);
+ private void processMatchRule(ExecutableElement method, MatchRuleDescriptor info, AnnotationMirror matchRule) {
+ logMessage("processMatchRule %s\n", method);
Types typeUtils = typeUtils();
if (!method.getModifiers().contains(Modifier.PUBLIC)) {
- errorMessage(method, "MatchRule method %s must be public", method.getSimpleName());
+ printError(method, "MatchRule method %s must be public", method.getSimpleName());
return;
}
if (method.getModifiers().contains(Modifier.STATIC)) {
- errorMessage(method, "MatchRule method %s must be non-static", method.getSimpleName());
+ printError(method, "MatchRule method %s must be non-static", method.getSimpleName());
return;
}
try {
TypeMirror returnType = method.getReturnType();
- if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(ComplexMatchResult.class.getName()).asType())) {
- errorMessage(method, "MatchRule method return type must be %s", ComplexMatchResult.class.getName());
+ if (!typeUtils.isSameType(returnType, processingEnv.getElementUtils().getTypeElement(COMPLEX_MATCH_RESULT_CLASS_NAME).asType())) {
+ printError(method, "MatchRule method return type must be %s", COMPLEX_MATCH_RESULT_CLASS_NAME);
return;
}
- String rule = matchRule.value();
+ String rule = getAnnotationValue(matchRule, "value", String.class);
RuleParser parser = new RuleParser(rule);
ArrayList<TypeDescriptor> expectedTypes = parser.capturedTypes();
ArrayList<String> expectedNames = parser.capturedNames();
List<? extends VariableElement> actualParameters = method.getParameters();
if (expectedTypes.size() + 1 < actualParameters.size()) {
- errorMessage(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
+ printError(method, "Too many arguments for match method %s != %s", expectedTypes.size() + 1, actualParameters.size());
return;
}
@@ -934,12 +929,12 @@
String name = parameter.getSimpleName().toString();
int nameIndex = expectedNames.indexOf(name);
if (nameIndex == -1) {
- errorMessage(method, "Argument \"%s\" isn't captured in the match rule", name);
+ printError(method, "Argument \"%s\" isn't captured in the match rule", name);
return;
}
TypeMirror type = parameter.asType();
if (!typeUtils.isAssignable(expectedTypes.get(nameIndex).mirror, type)) {
- errorMessage(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
+ printError(method, "Captured value \"%s\" of type %s is not assignable to argument of type %s", name, expectedTypes.get(nameIndex).mirror, type);
return;
}
}
@@ -952,7 +947,7 @@
} else if (invoker.method != method) {
// This could be supported but it's easier if they are unique since the names
// are used in log output and snippet counters.
- errorMessage(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(),
+ printError(method, "Use unique method names for match methods: %s.%s != %s.%s", method.getReceiverType(), method.getSimpleName(), invoker.method.getReceiverType(),
invoker.method.getSimpleName());
return;
}
@@ -960,12 +955,12 @@
Element enclosing = method.getEnclosingElement();
String declaringClass = "";
String separator = "";
- EconomicSet<Element> originatingElementsList = info.originatingElements;
+ Set<Element> originatingElementsList = info.originatingElements;
originatingElementsList.add(method);
while (enclosing != null) {
if (enclosing.getKind() == ElementKind.CLASS || enclosing.getKind() == ElementKind.INTERFACE) {
if (enclosing.getModifiers().contains(Modifier.PRIVATE)) {
- errorMessage(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
+ printError(method, "MatchRule cannot be declared in a private %s %s", enclosing.getKind().name().toLowerCase(), enclosing);
return;
}
originatingElementsList.add(enclosing);
@@ -988,144 +983,26 @@
info.matchRules.add(new MatchRuleItem(match, invoker));
}
} catch (RuleParseError e) {
- errorMessage(method, mirror, e.getMessage());
+ printError(method, matchRule, e.getMessage());
}
}
- private void errorMessage(Element element, String format, Object... args) {
- processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element);
- }
-
- private void errorMessage(Element element, AnnotationMirror mirror, String format, Object... args) {
- processingEnv.getMessager().printMessage(Kind.ERROR, String.format(format, args), element, mirror);
- }
-
- // TODO borrowed from com.oracle.truffle.dsl.processor.Utils
- @SuppressWarnings("unchecked")
- private static <T> List<T> getAnnotationValueList(Class<T> expectedListType, AnnotationMirror mirror, String name) {
- List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
- List<T> result = new ArrayList<>();
-
- if (values != null) {
- for (AnnotationValue value : values) {
- T annotationValue = resolveAnnotationValue(expectedListType, value);
- if (annotationValue != null) {
- result.add(annotationValue);
- }
- }
+ private Element elementForMessage(Element e) {
+ if (currentRound != null && !currentRound.getRootElements().contains(e) && currentElement != null) {
+ return currentElement;
}
- return result;
- }
-
- private static <T> T getAnnotationValue(Class<T> expectedType, AnnotationMirror mirror, String name) {
- return resolveAnnotationValue(expectedType, getAnnotationValue(mirror, name));
- }
-
- @SuppressWarnings({"unchecked"})
- private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
- if (value == null) {
- return null;
- }
-
- Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
- if (unboxedValue != null) {
- if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
- return null;
- }
- if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
- throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
- }
- }
- return (T) unboxedValue;
- }
-
- private static AnnotationValue getAnnotationValue(AnnotationMirror mirror, String name) {
- ExecutableElement valueMethod = null;
- for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
- if (method.getSimpleName().toString().equals(name)) {
- valueMethod = method;
- break;
- }
- }
-
- if (valueMethod == null) {
- return null;
- }
-
- AnnotationValue value = mirror.getElementValues().get(valueMethod);
- if (value == null) {
- value = valueMethod.getDefaultValue();
- }
-
- return value;
+ return e;
}
- private static class AnnotationValueVisitorImpl extends AbstractAnnotationValueVisitor7<Object, Void> {
-
- @Override
- public Object visitBoolean(boolean b, Void p) {
- return Boolean.valueOf(b);
- }
-
- @Override
- public Object visitByte(byte b, Void p) {
- return Byte.valueOf(b);
- }
-
- @Override
- public Object visitChar(char c, Void p) {
- return c;
- }
-
- @Override
- public Object visitDouble(double d, Void p) {
- return d;
- }
-
- @Override
- public Object visitFloat(float f, Void p) {
- return f;
- }
-
- @Override
- public Object visitInt(int i, Void p) {
- return i;
- }
+ private void printError(Element annotatedElement, String format, Object... args) {
+ Element e = elementForMessage(annotatedElement);
+ String prefix = e == annotatedElement ? "" : annotatedElement + ": ";
+ processingEnv.getMessager().printMessage(Kind.ERROR, prefix + String.format(format, args), e);
+ }
- @Override
- public Object visitLong(long i, Void p) {
- return i;
- }
-
- @Override
- public Object visitShort(short s, Void p) {
- return s;
- }
-
- @Override
- public Object visitString(String s, Void p) {
- return s;
- }
-
- @Override
- public Object visitType(TypeMirror t, Void p) {
- return t;
- }
-
- @Override
- public Object visitEnumConstant(VariableElement c, Void p) {
- return c;
- }
-
- @Override
- public Object visitAnnotation(AnnotationMirror a, Void p) {
- return a;
- }
-
- @Override
- public Object visitArray(List<? extends AnnotationValue> vals, Void p) {
- return vals;
- }
-
+ private void printError(Element annotatedElement, AnnotationMirror annotation, String format, Object... args) {
+ Element e = elementForMessage(annotatedElement);
+ String prefix = e == annotatedElement ? "" : annotation + " on " + annotatedElement + ": ";
+ processingEnv.getMessager().printMessage(Kind.ERROR, prefix + String.format(format, args), e, annotation);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java Thu May 31 10:38:05 2018 -0700
@@ -169,7 +169,7 @@
SPARCAddressValue address = (SPARCAddressValue) operand(cas.getAddress());
Condition condition = successIsTrue ? Condition.EQ : Condition.NE;
- Value result = getLIRGeneratorTool().emitValueCompareAndSwap(address, expectedValue, newValue);
+ Value result = getLIRGeneratorTool().emitValueCompareAndSwap(kind, address, expectedValue, newValue);
getLIRGeneratorTool().emitCompareBranch(kind.getPlatformKind(), result, expectedValue, condition, false, trueLabel, falseLabel, trueLabelProbability);
return null;
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ArrayLengthProviderTest.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+
+public class ArrayLengthProviderTest extends GraalCompilerTest {
+
+ public static Object test0Snippet(ArrayList<?> list, boolean a) {
+ while (true) {
+ Object[] array = toArray(list);
+ if (array.length < 1) {
+ return null;
+ }
+ if (array[0] instanceof String || a) {
+ /*
+ * This code is outside of the loop. Accessing the array reqires a ValueProxyNode.
+ * When the simplification of the ArrayLengthNode replaces the length access with
+ * the ArrayList.size used to create the array, then the value needs to have a
+ * ValueProxyNode too. In addition, the two parts of the if-condition actually lead
+ * to two separate loop exits, with two separate proxy nodes. A ValuePhiNode is
+ * present originally for the array, and the array length simplification needs to
+ * create a new ValuePhiNode for the two newly introduced ValueProxyNode.
+ */
+ if (array.length < 1) {
+ return null;
+ }
+ return array[0];
+ }
+ }
+ }
+
+ public static Object test1Snippet(ArrayList<?> list, boolean a, boolean b) {
+ while (true) {
+ Object[] array = toArray(list);
+ if (a || b) {
+ if (array.length < 1) {
+ return null;
+ }
+ return array[0];
+ }
+ }
+ }
+
+ public static Object[] toArray(List<?> list) {
+ return new Object[list.size()];
+ }
+
+ @Test
+ public void test0() {
+ test("test0Snippet", new ArrayList<>(Arrays.asList("a", "b")), true);
+ }
+
+ @Test
+ public void test1() {
+ test("test1Snippet", new ArrayList<>(Arrays.asList("a", "b")), true, true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CanonicalizedConversionTest.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,84 @@
+/*
+ * 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.graph.Node;
+import org.graalvm.compiler.nodes.IfNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
+import org.graalvm.compiler.nodes.calc.ReinterpretNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests that substitutions for {@link Double#doubleToLongBits(double)} and
+ * {@link Float#floatToIntBits(float)} produce graphs such that multiple calls to these methods with
+ * the same input are canonicalized.
+ */
+public class CanonicalizedConversionTest extends GraalCompilerTest {
+
+ @Override
+ protected boolean checkLowTierGraph(StructuredGraph graph) {
+ int reinterpretCount = 0;
+ int floatEqualsCount = 0;
+ int addCount = 0;
+ for (Node node : graph.getNodes()) {
+ if (node instanceof ReinterpretNode) {
+ reinterpretCount++;
+ } else if (node instanceof FloatEqualsNode) {
+ floatEqualsCount++;
+ } else if (node instanceof IfNode) {
+ Assert.fail("Unexpected node: " + node);
+ } else if (node instanceof AddNode) {
+ addCount++;
+ }
+ }
+ Assert.assertEquals(1, reinterpretCount);
+ Assert.assertEquals(1, floatEqualsCount);
+ Assert.assertEquals(2, addCount);
+ return true;
+ }
+
+ @Test
+ public void test4() {
+ test("snippet4", 567.890F);
+ test("snippet4", -567.890F);
+ test("snippet4", Float.NaN);
+ }
+
+ public static int snippet4(float value) {
+ return Float.floatToIntBits(value) + Float.floatToIntBits(value) + Float.floatToIntBits(value);
+ }
+
+ @Test
+ public void test5() {
+ test("snippet5", 567.890D);
+ test("snippet5", -567.890D);
+ test("snippet5", Double.NaN);
+ }
+
+ public static long snippet5(double value) {
+ return Double.doubleToLongBits(value) + Double.doubleToLongBits(value) + Double.doubleToLongBits(value);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest15.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,86 @@
+/*
+ * 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.debug.DebugContext;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.IterativeConditionalEliminationPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Collection of tests for {@link org.graalvm.compiler.phases.common.ConditionalEliminationPhase}
+ * including those that triggered bugs in this phase.
+ */
+public class ConditionalEliminationTest15 extends ConditionalEliminationTestBase {
+
+ private void checkNodeCount(String methodName, Class<? extends Node> nodeClass, int count) {
+ StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
+
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+ PhaseContext context = new PhaseContext(getProviders());
+
+ new LoweringPhase(new CanonicalizerPhase(), LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, context);
+ canonicalizer.apply(graph, context);
+
+ // Merge arr.length reads.
+ new EarlyReadEliminationPhase(canonicalizer).apply(graph, context);
+ new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
+
+ getDebugContext().dump(DebugContext.BASIC_LEVEL, graph, "After ConditionalEliminationPhase");
+
+ Assert.assertEquals(count, graph.getNodes().filter(nodeClass).count());
+ }
+
+ public static int testRedundantIntegerLessThanNode(int index, int[] arr) {
+ while (arr[index] != 42) {
+ if (index >= 0) { // redundant
+ return 1;
+ }
+ }
+ return 2;
+ }
+
+ public static int testRedundantIntegerLessThanNode2(int index, int[] arr) {
+ while (arr[index] != 42) {
+ if (index < arr.length) { // redundant
+ return 1;
+ }
+ }
+ return 2;
+ }
+
+ @Test
+ public void testRedundantSignedLessThanNode() {
+ checkNodeCount("testRedundantIntegerLessThanNode", IntegerLessThanNode.class, 0);
+ checkNodeCount("testRedundantIntegerLessThanNode2", IntegerLessThanNode.class, 0);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest2.java Thu May 31 10:38:05 2018 -0700
@@ -22,15 +22,18 @@
*/
package org.graalvm.compiler.core.test;
+import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.nodes.GuardNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
import org.graalvm.compiler.phases.common.FloatingReadPhase;
import org.graalvm.compiler.phases.common.LoweringPhase;
-import org.graalvm.compiler.phases.common.ConditionalEliminationPhase;
import org.graalvm.compiler.phases.tiers.PhaseContext;
+import org.junit.Assert;
import org.junit.Test;
/**
@@ -60,6 +63,15 @@
final Entry next;
}
+ static class A {
+ }
+
+ static class B extends A {
+ }
+
+ static class C extends A {
+ }
+
public static Entry search(Entry start, String name, Entry alternative) {
Entry current = start;
do {
@@ -129,4 +141,81 @@
assertDeepEquals(0, graph.getNodes().filter(GuardNode.class).count());
}
+ private void checkInstanceOfCount(String methodName, int count) {
+ StructuredGraph graph = parseEager(methodName, AllowAssumptions.YES);
+
+ CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+ PhaseContext context = new PhaseContext(getProviders());
+
+ canonicalizer.apply(graph, context);
+ new ConditionalEliminationPhase(true).apply(graph, context);
+ getDebugContext().dump(DebugContext.BASIC_LEVEL, graph, "After ConditionalEliminationPhase");
+ canonicalizer.apply(graph, context);
+
+ Assert.assertEquals(count, graph.getNodes().filter(InstanceOfNode.class).count());
+ }
+
+ public static A testRedundantInstanceOfClass(Object value) {
+ if (value != null && value.getClass() == A.class) {
+ return (A) value;
+ }
+ return null;
+ }
+
+ public static Object testRedundantInstanceOfArray(Object value) {
+ if (value != null && value.getClass() == Object[].class) {
+ return ((Object[]) value)[0];
+ }
+ return null;
+ }
+
+ public static boolean testRedundantInstanceOfPrecise(Object value) {
+ if (value != null && value.getClass() == A.class) {
+ return value instanceof A;
+ }
+ return false;
+ }
+
+ public static boolean testRedundantInstanceOfImplicitNonNull(Object value) {
+ if (value.getClass() == A.class) {
+ return value instanceof A;
+ }
+ return false;
+ }
+
+ @Test
+ public void testRedundantInstanceOf() {
+ checkInstanceOfCount("testRedundantInstanceOfClass", 1);
+ checkInstanceOfCount("testRedundantInstanceOfArray", 1);
+ checkInstanceOfCount("testRedundantInstanceOfPrecise", 1);
+ checkInstanceOfCount("testRedundantInstanceOfImplicitNonNull", 1);
+ }
+
+ public static boolean testNonRedundantInstanceOfClass(Object value) {
+ if (value instanceof A) {
+ return (value != null && value.getClass() == A.class);
+ }
+ return false;
+ }
+
+ public static boolean testNonRedundantInstanceOfArray(Object value) {
+ if (value instanceof Object[]) {
+ return (value != null && value.getClass() == Object[].class);
+ }
+ return false;
+ }
+
+ public static boolean testNonRedundantInstanceOfImplicitNonNull(Object value) {
+ if (value instanceof Object[]) {
+ return value.getClass() == Object[].class;
+ }
+ return false;
+ }
+
+ @Test
+ public void testNonRedundantInstanceOf() {
+ checkInstanceOfCount("testNonRedundantInstanceOfClass", 2);
+ checkInstanceOfCount("testNonRedundantInstanceOfArray", 2);
+ checkInstanceOfCount("testNonRedundantInstanceOfImplicitNonNull", 2);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java Thu May 31 10:38:05 2018 -0700
@@ -1054,7 +1054,7 @@
try (DebugContext.Scope s = debug.scope("Compile", graphToCompile)) {
assert options != null;
Request<CompilationResult> request = new Request<>(graphToCompile, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
- graphToCompile.getProfilingInfo(), createSuites(options), createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default);
+ graphToCompile.getProfilingInfo(), createSuites(options), createLIRSuites(options), compilationResult, CompilationResultBuilderFactory.Default, true);
return GraalCompiler.compile(request);
} catch (Throwable e) {
throw debug.handle(e);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/InfopointReasonTest.java Thu May 31 10:38:05 2018 -0700
@@ -68,7 +68,7 @@
final ResolvedJavaMethod method = getResolvedJavaMethod("testMethod");
final StructuredGraph graph = parseEager(method, AllowAssumptions.YES);
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
- createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
+ createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true);
for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason);
if (sp instanceof Call) {
@@ -90,7 +90,7 @@
assertTrue(graphLineSPs > 0);
PhaseSuite<HighTierContext> graphBuilderSuite = getCustomGraphBuilderSuite(GraphBuilderConfiguration.getDefault(getDefaultGraphBuilderPlugins()).withFullInfopoints(true));
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), graphBuilderSuite, OptimisticOptimizations.ALL, graph.getProfilingInfo(),
- createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
+ createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true);
int lineSPs = 0;
for (Infopoint sp : cr.getInfopoints()) {
assertNotNull(sp.reason);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/tutorial/InvokeGraal.java Thu May 31 10:38:05 2018 -0700
@@ -127,7 +127,7 @@
CompilationResultBuilderFactory factory = CompilationResultBuilderFactory.Default;
/* Invoke the whole Graal compilation pipeline. */
- GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory);
+ GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory, true);
/*
* Install the compilation result into the VM, i.e., copy the byte[] array that contains
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java Thu May 31 10:38:05 2018 -0700
@@ -106,6 +106,7 @@
public final LIRSuites lirSuites;
public final T compilationResult;
public final CompilationResultBuilderFactory factory;
+ public final boolean verifySourcePositions;
/**
* @param graph the graph to be compiled
@@ -122,7 +123,8 @@
* @param factory
*/
public Request(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend, PhaseSuite<HighTierContext> graphBuilderSuite,
- OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory) {
+ OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult, CompilationResultBuilderFactory factory,
+ boolean verifySourcePositions) {
this.graph = graph;
this.installedCodeOwner = installedCodeOwner;
this.providers = providers;
@@ -134,6 +136,7 @@
this.lirSuites = lirSuites;
this.compilationResult = compilationResult;
this.factory = factory;
+ this.verifySourcePositions = verifySourcePositions;
}
/**
@@ -156,8 +159,9 @@
*/
public static <T extends CompilationResult> T compileGraph(StructuredGraph graph, ResolvedJavaMethod installedCodeOwner, Providers providers, Backend backend,
PhaseSuite<HighTierContext> graphBuilderSuite, OptimisticOptimizations optimisticOpts, ProfilingInfo profilingInfo, Suites suites, LIRSuites lirSuites, T compilationResult,
- CompilationResultBuilderFactory factory) {
- return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory));
+ CompilationResultBuilderFactory factory, boolean verifySourcePositions) {
+ return compile(new Request<>(graph, installedCodeOwner, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, compilationResult, factory,
+ verifySourcePositions));
}
/**
@@ -173,6 +177,9 @@
try (DebugContext.Scope s0 = debug.scope("GraalCompiler", r.graph, r.providers.getCodeCache()); DebugCloseable a = CompilerTimer.start(debug)) {
emitFrontEnd(r.providers, r.backend, r.graph, r.graphBuilderSuite, r.optimisticOpts, r.profilingInfo, r.suites);
emitBackEnd(r.graph, null, r.installedCodeOwner, r.backend, r.compilationResult, r.factory, null, r.lirSuites);
+ if (r.verifySourcePositions) {
+ assert r.graph.verifySourcePositions(true);
+ }
} catch (Throwable e) {
throw debug.handle(e);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeMatchRules.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -22,8 +22,6 @@
*/
package org.graalvm.compiler.core.gen;
-import jdk.vm.ci.meta.Value;
-
import org.graalvm.compiler.core.match.MatchableNode;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.lir.LIRFrameState;
@@ -62,6 +60,8 @@
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.WriteNode;
+import jdk.vm.ci.meta.Value;
+
@MatchableNode(nodeClass = ConstantNode.class, shareable = true)
@MatchableNode(nodeClass = FloatConvertNode.class, inputs = {"value"})
@MatchableNode(nodeClass = FloatingReadNode.class, inputs = {"address"})
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java Thu May 31 10:38:05 2018 -0700
@@ -167,6 +167,32 @@
}
@Test
+ public void testContextScope() {
+ OptionValues options = new OptionValues(EconomicMap.create());
+ options = new OptionValues(options, DebugOptions.Log, ":5");
+ DebugContextSetup setup = new DebugContextSetup();
+ try (DebugContext debug = setup.openDebugContext(options)) {
+ try (DebugContext.Scope s0 = debug.scope("TestLogging")) {
+ try (DebugContext.Scope s1 = debug.withContext("A")) {
+ for (Object o : debug.context()) {
+ Assert.assertEquals(o, "A");
+ }
+ } catch (Throwable t) {
+ throw debug.handle(t);
+ }
+ try (DebugContext.Scope s1 = debug.withContext("B")) {
+ for (Object o : debug.context()) {
+ Assert.assertEquals(o, "B");
+ }
+ } catch (Throwable t) {
+ throw debug.handle(t);
+ }
+ }
+ }
+
+ }
+
+ @Test
public void testEnabledSandbox() {
EconomicMap<OptionKey<?>, Object> map = EconomicMap.create();
// Configure with an option that enables scopes
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CausableByCompilerAssert.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.debug;
+
+public interface CausableByCompilerAssert {
+ boolean isCausedByCompilerAssert();
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugConfigImpl.java Thu May 31 10:38:05 2018 -0700
@@ -239,8 +239,11 @@
@Override
public RuntimeException interceptException(DebugContext debug, Throwable e) {
- if (e instanceof BailoutException && !DebugOptions.InterceptBailout.getValue(options)) {
- return null;
+ if (e instanceof BailoutException) {
+ final boolean causedByCompilerAssert = e instanceof CausableByCompilerAssert && ((CausableByCompilerAssert) e).isCausedByCompilerAssert();
+ if (!DebugOptions.InterceptBailout.getValue(options) && !causedByCompilerAssert) {
+ return null;
+ }
}
OptionValues interceptOptions = new OptionValues(options,
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java Thu May 31 10:38:05 2018 -0700
@@ -96,7 +96,7 @@
*/
boolean metricsEnabled;
- DebugConfig currentConfig;
+ DebugConfigImpl currentConfig;
ScopeImpl currentScope;
CloseableCounter currentTimer;
CloseableCounter currentMemUseTracker;
@@ -739,6 +739,19 @@
}
/**
+ * Create an unnamed scope that appends some context to the current scope.
+ *
+ * @param context an object to be appended to the {@linkplain #context() current} debug context
+ */
+ public DebugContext.Scope withContext(Object context) throws Throwable {
+ if (currentScope != null) {
+ return enterScope("", null, context);
+ } else {
+ return null;
+ }
+ }
+
+ /**
* Creates and enters a new debug scope which will be disjoint from the current debug scope.
* <p>
* It is recommended to use the try-with-resource statement for managing entering and leaving
@@ -787,7 +800,7 @@
class DisabledScope implements DebugContext.Scope {
final boolean savedMetricsEnabled;
final ScopeImpl savedScope;
- final DebugConfig savedConfig;
+ final DebugConfigImpl savedConfig;
DisabledScope() {
this.savedMetricsEnabled = metricsEnabled;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugValueMap.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 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.debug;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A node in a tree of values.
- */
-public class DebugValueMap {
-
- /**
- * The top level maps for all threads.
- */
- private static final List<DebugValueMap> topLevelMaps = new ArrayList<>();
-
- private long[] values;
- private List<DebugValueMap> children;
- private String name;
-
- public DebugValueMap(String name) {
- this.name = name;
- }
-
- public void setCurrentValue(int index, long l) {
- ensureSize(index);
- values[index] = l;
- }
-
- public long getCurrentValue(int index) {
- ensureSize(index);
- return values[index];
- }
-
- public void clearChildren() {
- if (children != null) {
- children.clear();
- }
- }
-
- public void reset() {
- if (values != null) {
- Arrays.fill(values, 0L);
- }
- if (children != null) {
- for (DebugValueMap child : children) {
- child.reset();
- }
- }
- }
-
- private void ensureSize(int index) {
- if (values == null) {
- values = new long[index + 1];
- }
- if (values.length <= index) {
- values = Arrays.copyOf(values, index + 1);
- }
- }
-
- private int capacity() {
- return (values == null) ? 0 : values.length;
- }
-
- public void addChild(DebugValueMap map) {
- if (children == null) {
- children = new ArrayList<>(4);
- }
- children.add(map);
- }
-
- public List<DebugValueMap> getChildren() {
- if (children == null) {
- return Collections.emptyList();
- } else {
- return Collections.unmodifiableList(children);
- }
- }
-
- public boolean hasChildren() {
- return children != null && !children.isEmpty();
- }
-
- public String getName() {
- return this.name;
- }
-
- @Override
- public String toString() {
- return "DebugValueMap<" + getName() + ">";
- }
-
- public static synchronized void registerTopLevel(DebugValueMap map) {
- topLevelMaps.add(map);
- }
-
- public static synchronized List<DebugValueMap> getTopLevelMaps() {
- return topLevelMaps;
- }
-
- /**
- * The top level map for the current thread.
- */
- private static final ThreadLocal<DebugValueMap> topLevelMap = new ThreadLocal<>();
-
- static DebugValueMap getTopLevelMap() {
- DebugValueMap map = topLevelMap.get();
- if (map == null) {
- map = new DebugValueMap(Thread.currentThread().getName());
- topLevelMap.set(map);
- registerTopLevel(map);
- }
- return map;
- }
-
- public void normalize() {
- if (hasChildren()) {
- Map<String, DebugValueMap> occurred = new HashMap<>();
- for (DebugValueMap map : children) {
- String mapName = map.getName();
- if (!occurred.containsKey(mapName)) {
- occurred.put(mapName, map);
- map.normalize();
- } else {
- occurred.get(mapName).mergeWith(map);
- occurred.get(mapName).normalize();
- }
- }
-
- if (occurred.values().size() < children.size()) {
- // At least one duplicate was found.
- children.clear();
- for (DebugValueMap map : occurred.values()) {
- addChild(map);
- map.normalize();
- }
- }
- }
- }
-
- private void mergeWith(DebugValueMap map) {
- if (map.hasChildren()) {
- if (hasChildren()) {
- children.addAll(map.children);
- } else {
- children = map.children;
- }
- map.children = null;
- }
-
- int size = Math.max(this.capacity(), map.capacity());
- ensureSize(size);
- for (int i = 0; i < size; ++i) {
- long curValue = getCurrentValue(i);
- long otherValue = map.getCurrentValue(i);
- setCurrentValue(i, curValue + otherValue);
- }
- }
-
- public void group() {
- if (this.hasChildren()) {
- List<DebugValueMap> oldChildren = new ArrayList<>(this.children);
- this.children.clear();
- for (DebugValueMap map : oldChildren) {
- mergeWith(map);
- }
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/PathUtilities.java Thu May 31 10:38:05 2018 -0700
@@ -72,9 +72,10 @@
/**
* A maximum file name length supported by most file systems. There is no platform independent
- * way to get this in Java.
+ * way to get this in Java. Normally it is 255. But for AUFS it is 242. Refer AUFS_MAX_NAMELEN
+ * in http://aufs.sourceforge.net/aufs3/man.html.
*/
- private static final int MAX_FILE_NAME_LENGTH = 255;
+ private static final int MAX_FILE_NAME_LENGTH = 242;
private static final String ELLIPSIS = "...";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/ScopeImpl.java Thu May 31 10:38:05 2018 -0700
@@ -38,31 +38,35 @@
final String indent;
final IndentImpl parentIndent;
+ boolean isEmitted() {
+ return emitted;
+ }
+
+ private boolean emitted;
+
IndentImpl(IndentImpl parentIndent) {
this.parentIndent = parentIndent;
this.indent = (parentIndent == null ? "" : parentIndent.indent + INDENTATION_INCREMENT);
}
- private boolean logScopeName() {
- return logScopeName;
- }
-
private void printScopeName(StringBuilder str, boolean isCurrent) {
- if (logScopeName) {
- boolean parentPrinted = false;
+ if (!emitted) {
+ boolean mustPrint = true;
if (parentIndent != null) {
- parentPrinted = parentIndent.logScopeName();
- parentIndent.printScopeName(str, false);
+ if (!parentIndent.isEmitted()) {
+ parentIndent.printScopeName(str, false);
+ mustPrint = false;
+ }
}
/*
- * Always print the current scope, scopes with context and the any scope whose
- * parent didn't print. This ensure the first new scope always shows up.
+ * Always print the current scope, scopes with context and any scope whose parent
+ * didn't print. This ensure the first new scope always shows up.
*/
- if (isCurrent || printContext(null) != 0 || !parentPrinted) {
+ if (isCurrent || printContext(null) != 0 || mustPrint) {
str.append(indent).append("[thread:").append(Thread.currentThread().getId()).append("] scope: ").append(getQualifiedName()).append(System.lineSeparator());
}
printContext(str);
- logScopeName = false;
+ emitted = true;
}
}
@@ -116,7 +120,12 @@
private final ScopeImpl parent;
private final boolean sandbox;
private IndentImpl lastUsedIndent;
- private boolean logScopeName;
+
+ private boolean isEmptyScope() {
+ return emptyScope;
+ }
+
+ private final boolean emptyScope;
private final Object[] context;
@@ -136,23 +145,24 @@
private PrintStream output;
private boolean interceptDisabled;
- static final Object[] EMPTY_CONTEXT = new Object[0];
-
ScopeImpl(DebugContext owner, Thread thread) {
this(owner, thread.getName(), null, false);
}
- ScopeImpl(DebugContext owner, String unqualifiedName, ScopeImpl parent, boolean sandbox, Object... context) {
+ private ScopeImpl(DebugContext owner, String unqualifiedName, ScopeImpl parent, boolean sandbox, Object... context) {
this.owner = owner;
this.parent = parent;
this.sandbox = sandbox;
this.context = context;
this.unqualifiedName = unqualifiedName;
if (parent != null) {
- logScopeName = !unqualifiedName.equals("");
+ emptyScope = unqualifiedName.equals("");
this.interceptDisabled = parent.interceptDisabled;
} else {
- logScopeName = true;
+ if (unqualifiedName.isEmpty()) {
+ throw new IllegalArgumentException("root scope name must be non-empty");
+ }
+ emptyScope = false;
}
this.output = TTY.out;
@@ -169,29 +179,29 @@
return parent == null;
}
- public boolean isDumpEnabled(int dumpLevel) {
+ boolean isDumpEnabled(int dumpLevel) {
assert dumpLevel >= 0;
return currentDumpLevel >= dumpLevel;
}
- public boolean isVerifyEnabled() {
+ boolean isVerifyEnabled() {
return verifyEnabled;
}
- public boolean isLogEnabled(int logLevel) {
+ boolean isLogEnabled(int logLevel) {
assert logLevel > 0;
return currentLogLevel >= logLevel;
}
- public boolean isCountEnabled() {
+ boolean isCountEnabled() {
return countEnabled;
}
- public boolean isTimeEnabled() {
+ boolean isTimeEnabled() {
return timeEnabled;
}
- public boolean isMemUseTrackingEnabled() {
+ boolean isMemUseTrackingEnabled() {
return memUseTrackingEnabled;
}
@@ -307,7 +317,7 @@
throw silenceException(RuntimeException.class, e);
}
- void updateFlags(DebugConfig config) {
+ void updateFlags(DebugConfigImpl config) {
if (config == null) {
countEnabled = false;
memUseTrackingEnabled = false;
@@ -317,6 +327,14 @@
// Be pragmatic: provide a default log stream to prevent a crash if the stream is not
// set while logging
output = TTY.out;
+ } else if (isEmptyScope()) {
+ countEnabled = parent.countEnabled;
+ memUseTrackingEnabled = parent.memUseTrackingEnabled;
+ timeEnabled = parent.timeEnabled;
+ verifyEnabled = parent.verifyEnabled;
+ output = parent.output;
+ currentDumpLevel = parent.currentDumpLevel;
+ currentLogLevel = parent.currentLogLevel;
} else {
countEnabled = config.isCountEnabled(this);
memUseTrackingEnabled = config.isMemUseTrackingEnabled(this);
@@ -404,18 +422,21 @@
if (parent == null) {
qualifiedName = unqualifiedName;
} else {
- qualifiedName = parent.getQualifiedName() + SCOPE_SEP + unqualifiedName;
+ qualifiedName = parent.getQualifiedName();
+ if (!isEmptyScope()) {
+ qualifiedName += SCOPE_SEP + unqualifiedName;
+ }
}
}
return qualifiedName;
}
- public Indent pushIndentLogger() {
+ Indent pushIndentLogger() {
lastUsedIndent = getLastUsedIndent().indent();
return lastUsedIndent;
}
- public IndentImpl getLastUsedIndent() {
+ private IndentImpl getLastUsedIndent() {
if (lastUsedIndent == null) {
if (parent != null) {
lastUsedIndent = new IndentImpl(parent.getLastUsedIndent());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java Thu May 31 10:38:05 2018 -0700
@@ -1199,7 +1199,7 @@
return true;
}
- public boolean verifySourcePositions() {
+ public boolean verifySourcePositions(boolean performConsistencyCheck) {
if (trackNodeSourcePosition()) {
ResolvedJavaMethod root = null;
for (Node node : getNodes()) {
@@ -1211,6 +1211,11 @@
assert pos.verifyRootMethod(root) : node;
}
}
+
+ // More strict node-type-specific check
+ if (performConsistencyCheck) {
+ node.verifySourcePosition();
+ }
}
}
return true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Node.java Thu May 31 10:38:05 2018 -0700
@@ -263,7 +263,7 @@
static class NodeCreationStackTrace extends NodeStackTrace {
}
- static class NodeInsertionStackTrace extends NodeStackTrace {
+ public static class NodeInsertionStackTrace extends NodeStackTrace {
}
public Node(NodeClass<? extends Node> c) {
@@ -1063,6 +1063,10 @@
return true;
}
+ public boolean verifySourcePosition() {
+ return true;
+ }
+
/**
* Perform expensive verification of inputs, usages, predecessors and successors.
*
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java Thu May 31 10:38:05 2018 -0700
@@ -51,6 +51,7 @@
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.debug.TTY;
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.graph.Edges.Type;
import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -125,11 +126,33 @@
}
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());
+ int numTries = 0;
+ while (true) {
+ boolean shouldBeInitializedBefore = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+
+ NodeClass<T> result = getUnchecked(clazz);
+ if (result != null || clazz == NODE_CLASS) {
+ return result;
+ }
+
+ /*
+ * GR-9537: We observed a transient problem with TYPE fields being null. Retry a couple
+ * of times and print something to the log so that we can gather more diagnostic
+ * information without failing gates.
+ */
+ numTries++;
+ boolean shouldBeInitializedAfter = UnsafeAccess.UNSAFE.shouldBeInitialized(clazz);
+ String msg = "GR-9537 Reflective field access of TYPE field returned null. This is probably a bug in HotSpot class initialization. " +
+ " clazz: " + clazz.getTypeName() + ", numTries: " + numTries +
+ ", shouldBeInitializedBefore: " + shouldBeInitializedBefore + ", shouldBeInitializedAfter: " + shouldBeInitializedAfter;
+ if (numTries <= 100) {
+ TTY.println(msg);
+ UnsafeAccess.UNSAFE.ensureClassInitialized(clazz);
+ } else {
+ throw GraalError.shouldNotReachHere(msg);
+ }
+ return result;
}
- return result;
}
private static final Class<?> NODE_CLASS = Node.class;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java Thu May 31 10:38:05 2018 -0700
@@ -29,6 +29,7 @@
import static jdk.vm.ci.aarch64.AArch64.zr;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
import jdk.internal.vm.compiler.collections.EconomicSet;
@@ -41,6 +42,7 @@
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.core.aarch64.AArch64NodeMatchRules;
import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -48,6 +50,7 @@
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
import org.graalvm.compiler.hotspot.HotSpotHostBackend;
import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.stubs.Stub;
@@ -66,12 +69,15 @@
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.code.CallingConvention;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.code.RegisterConfig;
import jdk.vm.ci.code.StackSlot;
import jdk.vm.ci.hotspot.HotSpotCallingConventionType;
+import jdk.vm.ci.hotspot.HotSpotSentinelConstant;
import jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig;
+import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaType;
import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -269,7 +275,7 @@
Register klass = r10;
if (config.useCompressedClassPointers) {
masm.ldr(32, klass, klassAddress);
- AArch64HotSpotMove.decodeKlassPointer(masm, klass, klass, providers.getRegisters().getHeapBaseRegister(), config.getKlassEncoding());
+ AArch64HotSpotMove.decodeKlassPointer(crb, masm, klass, klass, config.getKlassEncoding(), config);
} else {
masm.ldr(64, klass, klassAddress);
}
@@ -285,6 +291,23 @@
crb.recordMark(config.MARKID_OSR_ENTRY);
masm.bind(verifiedStub);
crb.recordMark(config.MARKID_VERIFIED_ENTRY);
+
+ if (GeneratePIC.getValue(crb.getOptions())) {
+ // Check for method state
+ HotSpotFrameContext frameContext = (HotSpotFrameContext) crb.frameContext;
+ if (!frameContext.isStub) {
+ crb.recordInlineDataInCodeWithNote(new HotSpotSentinelConstant(LIRKind.value(AArch64Kind.QWORD), JavaKind.Long), HotSpotConstantLoadAction.MAKE_NOT_ENTRANT);
+ try (ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ masm.addressOf(scratch);
+ masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+ Label noCall = new Label();
+ masm.cbz(64, scratch, noCall);
+ AArch64Call.directJmp(crb, masm, getForeignCalls().lookupForeignCall(WRONG_METHOD_HANDLER));
+ masm.bind(noCall);
+ }
+ }
+ }
}
private static void emitCodeBody(CompilationResultBuilder crb, LIR lir, AArch64MacroAssembler masm) {
@@ -299,8 +322,10 @@
* @see "http://mail.openjdk.java.net/pipermail/aarch64-port-dev/2013-September/000273.html"
*/
public static void emitInvalidatePlaceholder(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
- crb.blockComment("[nop for method invalidation]");
- masm.nop();
+ if (!GeneratePIC.getValue(crb.getOptions())) {
+ crb.blockComment("[nop for method invalidation]");
+ masm.nop();
+ }
}
private void emitCodeSuffix(CompilationResultBuilder crb, AArch64MacroAssembler masm, FrameMap frameMap) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -25,6 +26,10 @@
import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.common.InitTimer.timer;
+import jdk.vm.ci.code.Architecture;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.TargetDescription;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.aarch64.AArch64AddressLoweringByUse;
@@ -64,10 +69,6 @@
import org.graalvm.compiler.word.WordTypes;
import jdk.vm.ci.aarch64.AArch64;
-import jdk.vm.ci.code.Architecture;
-import jdk.vm.ci.code.RegisterArray;
-import jdk.vm.ci.code.RegisterConfig;
-import jdk.vm.ci.code.TargetDescription;
import jdk.vm.ci.common.InitTimer;
import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
import jdk.vm.ci.hotspot.HotSpotConstantReflectionProvider;
@@ -77,6 +78,9 @@
import jdk.vm.ci.meta.Value;
import jdk.vm.ci.runtime.JVMCIBackend;
+import java.util.ArrayList;
+import java.util.List;
+
@ServiceProvider(HotSpotBackendFactory.class)
public class AArch64HotSpotBackendFactory implements HotSpotBackendFactory {
@@ -200,12 +204,20 @@
}
protected static Value[] createNativeABICallerSaveRegisters(@SuppressWarnings("unused") GraalHotSpotVMConfig config, RegisterConfig regConfig) {
- AArch64HotSpotRegisterConfig conf = (AArch64HotSpotRegisterConfig) regConfig;
- RegisterArray callerSavedRegisters = conf.getCallerSaveRegisters();
- int size = callerSavedRegisters.size();
- Value[] nativeABICallerSaveRegisters = new Value[size];
- for (int i = 0; i < size; i++) {
- nativeABICallerSaveRegisters[i] = callerSavedRegisters.get(i).asValue();
+ List<Register> callerSave = new ArrayList<>(regConfig.getAllocatableRegisters().asList());
+ callerSave.remove(AArch64.r19);
+ callerSave.remove(AArch64.r20);
+ callerSave.remove(AArch64.r21);
+ callerSave.remove(AArch64.r22);
+ callerSave.remove(AArch64.r23);
+ callerSave.remove(AArch64.r24);
+ callerSave.remove(AArch64.r25);
+ callerSave.remove(AArch64.r26);
+ callerSave.remove(AArch64.r27);
+ callerSave.remove(AArch64.r28);
+ Value[] nativeABICallerSaveRegisters = new Value[callerSave.size()];
+ for (int i = 0; i < callerSave.size(); i++) {
+ nativeABICallerSaveRegisters[i] = callerSave.get(i).asValue();
}
return nativeABICallerSaveRegisters;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallEpilogueOp.java Thu May 31 10:38:05 2018 -0700
@@ -24,6 +24,7 @@
import static jdk.vm.ci.aarch64.AArch64.zr;
+import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
@@ -37,20 +38,22 @@
public static final LIRInstructionClass<AArch64HotSpotCRuntimeCallEpilogueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotCRuntimeCallEpilogueOp.class);
private final int threadLastJavaSpOffset;
- private final int threadLastJavaFpOffset;
+ private final int threadLastJavaPcOffset;
private final Register thread;
+ @SuppressWarnings("unused") private final Label label;
- public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaFpOffset, Register thread) {
+ public AArch64HotSpotCRuntimeCallEpilogueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, Label label) {
super(TYPE);
this.threadLastJavaSpOffset = threadLastJavaSpOffset;
- this.threadLastJavaFpOffset = threadLastJavaFpOffset;
+ this.threadLastJavaPcOffset = threadLastJavaPcOffset;
this.thread = thread;
+ this.label = label;
}
@Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
// Reset last Java frame:
masm.str(64, zr, masm.makeAddress(thread, threadLastJavaSpOffset, 8));
- masm.str(64, zr, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
+ masm.str(64, zr, masm.makeAddress(thread, threadLastJavaPcOffset, 8));
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotCRuntimeCallPrologueOp.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -25,7 +26,6 @@
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static jdk.vm.ci.aarch64.AArch64.sp;
import static jdk.vm.ci.code.ValueUtil.asRegister;
-import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
@@ -43,16 +43,14 @@
private final int threadLastJavaSpOffset;
private final int threadLastJavaPcOffset;
- private final int threadLastJavaFpOffset;
private final Register thread;
@Temp({REG}) protected AllocatableValue scratch;
private final Label label;
- public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, int threadLastJavaFpOffset, Register thread, AllocatableValue scratch, Label label) {
+ public AArch64HotSpotCRuntimeCallPrologueOp(int threadLastJavaSpOffset, int threadLastJavaPcOffset, Register thread, AllocatableValue scratch, Label label) {
super(TYPE);
this.threadLastJavaSpOffset = threadLastJavaSpOffset;
this.threadLastJavaPcOffset = threadLastJavaPcOffset;
- this.threadLastJavaFpOffset = threadLastJavaFpOffset;
this.thread = thread;
this.scratch = scratch;
this.label = label;
@@ -69,7 +67,5 @@
// Get the current PC. Use a label to patch the return address.
masm.adr(scratchRegister, label);
masm.str(64, scratchRegister, masm.makeAddress(thread, threadLastJavaPcOffset, 8));
-
- masm.str(64, fp, masm.makeAddress(thread, threadLastJavaFpOffset, 8));
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotConstantRetrievalOp.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+
+import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.Value;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.lir.LIRFrameState;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.ValueProcedure;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotConstantRetrievalOp extends AArch64LIRInstruction {
+ public static final LIRInstructionClass<AArch64HotSpotConstantRetrievalOp> TYPE = LIRInstructionClass.create(AArch64HotSpotConstantRetrievalOp.class);
+
+ @Def protected AllocatableValue result;
+ protected final Constant[] constants;
+ @Alive protected AllocatableValue[] constantDescriptions;
+ @Temp protected AllocatableValue[] gotSlotOffsetParameters;
+ @Temp protected AllocatableValue[] descriptionParameters;
+ @Temp protected Value[] callTemps;
+ @State protected LIRFrameState frameState;
+ private final ForeignCallLinkage callLinkage;
+ private final Object[] notes;
+
+ private class CollectTemporaries implements ValueProcedure {
+ ArrayList<Value> values = new ArrayList<>();
+
+ CollectTemporaries() {
+ forEachTemp(this);
+ }
+
+ public Value[] asArray() {
+ Value[] copy = new Value[values.size()];
+ return values.toArray(copy);
+ }
+
+ @Override
+ public Value doValue(Value value, OperandMode mode, EnumSet<OperandFlag> flags) {
+ values.add(value);
+ return value;
+ }
+ }
+
+ public AArch64HotSpotConstantRetrievalOp(Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState, ForeignCallLinkage callLinkage, Object[] notes) {
+ super(TYPE);
+ this.constantDescriptions = constantDescriptions;
+ this.constants = constants;
+ this.frameState = frameState;
+ this.notes = notes;
+ assert constants.length == notes.length;
+
+ // call arguments
+ CallingConvention callingConvention = callLinkage.getOutgoingCallingConvention();
+ this.gotSlotOffsetParameters = new AllocatableValue[constants.length];
+ int argIndex = 0;
+ for (int i = 0; i < constants.length; i++, argIndex++) {
+ this.gotSlotOffsetParameters[i] = callingConvention.getArgument(argIndex);
+ }
+ this.descriptionParameters = new AllocatableValue[constantDescriptions.length];
+ for (int i = 0; i < constantDescriptions.length; i++, argIndex++) {
+ this.descriptionParameters[i] = callingConvention.getArgument(argIndex);
+ }
+ this.result = callingConvention.getReturn();
+
+ this.callLinkage = callLinkage;
+
+ // compute registers that are killed by the stub, but are not used as other temps.
+ this.callTemps = new Value[0];
+ this.callTemps = LIRValueUtil.subtractRegisters(callLinkage.getTemporaries(), new CollectTemporaries().asArray());
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ // metadata_adr
+ for (int i = 0; i < constants.length; i++) {
+ crb.recordInlineDataInCodeWithNote(constants[i], notes[i]);
+ masm.addressOf(asRegister(gotSlotOffsetParameters[i]));
+ }
+
+ for (int i = 0; i < constantDescriptions.length; i++) {
+ masm.mov(64, asRegister(descriptionParameters[i]), asRegister(constantDescriptions[i]));
+ }
+
+ final int before = masm.position();
+ masm.bl(before);
+ final int after = masm.position();
+ crb.recordDirectCall(before, after, callLinkage, frameState);
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLIRGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -23,11 +24,21 @@
package org.graalvm.compiler.hotspot.aarch64;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.INITIALIZE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_KLASS_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_STRING_BY_SYMBOL;
+import static org.graalvm.compiler.hotspot.HotSpotBackend.RESOLVE_DYNAMIC_INVOKE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.RESOLVE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.INITIALIZE;
+import static org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction.LOAD_COUNTERS;
import static org.graalvm.compiler.lir.LIRValueUtil.asConstant;
import static org.graalvm.compiler.lir.LIRValueUtil.isConstantValue;
import java.util.function.Function;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.aarch64.AArch64Address.AddressingMode;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
@@ -38,6 +49,7 @@
import org.graalvm.compiler.core.common.CompressEncoding;
import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
import org.graalvm.compiler.core.common.spi.LIRKindTool;
import org.graalvm.compiler.debug.GraalError;
@@ -48,6 +60,7 @@
import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
import org.graalvm.compiler.hotspot.HotSpotLIRGenerator;
import org.graalvm.compiler.hotspot.HotSpotLockStack;
+import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
import org.graalvm.compiler.hotspot.stubs.Stub;
@@ -66,6 +79,9 @@
import org.graalvm.compiler.lir.aarch64.AArch64Move;
import org.graalvm.compiler.lir.aarch64.AArch64Move.StoreOp;
import org.graalvm.compiler.lir.aarch64.AArch64PrefetchOp;
+import org.graalvm.compiler.lir.aarch64.AArch64SaveRegistersOp;
+import org.graalvm.compiler.lir.aarch64.AArch64RestoreRegistersOp;
+
import org.graalvm.compiler.lir.gen.LIRGenerationResult;
import jdk.vm.ci.aarch64.AArch64;
@@ -84,6 +100,7 @@
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.PlatformKind;
import jdk.vm.ci.meta.Value;
+import org.graalvm.compiler.options.OptionValues;
/**
* LIR generator specialized for AArch64 HotSpot.
@@ -114,7 +131,7 @@
return getResult().getStub() != null;
}
- @SuppressWarnings("unused") private LIRFrameState currentRuntimeCallInfo;
+ private LIRFrameState currentRuntimeCallInfo;
@Override
protected void emitForeignCallOp(ForeignCallLinkage linkage, Value result, Value[] arguments, Value[] temps, LIRFrameState info) {
@@ -145,8 +162,45 @@
append(new AArch64CCall(nativeCallingConvention.getReturn(), ptr, argLocations));
}
- public SaveRegistersOp emitSaveAllRegisters() {
- throw GraalError.unimplemented();
+ /**
+ * @param savedRegisters the registers saved by this operation which may be subject to pruning
+ * @param savedRegisterLocations the slots to which the registers are saved
+ * @param supportsRemove determines if registers can be pruned
+ */
+ protected AArch64SaveRegistersOp emitSaveRegisters(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+ AArch64SaveRegistersOp save = new AArch64SaveRegistersOp(savedRegisters, savedRegisterLocations, supportsRemove);
+ append(save);
+ return save;
+ }
+
+ /**
+ * Allocate a stack slot for saving a register.
+ */
+ protected VirtualStackSlot allocateSaveRegisterLocation(Register register) {
+ PlatformKind kind = target().arch.getLargestStorableKind(register.getRegisterCategory());
+ if (kind.getVectorLength() > 1) {
+ // we don't use vector registers, so there is no need to save them
+ kind = AArch64Kind.QWORD;
+ }
+ return getResult().getFrameMapBuilder().allocateSpillSlot(LIRKind.value(kind));
+ }
+
+ /**
+ * Adds a node to the graph that saves all allocatable registers to the stack.
+ *
+ * @param supportsRemove determines if registers can be pruned
+ * @return the register save node
+ */
+ private AArch64SaveRegistersOp emitSaveAllRegisters(Register[] savedRegisters, boolean supportsRemove) {
+ AllocatableValue[] savedRegisterLocations = new AllocatableValue[savedRegisters.length];
+ for (int i = 0; i < savedRegisters.length; i++) {
+ savedRegisterLocations[i] = allocateSaveRegisterLocation(savedRegisters[i]);
+ }
+ return emitSaveRegisters(savedRegisters, savedRegisterLocations, supportsRemove);
+ }
+
+ protected void emitRestoreRegisters(AArch64SaveRegistersOp save) {
+ append(new AArch64RestoreRegistersOp(save.getSlots().clone(), save));
}
@Override
@@ -199,6 +253,7 @@
@Override
public Value emitCompress(Value pointer, CompressEncoding encoding, boolean nonNull) {
LIRKind inputKind = pointer.getValueKind(LIRKind.class);
+ LIRKindTool lirKindTool = getLIRKindTool();
assert inputKind.getPlatformKind() == AArch64Kind.QWORD;
if (inputKind.isReference(0)) {
// oop
@@ -209,8 +264,16 @@
// metaspace pointer
Variable result = newVariable(LIRKind.value(AArch64Kind.DWORD));
AllocatableValue base = Value.ILLEGAL;
- if (encoding.hasBase()) {
- base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ OptionValues options = getResult().getLIR().getOptions();
+ if (encoding.hasBase() || GeneratePIC.getValue(options)) {
+ if (GeneratePIC.getValue(options)) {
+ Variable baseAddress = newVariable(lirKindTool.getWordKind());
+ AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
+ append(move);
+ base = baseAddress;
+ } else {
+ base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ }
}
append(new AArch64HotSpotMove.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
return result;
@@ -230,8 +293,16 @@
// metaspace pointer
Variable result = newVariable(LIRKind.value(AArch64Kind.QWORD));
AllocatableValue base = Value.ILLEGAL;
- if (encoding.hasBase()) {
- base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ OptionValues options = getResult().getLIR().getOptions();
+ if (encoding.hasBase() || GeneratePIC.getValue(options)) {
+ if (GeneratePIC.getValue(options)) {
+ Variable baseAddress = newVariable(LIRKind.value(AArch64Kind.QWORD));
+ AArch64HotSpotMove.BaseMove move = new AArch64HotSpotMove.BaseMove(baseAddress, config);
+ append(move);
+ base = baseAddress;
+ } else {
+ base = emitLoadConstant(LIRKind.value(AArch64Kind.QWORD), JavaConstant.forLong(encoding.getBase()));
+ }
}
append(new AArch64HotSpotMove.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull));
return result;
@@ -270,6 +341,17 @@
@Override
public Variable emitForeignCall(ForeignCallLinkage linkage, LIRFrameState state, Value... args) {
HotSpotForeignCallLinkage hotspotLinkage = (HotSpotForeignCallLinkage) linkage;
+ boolean destroysRegisters = hotspotLinkage.destroysRegisters();
+
+ AArch64SaveRegistersOp save = null;
+ Stub stub = getStub();
+ if (destroysRegisters) {
+ if (stub != null && stub.preservesRegisters()) {
+ Register[] savedRegisters = getRegisterConfig().getAllocatableRegisters().toArray();
+ save = emitSaveAllRegisters(savedRegisters, true);
+ }
+ }
+
Variable result;
LIRFrameState debugInfo = null;
if (hotspotLinkage.needsDebugInfo()) {
@@ -277,7 +359,7 @@
assert debugInfo != null || getStub() != null;
}
- if (linkage.destroysRegisters() || hotspotLinkage.needsJavaFrameAnchor()) {
+ if (destroysRegisters || hotspotLinkage.needsJavaFrameAnchor()) {
HotSpotRegistersProvider registers = getProviders().getRegisters();
Register thread = registers.getThreadRegister();
Variable scratch = newVariable(LIRKind.value(target().arch.getWordKind()));
@@ -285,9 +367,9 @@
// We need a label for the return address.
label = new Label();
- append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), config.threadLastJavaFpOffset(), thread, scratch, label));
+ append(new AArch64HotSpotCRuntimeCallPrologueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, scratch, label));
result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
- append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaFpOffset(), thread));
+ append(new AArch64HotSpotCRuntimeCallEpilogueOp(config.threadLastJavaSpOffset(), config.threadLastJavaPcOffset(), thread, label));
// Clear it out so it's not being reused later.
label = null;
@@ -295,6 +377,21 @@
result = super.emitForeignCall(hotspotLinkage, debugInfo, args);
}
+ if (destroysRegisters) {
+ if (stub != null) {
+ if (stub.preservesRegisters()) {
+ HotSpotLIRGenerationResult generationResult = getResult();
+ LIRFrameState key = currentRuntimeCallInfo;
+ if (key == null) {
+ key = LIRFrameState.NO_STATE;
+ }
+ assert !generationResult.getCalleeSaveInfo().containsKey(key);
+ generationResult.getCalleeSaveInfo().put(key, save);
+ emitRestoreRegisters(save);
+ }
+ }
+ }
+
return result;
}
@@ -336,6 +433,65 @@
}
@Override
+ public Value emitLoadObjectAddress(Constant constant) {
+ HotSpotObjectConstant objectConstant = (HotSpotObjectConstant) constant;
+ LIRKind kind = objectConstant.isCompressed() ? getLIRKindTool().getNarrowOopKind() : getLIRKindTool().getObjectKind();
+ Variable result = newVariable(kind);
+ append(new AArch64HotSpotLoadAddressOp(result, constant, HotSpotConstantLoadAction.RESOLVE));
+ return result;
+ }
+
+ @Override
+ public Value emitLoadMetaspaceAddress(Constant constant, HotSpotConstantLoadAction action) {
+ HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) constant;
+ LIRKind kind = metaspaceConstant.isCompressed() ? getLIRKindTool().getNarrowPointerKind() : getLIRKindTool().getWordKind();
+ Variable result = newVariable(kind);
+ append(new AArch64HotSpotLoadAddressOp(result, constant, action));
+ return result;
+ }
+
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, Object[] notes, Constant[] constants, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+ ForeignCallLinkage linkage = getForeignCalls().lookupForeignCall(foreignCall);
+ append(new AArch64HotSpotConstantRetrievalOp(constants, constantDescriptions, frameState, linkage, notes));
+ AllocatableValue result = linkage.getOutgoingCallingConvention().getReturn();
+ return emitMove(result);
+ }
+
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, AllocatableValue[] constantDescriptions, LIRFrameState frameState) {
+ Constant[] constants = new Constant[]{constant};
+ Object[] notes = new Object[]{action};
+ return emitConstantRetrieval(foreignCall, notes, constants, constantDescriptions, frameState);
+ }
+
+ @Override
+ public Value emitResolveDynamicInvoke(Constant appendix, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[0];
+ return emitConstantRetrieval(RESOLVE_DYNAMIC_INVOKE, INITIALIZE, appendix, constantDescriptions, frameState);
+ }
+
+ @Override
+ public Value emitLoadConfigValue(int markId, LIRKind kind) {
+ Variable result = newVariable(kind);
+ append(new AArch64HotSpotLoadConfigValueOp(markId, result));
+ return result;
+ }
+
+ private Value emitConstantRetrieval(ForeignCallDescriptor foreignCall, HotSpotConstantLoadAction action, Constant constant, Value constantDescription, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(constantDescription)};
+ return emitConstantRetrieval(foreignCall, action, constant, constantDescriptions, frameState);
+ }
+
+ @Override
+ public Value emitObjectConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+ return emitConstantRetrieval(RESOLVE_STRING_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+ }
+
+ @Override
+ public Value emitMetaspaceConstantRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+ return emitConstantRetrieval(RESOLVE_KLASS_BY_SYMBOL, RESOLVE, constant, constantDescription, frameState);
+ }
+
+ @Override
public void emitReturn(JavaKind kind, Value input) {
AllocatableValue operand = Value.ILLEGAL;
if (input != null) {
@@ -346,6 +502,17 @@
append(new AArch64HotSpotReturnOp(operand, getStub() != null, config, thread));
}
+ @Override
+ public Value emitKlassInitializationAndRetrieval(Constant constant, Value constantDescription, LIRFrameState frameState) {
+ return emitConstantRetrieval(INITIALIZE_KLASS_BY_SYMBOL, INITIALIZE, constant, constantDescription, frameState);
+ }
+
+ @Override
+ public Value emitResolveMethodAndLoadCounters(Constant method, Value klassHint, Value methodDescription, LIRFrameState frameState) {
+ AllocatableValue[] constantDescriptions = new AllocatableValue[]{asAllocatable(klassHint), asAllocatable(methodDescription)};
+ return emitConstantRetrieval(RESOLVE_METHOD_BY_SYMBOL_AND_LOAD_COUNTERS, LOAD_COUNTERS, method, constantDescriptions, frameState);
+ }
+
/**
* Gets the {@link Stub} this generator is generating code for or {@code null} if a stub is not
* being generated.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadAddressOp.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+import jdk.vm.ci.meta.Constant;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotLoadAddressOp extends AArch64LIRInstruction {
+
+ public static final LIRInstructionClass<AArch64HotSpotLoadAddressOp> TYPE = LIRInstructionClass.create(AArch64HotSpotLoadAddressOp.class);
+
+ @Def({OperandFlag.REG}) protected AllocatableValue result;
+ private final Constant constant;
+ private final Object note;
+
+ public AArch64HotSpotLoadAddressOp(AllocatableValue result, Constant constant, Object note) {
+ super(TYPE);
+ this.result = result;
+ this.constant = constant;
+ this.note = note;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ crb.recordInlineDataInCodeWithNote(constant, note);
+ AArch64Kind kind = (AArch64Kind) result.getPlatformKind();
+ int size = 0;
+ switch (kind) {
+ case DWORD:
+ size = 32;
+ break;
+ case QWORD:
+ size = 64;
+ break;
+ default:
+ throw GraalError.shouldNotReachHere("unexpected kind: " + kind);
+ }
+ if (crb.compilationResult.isImmutablePIC()) {
+ Register dst = asRegister(result);
+ masm.addressOf(dst);
+ masm.ldr(size, dst, AArch64Address.createBaseRegisterOnlyAddress(dst));
+ } else {
+ masm.ldr(size, asRegister(result), masm.getPlaceholder(-1));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoadConfigValueOp.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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.aarch64;
+
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
+import static jdk.vm.ci.code.ValueUtil.asRegister;
+
+import jdk.vm.ci.aarch64.AArch64Kind;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.meta.AllocatableValue;
+
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+public final class AArch64HotSpotLoadConfigValueOp extends AArch64LIRInstruction {
+
+ public static final LIRInstructionClass<AArch64HotSpotLoadConfigValueOp> TYPE = LIRInstructionClass.create(AArch64HotSpotLoadConfigValueOp.class);
+
+ @Def({OperandFlag.REG}) protected AllocatableValue result;
+ private final int markId;
+
+ public AArch64HotSpotLoadConfigValueOp(int markId, AllocatableValue result) {
+ super(TYPE);
+ this.result = result;
+ this.markId = markId;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ if (GeneratePIC.getValue(crb.getOptions())) {
+ AArch64Kind kind = (AArch64Kind) result.getPlatformKind();
+ Register reg = asRegister(result);
+ masm.adrp(reg);
+ masm.add(64, reg, reg, 1);
+ switch (kind) {
+ case BYTE:
+ masm.ldrs(8, 32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+ break;
+ case WORD:
+ masm.ldrs(16, 32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+ break;
+ case DWORD:
+ masm.ldr(32, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+ break;
+ case QWORD:
+ masm.ldr(64, reg, AArch64Address.createBaseRegisterOnlyAddress(reg));
+ break;
+ default:
+ throw GraalError.unimplemented();
+ }
+ masm.nop();
+ } else {
+ throw GraalError.unimplemented();
+ }
+ crb.recordMark(markId);
+ }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotLoweringProvider.java Thu May 31 10:38:05 2018 -0700
@@ -26,13 +26,13 @@
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
-import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
import org.graalvm.compiler.nodes.calc.FloatConvertNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
import org.graalvm.compiler.nodes.calc.RemNode;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.options.OptionValues;
@@ -62,8 +62,8 @@
@Override
public void lower(Node n, LoweringTool tool) {
- if (n instanceof FixedBinaryNode) {
- integerArithmeticSnippets.lower((FixedBinaryNode) n, tool);
+ if (n instanceof IntegerDivRemNode) {
+ integerArithmeticSnippets.lower((IntegerDivRemNode) n, tool);
} else if (n instanceof RemNode) {
floatArithmeticSnippets.lower((RemNode) n, tool);
} else if (n instanceof FloatConvertNode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotMove.java Thu May 31 10:38:05 2018 -0700
@@ -25,15 +25,19 @@
import static jdk.vm.ci.aarch64.AArch64.zr;
import static jdk.vm.ci.code.ValueUtil.asRegister;
import static jdk.vm.ci.code.ValueUtil.isRegister;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
import org.graalvm.compiler.asm.Label;
+import org.graalvm.compiler.asm.aarch64.AArch64Address;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.core.common.CompressEncoding;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.lir.LIRInstruction;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.StandardOp.LoadConstantOp;
import org.graalvm.compiler.lir.aarch64.AArch64LIRInstruction;
@@ -80,6 +84,32 @@
}
}
+ public static final class BaseMove extends AArch64LIRInstruction {
+ public static final LIRInstructionClass<BaseMove> TYPE = LIRInstructionClass.create(BaseMove.class);
+
+ @LIRInstruction.Def({REG, HINT}) protected AllocatableValue result;
+ private final GraalHotSpotVMConfig config;
+
+ public BaseMove(AllocatableValue result, GraalHotSpotVMConfig config) {
+ super(TYPE);
+ this.result = result;
+ this.config = config;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ try (AArch64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ masm.adrp(scratch);
+ masm.add(64, scratch, scratch, 1);
+ masm.ldr(64, asRegister(result), AArch64Address.createBaseRegisterOnlyAddress(scratch));
+ masm.nop();
+ crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+ }
+ }
+
+ }
+
/**
* Compresses a 8-byte pointer as a 4-byte int.
*/
@@ -117,7 +147,7 @@
} else if (nonNull) {
masm.sub(64, resultRegister, ptr, base);
if (encoding.hasShift()) {
- masm.shl(64, resultRegister, resultRegister, encoding.getShift());
+ masm.lshr(64, resultRegister, resultRegister, encoding.getShift());
}
} else {
// if ptr is null it still has to be null after compression
@@ -192,11 +222,21 @@
// masm.cmov(64, result, result, ARMv8.zr, ARMv8Assembler.ConditionFlag.NE);
// }
- public static void decodeKlassPointer(AArch64MacroAssembler masm, Register result, Register ptr, Register klassBase, CompressEncoding encoding) {
- // result = klassBase + ptr << shift
- if (encoding.hasShift() || encoding.hasBase()) {
- masm.add(64, result, klassBase, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+ public static void decodeKlassPointer(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, Register ptr, CompressEncoding encoding, GraalHotSpotVMConfig config) {
+ try (AArch64MacroAssembler.ScratchRegister sc = masm.getScratchRegister()) {
+ Register scratch = sc.getRegister();
+ boolean pic = GeneratePIC.getValue(crb.getOptions());
+ if (pic || encoding.hasBase() || encoding.getShift() != 0) {
+ if (pic) {
+ masm.addressOf(scratch);
+ masm.ldr(64, scratch, AArch64Address.createBaseRegisterOnlyAddress(scratch));
+ masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+ crb.recordMark(config.MARKID_NARROW_KLASS_BASE_ADDRESS);
+ } else {
+ masm.mov(scratch, encoding.getBase());
+ masm.add(64, result, scratch, ptr, AArch64Assembler.ExtendType.UXTX, encoding.getShift());
+ }
+ }
}
}
-
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotLIRGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -236,7 +236,7 @@
}
@Override
- public Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
+ public Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue) {
ValueKind<?> kind = newValue.getValueKind();
assert kind.equals(expectedValue.getValueKind());
SPARCKind memKind = (SPARCKind) kind.getPlatformKind();
@@ -246,7 +246,7 @@
}
@Override
- public Variable emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue) {
+ public Variable emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue) {
ValueKind<?> kind = newValue.getValueKind();
assert kind.equals(expectedValue.getValueKind());
Variable result = newVariable(newValue.getValueKind());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java Thu May 31 10:38:05 2018 -0700
@@ -422,6 +422,12 @@
"jdk/internal/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I");
}
+ if (isJDK11OrHigher()) {
+ // Relevant for Java flight recorder
+ add(TO_BE_INVESTIGATED,
+ "jdk/jfr/internal/JVM.getEventWriter()Ljava/lang/Object;");
+ }
+
if (!getHostArchitectureName().equals("amd64")) {
// Can we implement these on non-AMD64 platforms? C2 seems to.
add(TO_BE_INVESTIGATED,
@@ -549,6 +555,10 @@
return GraalServices.JAVA_SPECIFICATION_VERSION >= 10;
}
+ private static boolean isJDK11OrHigher() {
+ return GraalServices.JAVA_SPECIFICATION_VERSION >= 11;
+ }
+
private static String getHostArchitectureName() {
String arch = System.getProperty("os.arch");
if (arch.equals("x86_64")) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompilationWrapperTest.java Thu May 31 10:38:05 2018 -0700
@@ -223,25 +223,19 @@
Assert.assertTrue(zip.toString(), zip.exists());
Assert.assertTrue(zip + " not in " + dumpPathEntries, dumpPathEntries.contains(zip.getName()));
try {
- int bgv = 0;
- int cfg = 0;
+ int bgvOrCfgFiles = 0;
ZipFile dd = new ZipFile(diagnosticOutputZip);
List<String> entries = new ArrayList<>();
for (Enumeration<? extends ZipEntry> e = dd.entries(); e.hasMoreElements();) {
ZipEntry ze = e.nextElement();
String name = ze.getName();
entries.add(name);
- if (name.endsWith(".bgv")) {
- bgv++;
- } else if (name.endsWith(".cfg")) {
- cfg++;
+ if (name.endsWith(".bgv") || name.endsWith(".cfg")) {
+ bgvOrCfgFiles++;
}
}
- if (bgv == 0) {
- Assert.fail(String.format("Expected at least one .bgv file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
- }
- if (cfg == 0) {
- Assert.fail(String.format("Expected at least one .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
+ if (bgvOrCfgFiles == 0) {
+ Assert.fail(String.format("Expected at least one .bgv or .cfg file in %s: %s%n%s", diagnosticOutputZip, entries, proc));
}
} finally {
zip.delete();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/aaa Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-/*
- * 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.hotspot.nodes.aot.InitializeKlassNode;
-import org.graalvm.compiler.java.GraphBuilderPhase;
-import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
-import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
-import org.graalvm.compiler.phases.PhaseSuite;
-import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-import jdk.vm.ci.meta.ConstantPool;
-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 X_initialized = false;
-
- static class X {
- static {
- X_initialized = true;
- }
- static void foo() {}
- }
-
- public static void invokeStatic() {
- X.foo();
- }
-
- private void test(String name) {
- ResolvedJavaMethod method = getResolvedJavaMethod(name);
- Assume.assumeTrue("skipping for old JVMCI", classInitPlugin.supportsLazyInitialization(method.getConstantPool()));
- StructuredGraph graph = parseEager(method, AllowAssumptions.NO);
- Assert.assertFalse(X_initialized);
- }
-
- @Test
- public void test1() {
- test("invokeStatic");
- }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java Thu May 31 10:38:05 2018 -0700
@@ -101,6 +101,13 @@
return new DefaultBackendMap(name);
}
+ /**
+ * Returns a name that should uniquely identify this compiler configuration.
+ */
+ public final String getName() {
+ return name;
+ }
+
public interface BackendMap {
HotSpotBackendFactory getBackendFactory(Architecture arch);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfig.java Thu May 31 10:38:05 2018 -0700
@@ -80,6 +80,9 @@
public final boolean foldStableValues = getFlag("FoldStableValues", Boolean.class);
public final int maxVectorSize = getFlag("MaxVectorSize", Integer.class);
+ public final boolean verifyBeforeGC = getFlag("VerifyBeforeGC", Boolean.class);
+ public final boolean verifyAfterGC = getFlag("VerifyAfterGC", Boolean.class);
+
public final boolean useTLAB = getFlag("UseTLAB", Boolean.class);
public final boolean useBiasedLocking = getFlag("UseBiasedLocking", Boolean.class);
public final boolean usePopCountInstruction = getFlag("UsePopCountInstruction", Boolean.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/GraalHotSpotVMConfigVersioned.java Thu May 31 10:38:05 2018 -0700
@@ -40,12 +40,12 @@
super(store);
}
+ // JSK-8132287
+ final boolean inlineNotify = !getFlag("SyncKnobs", String.class, "").contains("InlineNotify=0");
+
// JDK-8073583
final boolean useCRC32CIntrinsics = getFlag("UseCRC32CIntrinsics", Boolean.class);
- // JDK-8075171
- final boolean inlineNotify = getFlag("InlineNotify", Boolean.class, true);
-
// JDK-8046936
final int javaThreadReservedStackActivationOffset = getFieldOffset("JavaThread::_reserved_stack_activation", Integer.class, "address");
final int methodFlagsOffset = getFieldOffset("Method::_flags", Integer.class, "u2");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalCompiler.java Thu May 31 10:38:05 2018 -0700
@@ -185,7 +185,7 @@
result.setEntryBCI(entryBCI);
boolean shouldDebugNonSafepoints = providers.getCodeCache().shouldDebugNonSafepoints();
PhaseSuite<HighTierContext> graphBuilderSuite = configGraphBuilderSuite(providers.getSuites().getDefaultGraphBuilderSuite(), shouldDebugNonSafepoints, isOSR);
- GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf);
+ GraalCompiler.compileGraph(graph, method, providers, backend, graphBuilderSuite, optimisticOpts, profilingInfo, suites, lirSuites, result, crbf, true);
if (!isOSR && useProfilingInfo) {
ProfilingInfo profile = profilingInfo;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java Thu May 31 10:38:05 2018 -0700
@@ -105,6 +105,7 @@
}
private final String runtimeName;
+ private final String compilerConfigurationName;
private final HotSpotBackend hostBackend;
private final GlobalMetrics metricValues = new GlobalMetrics();
private final List<SnippetCounter.Group> snippetCounterGroups;
@@ -155,6 +156,7 @@
compilationProblemsPerAction = new EnumMap<>(ExceptionAction.class);
snippetCounterGroups = GraalOptions.SnippetCounters.getValue(options) ? new ArrayList<>() : null;
CompilerConfiguration compilerConfiguration = compilerConfigurationFactory.createCompilerConfiguration();
+ compilerConfigurationName = compilerConfigurationFactory.getName();
compiler = new HotSpotGraalCompiler(jvmciRuntime, this, options);
management = GraalServices.loadSingle(HotSpotGraalManagementRegistration.class, false);
@@ -296,6 +298,11 @@
return backends.get(arch);
}
+ @Override
+ public String getCompilerConfigurationName() {
+ return compilerConfigurationName;
+ }
+
private long runtimeStartTime;
private boolean shutdown;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntimeProvider.java Thu May 31 10:38:05 2018 -0700
@@ -94,4 +94,10 @@
* Gets the map used to count compilation problems at each {@link ExceptionAction} level.
*/
Map<ExceptionAction, Integer> getCompilationProblemsPerAction();
+
+ /**
+ * Returns the unique compiler configuration name that is in use. Useful for users to find out
+ * which configuration is in use.
+ */
+ String getCompilerConfigurationName();
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/DefaultHotSpotLoweringProvider.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,7 @@
import static jdk.internal.vm.compiler.word.LocationIdentity.any;
import java.lang.ref.Reference;
+import java.util.EnumMap;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.core.common.CompressEncoding;
@@ -49,6 +50,7 @@
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.StampPair;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
@@ -91,8 +93,8 @@
import org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets;
import org.graalvm.compiler.hotspot.replacements.aot.ResolveConstantSnippets;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyNode;
+import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopyWithSlowPathNode;
-import org.graalvm.compiler.hotspot.replacements.arraycopy.ArrayCopySnippets;
import org.graalvm.compiler.hotspot.replacements.profiling.ProfileSnippets;
import org.graalvm.compiler.hotspot.word.KlassPointer;
import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -118,6 +120,7 @@
import org.graalvm.compiler.nodes.debug.StringToBytesNode;
import org.graalvm.compiler.nodes.debug.VerifyHeapNode;
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.nodes.extended.GetClassNode;
import org.graalvm.compiler.nodes.extended.GuardedUnsafeLoadNode;
@@ -207,7 +210,7 @@
instanceofSnippets = new InstanceOfSnippets.Templates(options, factories, runtime, providers, target);
newObjectSnippets = new NewObjectSnippets.Templates(options, factories, runtime, providers, target, config);
monitorSnippets = new MonitorSnippets.Templates(options, factories, runtime, providers, target, config.useFastLocking);
- writeBarrierSnippets = new WriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config.useCompressedOops ? config.getOopEncoding() : null);
+ writeBarrierSnippets = new WriteBarrierSnippets.Templates(options, factories, runtime, providers, target, config);
exceptionObjectSnippets = new LoadExceptionObjectSnippets.Templates(options, factories, providers, target);
unsafeLoadSnippets = new UnsafeLoadSnippets.Templates(options, factories, providers, target);
assertionSnippets = new AssertionSnippets.Templates(options, factories, providers, target);
@@ -223,162 +226,165 @@
}
@Override
+ @SuppressWarnings("try")
public void lower(Node n, LoweringTool tool) {
StructuredGraph graph = (StructuredGraph) n.graph();
- if (n instanceof Invoke) {
- lowerInvoke((Invoke) n, tool, graph);
- } else if (n instanceof LoadMethodNode) {
- lowerLoadMethodNode((LoadMethodNode) n);
- } else if (n instanceof GetClassNode) {
- lowerGetClassNode((GetClassNode) n, tool, graph);
- } else if (n instanceof StoreHubNode) {
- lowerStoreHubNode((StoreHubNode) n, graph);
- } else if (n instanceof OSRStartNode) {
- lowerOSRStartNode((OSRStartNode) n);
- } else if (n instanceof BytecodeExceptionNode) {
- lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
- } else if (n instanceof InstanceOfNode) {
- InstanceOfNode instanceOfNode = (InstanceOfNode) n;
- if (graph.getGuardsStage().areDeoptsFixed()) {
- instanceofSnippets.lower(instanceOfNode, tool);
- } else {
- if (instanceOfNode.allowsNull()) {
- ValueNode object = instanceOfNode.getValue();
- LogicNode newTypeCheck = graph.addOrUniqueWithInputs(InstanceOfNode.create(instanceOfNode.type(), object, instanceOfNode.profile(), instanceOfNode.getAnchor()));
- LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
- instanceOfNode.replaceAndDelete(newNode);
+ try (DebugCloseable context = n.withNodeSourcePosition()) {
+ if (n instanceof Invoke) {
+ lowerInvoke((Invoke) n, tool, graph);
+ } else if (n instanceof LoadMethodNode) {
+ lowerLoadMethodNode((LoadMethodNode) n);
+ } else if (n instanceof GetClassNode) {
+ lowerGetClassNode((GetClassNode) n, tool, graph);
+ } else if (n instanceof StoreHubNode) {
+ lowerStoreHubNode((StoreHubNode) n, graph);
+ } else if (n instanceof OSRStartNode) {
+ lowerOSRStartNode((OSRStartNode) n);
+ } else if (n instanceof BytecodeExceptionNode) {
+ lowerBytecodeExceptionNode((BytecodeExceptionNode) n);
+ } else if (n instanceof InstanceOfNode) {
+ InstanceOfNode instanceOfNode = (InstanceOfNode) n;
+ if (graph.getGuardsStage().areDeoptsFixed()) {
+ instanceofSnippets.lower(instanceOfNode, tool);
+ } else {
+ if (instanceOfNode.allowsNull()) {
+ ValueNode object = instanceOfNode.getValue();
+ LogicNode newTypeCheck = graph.addOrUniqueWithInputs(InstanceOfNode.create(instanceOfNode.type(), object, instanceOfNode.profile(), instanceOfNode.getAnchor()));
+ LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
+ instanceOfNode.replaceAndDelete(newNode);
+ }
}
- }
- } else if (n instanceof InstanceOfDynamicNode) {
- InstanceOfDynamicNode instanceOfDynamicNode = (InstanceOfDynamicNode) n;
- if (graph.getGuardsStage().areDeoptsFixed()) {
- instanceofSnippets.lower(instanceOfDynamicNode, tool);
- } else {
- ValueNode mirror = instanceOfDynamicNode.getMirrorOrHub();
- if (mirror.stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Object) {
- ClassGetHubNode classGetHub = graph.unique(new ClassGetHubNode(mirror));
- instanceOfDynamicNode.setMirror(classGetHub);
- }
+ } else if (n instanceof InstanceOfDynamicNode) {
+ InstanceOfDynamicNode instanceOfDynamicNode = (InstanceOfDynamicNode) n;
+ if (graph.getGuardsStage().areDeoptsFixed()) {
+ instanceofSnippets.lower(instanceOfDynamicNode, tool);
+ } else {
+ ValueNode mirror = instanceOfDynamicNode.getMirrorOrHub();
+ if (mirror.stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Object) {
+ ClassGetHubNode classGetHub = graph.unique(new ClassGetHubNode(mirror));
+ instanceOfDynamicNode.setMirror(classGetHub);
+ }
- if (instanceOfDynamicNode.allowsNull()) {
- ValueNode object = instanceOfDynamicNode.getObject();
- LogicNode newTypeCheck = graph.addOrUniqueWithInputs(
- InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), instanceOfDynamicNode.getMirrorOrHub(), object, false));
- LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
- instanceOfDynamicNode.replaceAndDelete(newNode);
+ if (instanceOfDynamicNode.allowsNull()) {
+ ValueNode object = instanceOfDynamicNode.getObject();
+ LogicNode newTypeCheck = graph.addOrUniqueWithInputs(
+ InstanceOfDynamicNode.create(graph.getAssumptions(), tool.getConstantReflection(), instanceOfDynamicNode.getMirrorOrHub(), object, false));
+ LogicNode newNode = LogicNode.or(graph.unique(IsNullNode.create(object)), newTypeCheck, GraalDirectives.UNLIKELY_PROBABILITY);
+ instanceOfDynamicNode.replaceAndDelete(newNode);
+ }
+ }
+ } else if (n instanceof ClassIsAssignableFromNode) {
+ if (graph.getGuardsStage().areDeoptsFixed()) {
+ instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
+ }
+ } else if (n instanceof NewInstanceNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
+ }
+ } else if (n instanceof DynamicNewInstanceNode) {
+ DynamicNewInstanceNode newInstanceNode = (DynamicNewInstanceNode) n;
+ if (newInstanceNode.getClassClass() == null) {
+ JavaConstant classClassMirror = constantReflection.forObject(Class.class);
+ ConstantNode classClass = ConstantNode.forConstant(classClassMirror, tool.getMetaAccess(), graph);
+ newInstanceNode.setClassClass(classClass);
+ }
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower(newInstanceNode, registers, tool);
+ }
+ } else if (n instanceof NewArrayNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower((NewArrayNode) n, registers, tool);
+ }
+ } else if (n instanceof DynamicNewArrayNode) {
+ DynamicNewArrayNode dynamicNewArrayNode = (DynamicNewArrayNode) n;
+ if (dynamicNewArrayNode.getVoidClass() == null) {
+ JavaConstant voidClassMirror = constantReflection.forObject(void.class);
+ ConstantNode voidClass = ConstantNode.forConstant(voidClassMirror, tool.getMetaAccess(), graph);
+ dynamicNewArrayNode.setVoidClass(voidClass);
+ }
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower(dynamicNewArrayNode, registers, tool);
+ }
+ } else if (n instanceof VerifyHeapNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower((VerifyHeapNode) n, registers, tool);
+ }
+ } else if (n instanceof RawMonitorEnterNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ monitorSnippets.lower((RawMonitorEnterNode) n, registers, tool);
+ }
+ } else if (n instanceof MonitorExitNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ monitorSnippets.lower((MonitorExitNode) n, registers, tool);
}
- }
- } else if (n instanceof ClassIsAssignableFromNode) {
- if (graph.getGuardsStage().areDeoptsFixed()) {
- instanceofSnippets.lower((ClassIsAssignableFromNode) n, tool);
- }
- } else if (n instanceof NewInstanceNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower((NewInstanceNode) n, registers, tool);
- }
- } else if (n instanceof DynamicNewInstanceNode) {
- DynamicNewInstanceNode newInstanceNode = (DynamicNewInstanceNode) n;
- if (newInstanceNode.getClassClass() == null) {
- JavaConstant classClassMirror = constantReflection.forObject(Class.class);
- ConstantNode classClass = ConstantNode.forConstant(classClassMirror, tool.getMetaAccess(), graph);
- newInstanceNode.setClassClass(classClass);
- }
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower(newInstanceNode, registers, tool);
- }
- } else if (n instanceof NewArrayNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower((NewArrayNode) n, registers, tool);
- }
- } else if (n instanceof DynamicNewArrayNode) {
- DynamicNewArrayNode dynamicNewArrayNode = (DynamicNewArrayNode) n;
- if (dynamicNewArrayNode.getVoidClass() == null) {
- JavaConstant voidClassMirror = constantReflection.forObject(void.class);
- ConstantNode voidClass = ConstantNode.forConstant(voidClassMirror, tool.getMetaAccess(), graph);
- dynamicNewArrayNode.setVoidClass(voidClass);
- }
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower(dynamicNewArrayNode, registers, tool);
+ } else if (n instanceof ArrayCopyNode) {
+ arraycopySnippets.lower((ArrayCopyNode) n, tool);
+ } else if (n instanceof ArrayCopyWithSlowPathNode) {
+ arraycopySnippets.lower((ArrayCopyWithSlowPathNode) n, tool);
+ } else if (n instanceof G1PreWriteBarrier) {
+ writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
+ } else if (n instanceof G1PostWriteBarrier) {
+ writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
+ } else if (n instanceof G1ReferentFieldReadBarrier) {
+ writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
+ } else if (n instanceof SerialWriteBarrier) {
+ writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
+ } else if (n instanceof SerialArrayRangeWriteBarrier) {
+ writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
+ } else if (n instanceof G1ArrayRangePreWriteBarrier) {
+ writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
+ } else if (n instanceof G1ArrayRangePostWriteBarrier) {
+ writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
+ } else if (n instanceof NewMultiArrayNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ newObjectSnippets.lower((NewMultiArrayNode) n, tool);
+ }
+ } else if (n instanceof LoadExceptionObjectNode) {
+ exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
+ } else if (n instanceof AssertionNode) {
+ assertionSnippets.lower((AssertionNode) n, tool);
+ } else if (n instanceof StringToBytesNode) {
+ if (graph.getGuardsStage().areDeoptsFixed()) {
+ stringToBytesSnippets.lower((StringToBytesNode) n, tool);
+ }
+ } else if (n instanceof IntegerDivRemNode) {
+ // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
+ // zero and the MIN_VALUE / -1 cases.
+ } else if (n instanceof AbstractDeoptimizeNode || n instanceof UnwindNode || n instanceof RemNode || n instanceof SafepointNode) {
+ /* No lowering, we generate LIR directly for these nodes. */
+ } else if (n instanceof ClassGetHubNode) {
+ lowerClassGetHubNode((ClassGetHubNode) n, tool);
+ } else if (n instanceof HubGetClassNode) {
+ lowerHubGetClassNode((HubGetClassNode) n, tool);
+ } else if (n instanceof KlassLayoutHelperNode) {
+ lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool);
+ } else if (n instanceof ComputeObjectAddressNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ lowerComputeObjectAddressNode((ComputeObjectAddressNode) n);
+ }
+ } else if (n instanceof IdentityHashCodeNode) {
+ hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
+ } else if (n instanceof ResolveDynamicConstantNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool);
+ }
+ } else if (n instanceof ResolveConstantNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
+ }
+ } else if (n instanceof ResolveMethodAndLoadCountersNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool);
+ }
+ } else if (n instanceof InitializeKlassNode) {
+ if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
+ resolveConstantSnippets.lower((InitializeKlassNode) n, tool);
+ }
+ } else if (n instanceof ProfileNode) {
+ profileSnippets.lower((ProfileNode) n, tool);
+ } else {
+ super.lower(n, tool);
}
- } else if (n instanceof VerifyHeapNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower((VerifyHeapNode) n, registers, tool);
- }
- } else if (n instanceof RawMonitorEnterNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- monitorSnippets.lower((RawMonitorEnterNode) n, registers, tool);
- }
- } else if (n instanceof MonitorExitNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- monitorSnippets.lower((MonitorExitNode) n, registers, tool);
- }
- } else if (n instanceof ArrayCopyNode) {
- arraycopySnippets.lower((ArrayCopyNode) n, tool);
- } else if (n instanceof ArrayCopyWithSlowPathNode) {
- arraycopySnippets.lower((ArrayCopyWithSlowPathNode) n, tool);
- } else if (n instanceof G1PreWriteBarrier) {
- writeBarrierSnippets.lower((G1PreWriteBarrier) n, registers, tool);
- } else if (n instanceof G1PostWriteBarrier) {
- writeBarrierSnippets.lower((G1PostWriteBarrier) n, registers, tool);
- } else if (n instanceof G1ReferentFieldReadBarrier) {
- writeBarrierSnippets.lower((G1ReferentFieldReadBarrier) n, registers, tool);
- } else if (n instanceof SerialWriteBarrier) {
- writeBarrierSnippets.lower((SerialWriteBarrier) n, tool);
- } else if (n instanceof SerialArrayRangeWriteBarrier) {
- writeBarrierSnippets.lower((SerialArrayRangeWriteBarrier) n, tool);
- } else if (n instanceof G1ArrayRangePreWriteBarrier) {
- writeBarrierSnippets.lower((G1ArrayRangePreWriteBarrier) n, registers, tool);
- } else if (n instanceof G1ArrayRangePostWriteBarrier) {
- writeBarrierSnippets.lower((G1ArrayRangePostWriteBarrier) n, registers, tool);
- } else if (n instanceof NewMultiArrayNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- newObjectSnippets.lower((NewMultiArrayNode) n, tool);
- }
- } else if (n instanceof LoadExceptionObjectNode) {
- exceptionObjectSnippets.lower((LoadExceptionObjectNode) n, registers, tool);
- } else if (n instanceof AssertionNode) {
- assertionSnippets.lower((AssertionNode) n, tool);
- } else if (n instanceof StringToBytesNode) {
- if (graph.getGuardsStage().areDeoptsFixed()) {
- stringToBytesSnippets.lower((StringToBytesNode) n, tool);
- }
- } else if (n instanceof IntegerDivRemNode) {
- // Nothing to do for division nodes. The HotSpot signal handler catches divisions by
- // zero and the MIN_VALUE / -1 cases.
- } else if (n instanceof AbstractDeoptimizeNode || n instanceof UnwindNode || n instanceof RemNode || n instanceof SafepointNode) {
- /* No lowering, we generate LIR directly for these nodes. */
- } else if (n instanceof ClassGetHubNode) {
- lowerClassGetHubNode((ClassGetHubNode) n, tool);
- } else if (n instanceof HubGetClassNode) {
- lowerHubGetClassNode((HubGetClassNode) n, tool);
- } else if (n instanceof KlassLayoutHelperNode) {
- lowerKlassLayoutHelperNode((KlassLayoutHelperNode) n, tool);
- } else if (n instanceof ComputeObjectAddressNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- lowerComputeObjectAddressNode((ComputeObjectAddressNode) n);
- }
- } else if (n instanceof IdentityHashCodeNode) {
- hashCodeSnippets.lower((IdentityHashCodeNode) n, tool);
- } else if (n instanceof ResolveDynamicConstantNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- resolveConstantSnippets.lower((ResolveDynamicConstantNode) n, tool);
- }
- } else if (n instanceof ResolveConstantNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- resolveConstantSnippets.lower((ResolveConstantNode) n, tool);
- }
- } else if (n instanceof ResolveMethodAndLoadCountersNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- resolveConstantSnippets.lower((ResolveMethodAndLoadCountersNode) n, tool);
- }
- } else if (n instanceof InitializeKlassNode) {
- if (graph.getGuardsStage().areFrameStatesAtDeopts()) {
- resolveConstantSnippets.lower((InitializeKlassNode) n, tool);
- }
- } else if (n instanceof ProfileNode) {
- profileSnippets.lower((ProfileNode) n, tool);
- } else {
- super.lower(n, tool);
}
}
@@ -635,59 +641,53 @@
}
static final class Exceptions {
- protected static final ArrayIndexOutOfBoundsException cachedArrayIndexOutOfBoundsException;
- protected static final NullPointerException cachedNullPointerException;
+ protected static final EnumMap<BytecodeExceptionKind, RuntimeException> cachedExceptions;
static {
- cachedArrayIndexOutOfBoundsException = new ArrayIndexOutOfBoundsException();
- cachedArrayIndexOutOfBoundsException.setStackTrace(new StackTraceElement[0]);
- cachedNullPointerException = new NullPointerException();
- cachedNullPointerException.setStackTrace(new StackTraceElement[0]);
+ cachedExceptions = new EnumMap<>(BytecodeExceptionKind.class);
+ cachedExceptions.put(BytecodeExceptionKind.NULL_POINTER, clearStackTrace(new NullPointerException()));
+ cachedExceptions.put(BytecodeExceptionKind.OUT_OF_BOUNDS, clearStackTrace(new ArrayIndexOutOfBoundsException()));
+ cachedExceptions.put(BytecodeExceptionKind.CLASS_CAST, clearStackTrace(new ClassCastException()));
+ cachedExceptions.put(BytecodeExceptionKind.ARRAY_STORE, clearStackTrace(new ArrayStoreException()));
+ cachedExceptions.put(BytecodeExceptionKind.DIVISION_BY_ZERO, clearStackTrace(new ArithmeticException()));
+ }
+
+ private static RuntimeException clearStackTrace(RuntimeException ex) {
+ ex.setStackTrace(new StackTraceElement[0]);
+ return ex;
}
}
public static final class RuntimeCalls {
- public static final ForeignCallDescriptor CREATE_ARRAY_STORE_EXCEPTION = new ForeignCallDescriptor("createArrayStoreException", ArrayStoreException.class, Object.class);
- public static final ForeignCallDescriptor CREATE_CLASS_CAST_EXCEPTION = new ForeignCallDescriptor("createClassCastException", ClassCastException.class, Object.class, KlassPointer.class);
- public static final ForeignCallDescriptor CREATE_NULL_POINTER_EXCEPTION = new ForeignCallDescriptor("createNullPointerException", NullPointerException.class);
- public static final ForeignCallDescriptor CREATE_OUT_OF_BOUNDS_EXCEPTION = new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class);
+ public static final EnumMap<BytecodeExceptionKind, ForeignCallDescriptor> runtimeCalls;
+
+ static {
+ runtimeCalls = new EnumMap<>(BytecodeExceptionKind.class);
+ runtimeCalls.put(BytecodeExceptionKind.ARRAY_STORE, new ForeignCallDescriptor("createArrayStoreException", ArrayStoreException.class, Object.class));
+ runtimeCalls.put(BytecodeExceptionKind.CLASS_CAST, new ForeignCallDescriptor("createClassCastException", ClassCastException.class, Object.class, KlassPointer.class));
+ runtimeCalls.put(BytecodeExceptionKind.NULL_POINTER, new ForeignCallDescriptor("createNullPointerException", NullPointerException.class));
+ runtimeCalls.put(BytecodeExceptionKind.OUT_OF_BOUNDS, new ForeignCallDescriptor("createOutOfBoundsException", ArrayIndexOutOfBoundsException.class, int.class, int.class));
+ runtimeCalls.put(BytecodeExceptionKind.DIVISION_BY_ZERO, new ForeignCallDescriptor("createDivisionByZeroException", ArithmeticException.class));
+ }
}
- private boolean throwCachedException(BytecodeExceptionNode node) {
- Throwable exception;
- if (node.getExceptionClass() == NullPointerException.class) {
- exception = Exceptions.cachedNullPointerException;
- } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
- exception = Exceptions.cachedArrayIndexOutOfBoundsException;
- } else {
- return false;
- }
+ private void throwCachedException(BytecodeExceptionNode node) {
+ Throwable exception = Exceptions.cachedExceptions.get(node.getExceptionKind());
+ assert exception != null;
StructuredGraph graph = node.graph();
FloatingNode exceptionNode = ConstantNode.forConstant(constantReflection.forObject(exception), metaAccess, graph);
graph.replaceFixedWithFloating(node, exceptionNode);
- return true;
}
private void lowerBytecodeExceptionNode(BytecodeExceptionNode node) {
if (OmitHotExceptionStacktrace.getValue(node.getOptions())) {
- if (throwCachedException(node)) {
- return;
- }
+ throwCachedException(node);
+ return;
}
- ForeignCallDescriptor descriptor;
- if (node.getExceptionClass() == NullPointerException.class) {
- descriptor = RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
- } else if (node.getExceptionClass() == ArrayIndexOutOfBoundsException.class) {
- descriptor = RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
- } else if (node.getExceptionClass() == ArrayStoreException.class) {
- descriptor = RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION;
- } else if (node.getExceptionClass() == ClassCastException.class) {
- descriptor = RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION;
- } else {
- throw GraalError.shouldNotReachHere();
- }
+ ForeignCallDescriptor descriptor = RuntimeCalls.runtimeCalls.get(node.getExceptionKind());
+ assert descriptor != null;
StructuredGraph graph = node.graph();
ForeignCallNode foreignCallNode = graph.add(new ForeignCallNode(foreignCalls, descriptor, node.stamp(NodeView.DEFAULT), node.getArguments()));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java Thu May 31 10:38:05 2018 -0700
@@ -65,10 +65,6 @@
import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.Transition.STACK_INSPECTABLE_LEAF;
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.DEOPTIMIZATION_HANDLER;
import static org.graalvm.compiler.hotspot.HotSpotHostBackend.UNCOMMON_TRAP_HANDLER;
-import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_ARRAY_STORE_EXCEPTION;
-import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_CLASS_CAST_EXCEPTION;
-import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_NULL_POINTER_EXCEPTION;
-import static org.graalvm.compiler.hotspot.meta.DefaultHotSpotLoweringProvider.RuntimeCalls.CREATE_OUT_OF_BOUNDS_EXCEPTION;
import static org.graalvm.compiler.hotspot.replacements.AssertionSnippets.ASSERTION_VM_MESSAGE_C;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.MARK_WORD_LOCATION;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.TLAB_END_LOCATION;
@@ -112,6 +108,7 @@
import org.graalvm.compiler.hotspot.stubs.ArrayStoreExceptionStub;
import org.graalvm.compiler.hotspot.stubs.ClassCastExceptionStub;
import org.graalvm.compiler.hotspot.stubs.CreateExceptionStub;
+import org.graalvm.compiler.hotspot.stubs.DivisionByZeroExceptionStub;
import org.graalvm.compiler.hotspot.stubs.ExceptionHandlerStub;
import org.graalvm.compiler.hotspot.stubs.NewArrayStub;
import org.graalvm.compiler.hotspot.stubs.NewInstanceStub;
@@ -121,6 +118,7 @@
import org.graalvm.compiler.hotspot.stubs.UnwindExceptionToCallerStub;
import org.graalvm.compiler.hotspot.stubs.VerifyOopStub;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.word.Word;
import org.graalvm.compiler.word.WordTypes;
@@ -285,10 +283,13 @@
link(new ExceptionHandlerStub(options, providers, foreignCalls.get(EXCEPTION_HANDLER)));
link(new UnwindExceptionToCallerStub(options, providers, registerStubCall(UNWIND_EXCEPTION_TO_CALLER, NOT_REEXECUTABLE, SAFEPOINT, any())));
link(new VerifyOopStub(options, providers, registerStubCall(VERIFY_OOP, REEXECUTABLE, LEAF_NOFP, NO_LOCATIONS)));
- link(new ArrayStoreExceptionStub(options, providers, registerStubCall(CREATE_ARRAY_STORE_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
- link(new ClassCastExceptionStub(options, providers, registerStubCall(CREATE_CLASS_CAST_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
- link(new NullPointerExceptionStub(options, providers, registerStubCall(CREATE_NULL_POINTER_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
- link(new OutOfBoundsExceptionStub(options, providers, registerStubCall(CREATE_OUT_OF_BOUNDS_EXCEPTION, REEXECUTABLE, SAFEPOINT, any())));
+
+ EnumMap<BytecodeExceptionKind, ForeignCallDescriptor> exceptionRuntimeCalls = DefaultHotSpotLoweringProvider.RuntimeCalls.runtimeCalls;
+ link(new ArrayStoreExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.ARRAY_STORE), REEXECUTABLE, SAFEPOINT, any())));
+ link(new ClassCastExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.CLASS_CAST), REEXECUTABLE, SAFEPOINT, any())));
+ link(new NullPointerExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.NULL_POINTER), REEXECUTABLE, SAFEPOINT, any())));
+ link(new OutOfBoundsExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.OUT_OF_BOUNDS), REEXECUTABLE, SAFEPOINT, any())));
+ link(new DivisionByZeroExceptionStub(options, providers, registerStubCall(exceptionRuntimeCalls.get(BytecodeExceptionKind.DIVISION_BY_ZERO), REEXECUTABLE, SAFEPOINT, any())));
linkForeignCall(options, providers, IDENTITY_HASHCODE, c.identityHashCodeAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, MARK_WORD_LOCATION);
linkForeignCall(options, providers, REGISTER_FINALIZER, c.registerFinalizerAddress, PREPEND_THREAD, SAFEPOINT, NOT_REEXECUTABLE, any());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotNodePlugin.java Thu May 31 10:38:05 2018 -0700
@@ -27,6 +27,7 @@
import org.graalvm.compiler.core.common.type.StampPair;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
@@ -147,16 +148,16 @@
}
@Override
- public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
- if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, elementKind)) {
+ public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
+ if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, boundsCheck, elementKind)) {
return true;
}
return false;
}
@Override
- public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
- if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, elementKind, value)) {
+ public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) {
+ if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, boundsCheck, storeCheck, elementKind, value)) {
return true;
}
return false;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotWordOperationPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -45,6 +45,7 @@
import org.graalvm.compiler.nodes.calc.ConditionalNode;
import org.graalvm.compiler.nodes.calc.IsNullNode;
import org.graalvm.compiler.nodes.calc.PointerEqualsNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
@@ -69,13 +70,13 @@
}
@Override
- protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
+ protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck) {
ResolvedJavaType arrayType = StampTool.typeOrNull(array);
Stamp componentStamp = wordTypes.getWordStamp(arrayType.getComponentType());
if (componentStamp instanceof MetaspacePointerStamp) {
- return new LoadIndexedPointerNode(componentStamp, array, index);
+ return new LoadIndexedPointerNode(componentStamp, array, index, boundsCheck);
} else {
- return super.createLoadIndexedNode(array, index);
+ return super.createLoadIndexedNode(array, index, boundsCheck);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/LoadIndexedPointerNode.java Thu May 31 10:38:05 2018 -0700
@@ -26,6 +26,7 @@
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
import jdk.vm.ci.meta.JavaKind;
@@ -35,8 +36,8 @@
public static final NodeClass<LoadIndexedPointerNode> TYPE = NodeClass.create(LoadIndexedPointerNode.class);
- public LoadIndexedPointerNode(Stamp stamp, ValueNode array, ValueNode index) {
- super(TYPE, stamp, array, index, JavaKind.Illegal);
+ public LoadIndexedPointerNode(Stamp stamp, ValueNode array, ValueNode index, GuardingNode boundsCheck) {
+ super(TYPE, stamp, array, index, boundsCheck, JavaKind.Illegal);
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java Thu May 31 10:38:05 2018 -0700
@@ -121,6 +121,8 @@
boolean precise = barrierType == BarrierType.PRECISE;
if (config.useG1GC) {
if (!node.getLocationIdentity().isInit()) {
+ // The pre barrier does nothing if the value being read is null, so it can
+ // be explicitly skipped when this is an initializing store.
addG1PreWriteBarrier(node, node.getAddress(), null, true, node.getNullCheck(), graph);
}
addG1PostWriteBarrier(node, node.getAddress(), node.value(), precise, graph);
@@ -178,6 +180,8 @@
private void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) {
if (config.useG1GC) {
if (!write.isInitialization()) {
+ // The pre barrier does nothing if the value being read is null, so it can
+ // be explicitly skipped when this is an initializing store.
G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ObjectCloneNode.java Thu May 31 10:38:05 2018 -0700
@@ -40,10 +40,8 @@
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.nodes.java.NewInstanceNode;
import org.graalvm.compiler.nodes.java.StoreFieldNode;
-import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.LoweringTool;
import org.graalvm.compiler.nodes.spi.Replacements;
-import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
import org.graalvm.compiler.nodes.type.StampTool;
import org.graalvm.compiler.replacements.nodes.BasicObjectCloneNode;
@@ -53,7 +51,7 @@
import jdk.vm.ci.meta.ResolvedJavaType;
@NodeInfo
-public final class ObjectCloneNode extends BasicObjectCloneNode implements VirtualizableAllocation, ArrayLengthProvider {
+public final class ObjectCloneNode extends BasicObjectCloneNode {
public static final NodeClass<ObjectCloneNode> TYPE = NodeClass.create(ObjectCloneNode.class);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java Thu May 31 10:38:05 2018 -0700
@@ -51,6 +51,7 @@
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
import org.graalvm.compiler.hotspot.nodes.G1ArrayRangePostWriteBarrier;
@@ -65,6 +66,7 @@
import org.graalvm.compiler.hotspot.nodes.VMErrorNode;
import org.graalvm.compiler.nodes.NamedLocationIdentity;
import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.PiNode;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.FixedValueAnchorNode;
@@ -79,12 +81,14 @@
import org.graalvm.compiler.nodes.type.NarrowOopStamp;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.replacements.Log;
+import org.graalvm.compiler.replacements.ReplacementsUtil;
import org.graalvm.compiler.replacements.SnippetCounter;
import org.graalvm.compiler.replacements.SnippetCounter.Group;
import org.graalvm.compiler.replacements.SnippetTemplate.AbstractTemplates;
import org.graalvm.compiler.replacements.SnippetTemplate.Arguments;
import org.graalvm.compiler.replacements.SnippetTemplate.SnippetInfo;
import org.graalvm.compiler.replacements.Snippets;
+import org.graalvm.compiler.replacements.nodes.AssertionNode;
import org.graalvm.compiler.replacements.nodes.DirectStoreNode;
import org.graalvm.compiler.word.Word;
import jdk.internal.vm.compiler.word.LocationIdentity;
@@ -140,7 +144,10 @@
}
@Snippet
- public static void serialImpreciseWriteBarrier(Object object, @ConstantParameter Counters counters) {
+ public static void serialImpreciseWriteBarrier(Object object, @ConstantParameter boolean verifyBarrier, @ConstantParameter Counters counters) {
+ if (verifyBarrier) {
+ verifyNotArray(object);
+ }
serialWriteBarrier(Word.objectToTrackedPointer(object), counters);
}
@@ -221,8 +228,8 @@
}
@Snippet
- public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter Register threadRegister,
- @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
+ public static void g1PostWriteBarrier(Address address, Object object, Object value, @ConstantParameter boolean usePrecise, @ConstantParameter boolean verifyBarrier,
+ @ConstantParameter Register threadRegister, @ConstantParameter boolean trace, @ConstantParameter Counters counters) {
Word thread = registerAsWord(threadRegister);
Object fixedValue = FixedValueAnchorNode.getObject(value);
verifyOop(object);
@@ -232,6 +239,9 @@
if (usePrecise) {
oop = Word.fromAddress(address);
} else {
+ if (verifyBarrier) {
+ verifyNotArray(object);
+ }
oop = Word.objectToTrackedPointer(object);
}
int gcCycle = 0;
@@ -298,6 +308,13 @@
}
}
+ private static void verifyNotArray(Object object) {
+ if (object != null) {
+ // Manually build the null check and cast because we're in snippet that's lowered late.
+ AssertionNode.assertion(false, !PiNode.piCastNonNull(object, Object.class).getClass().isArray(), "imprecise card mark used with array");
+ }
+ }
+
@Snippet
public static void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
Word thread = registerAsWord(threadRegister);
@@ -415,11 +432,13 @@
private final CompressEncoding oopEncoding;
private final Counters counters;
+ private final boolean verifyBarrier;
- public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, HotSpotProviders providers, TargetDescription target,
- CompressEncoding oopEncoding) {
+ public Templates(OptionValues options, Iterable<DebugHandlersFactory> factories, Group.Factory factory, HotSpotProviders providers, TargetDescription target,
+ GraalHotSpotVMConfig config) {
super(options, factories, providers, providers.getSnippetReflection(), target);
- this.oopEncoding = oopEncoding;
+ this.oopEncoding = config.useCompressedOops ? config.getOopEncoding() : null;
+ this.verifyBarrier = ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED || config.verifyBeforeGC || config.verifyAfterGC;
this.counters = new Counters(factory);
}
@@ -432,6 +451,7 @@
args = new Arguments(serialImpreciseWriteBarrier, writeBarrier.graph().getGuardsStage(), tool.getLoweringStage());
OffsetAddressNode address = (OffsetAddressNode) writeBarrier.getAddress();
args.add("object", address.getBase());
+ args.addConst("verifyBarrier", verifyBarrier);
}
args.addConst("counters", counters);
template(writeBarrier, args).instantiate(providers.getMetaAccess(), writeBarrier, DEFAULT_REPLACER, args);
@@ -519,6 +539,7 @@
args.add("value", value);
args.addConst("usePrecise", writeBarrierPost.usePrecise());
+ args.addConst("verifyBarrier", verifyBarrier);
args.addConst("threadRegister", registers.getThreadRegister());
args.addConst("trace", traceBarrier(writeBarrierPost.graph()));
args.addConst("counters", counters);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/DivisionByZeroExceptionStub.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,55 @@
+/*
+ * 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.hotspot.stubs;
+
+import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
+import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
+import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.replacements.nodes.CStringConstant;
+import org.graalvm.compiler.word.Word;
+
+import jdk.vm.ci.code.Register;
+
+/**
+ * Stub to allocate an {@link ArithmeticException} thrown by a bytecode for a division by zero.
+ */
+public class DivisionByZeroExceptionStub extends CreateExceptionStub {
+ public DivisionByZeroExceptionStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
+ super("createDivisionByZeroException", options, providers, linkage);
+ }
+
+ @Override
+ protected Object getConstantParameterValue(int index, String name) {
+ GraalError.guarantee(index == 0, "unknown parameter %s at index %d", name, index);
+ return providers.getRegisters().getThreadRegister();
+ }
+
+ @Snippet
+ private static Object createDivisionByZeroException(@ConstantParameter Register threadRegister) {
+ Word msg = CStringConstant.cstring("/ by zero");
+ return createException(threadRegister, ArithmeticException.class, msg);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/OutOfBoundsExceptionStub.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,9 @@
*/
package org.graalvm.compiler.hotspot.stubs;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printNumber;
+import static org.graalvm.compiler.hotspot.stubs.StubUtil.printString;
+
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.debug.GraalError;
@@ -29,6 +32,7 @@
import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
import org.graalvm.compiler.hotspot.nodes.AllocaNode;
import org.graalvm.compiler.options.OptionValues;
+import org.graalvm.compiler.serviceprovider.GraalServices;
import org.graalvm.compiler.word.Word;
import jdk.vm.ci.code.Register;
@@ -37,51 +41,52 @@
* Stub to allocate an {@link ArrayIndexOutOfBoundsException} thrown by a bytecode.
*/
public class OutOfBoundsExceptionStub extends CreateExceptionStub {
-
public OutOfBoundsExceptionStub(OptionValues options, HotSpotProviders providers, HotSpotForeignCallLinkage linkage) {
super("createOutOfBoundsException", options, providers, linkage);
}
+ // JDK-8201593: Print array length in ArrayIndexOutOfBoundsException.
+ private static final boolean PRINT_LENGTH_IN_EXCEPTION = GraalServices.JAVA_SPECIFICATION_VERSION >= 11;
private static final int MAX_INT_STRING_SIZE = Integer.toString(Integer.MIN_VALUE).length();
+ private static final String STR_INDEX = "Index ";
+ private static final String STR_OUTOFBOUNDSFORLENGTH = " out of bounds for length ";
@Override
protected Object getConstantParameterValue(int index, String name) {
switch (index) {
- case 1:
+ case 2:
return providers.getRegisters().getThreadRegister();
- case 2:
+ case 3:
int wordSize = providers.getWordTypes().getWordKind().getByteCount();
- // (MAX_INT_STRING_SIZE + 1) / wordSize, rounded up
- return MAX_INT_STRING_SIZE / wordSize + 1;
+ int bytes;
+ if (PRINT_LENGTH_IN_EXCEPTION) {
+ bytes = STR_INDEX.length() + STR_OUTOFBOUNDSFORLENGTH.length() + 2 * MAX_INT_STRING_SIZE;
+ } else {
+ bytes = MAX_INT_STRING_SIZE;
+ }
+ // (required words for maximum length + nullbyte), rounded up
+ return (bytes + 1) / wordSize + 1;
+ case 4:
+ return PRINT_LENGTH_IN_EXCEPTION;
default:
throw GraalError.shouldNotReachHere("unknown parameter " + name + " at index " + index);
}
}
@Snippet
- private static Object createOutOfBoundsException(int idx, @ConstantParameter Register threadRegister, @ConstantParameter int bufferSizeInWords) {
+ private static Object createOutOfBoundsException(int idx, int length, @ConstantParameter Register threadRegister, @ConstantParameter int bufferSizeInWords,
+ @ConstantParameter boolean printLengthInException) {
Word buffer = AllocaNode.alloca(bufferSizeInWords);
-
- long number = idx;
- if (number < 0) {
- number = -number;
+ Word ptr;
+ if (printLengthInException) {
+ ptr = printString(buffer, STR_INDEX);
+ ptr = printNumber(ptr, idx);
+ ptr = printString(ptr, STR_OUTOFBOUNDSFORLENGTH);
+ ptr = printNumber(ptr, length);
+ } else {
+ ptr = printNumber(buffer, idx);
}
-
- Word ptr = buffer.add(MAX_INT_STRING_SIZE);
ptr.writeByte(0, (byte) 0);
- do {
- long digit = number % 10;
- number /= 10;
-
- ptr = ptr.subtract(1);
- ptr.writeByte(0, (byte) ('0' + digit));
- } while (number > 0);
-
- if (idx < 0) {
- ptr = ptr.subtract(1);
- ptr.writeByte(0, (byte) '-');
- }
-
- return createException(threadRegister, ArrayIndexOutOfBoundsException.class, ptr);
+ return createException(threadRegister, ArrayIndexOutOfBoundsException.class, buffer);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/StubUtil.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
package org.graalvm.compiler.hotspot.stubs;
import static jdk.vm.ci.meta.DeoptimizationReason.RuntimeConstraint;
-import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfigBase.INJECTED_VMCONFIG;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.clearPendingException;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.getAndClearObjectResult;
import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadHubIntrinsic;
@@ -272,4 +272,59 @@
static int hubOffset(@InjectedParameter GraalHotSpotVMConfig config) {
return config.hubOffset;
}
+
+ /**
+ * Print {@code number} as decimal string to {@code buffer}.
+ *
+ * @param buffer
+ * @param number
+ * @return A pointer pointing one byte right after the last printed digit in {@code buffer}.
+ */
+ public static Word printNumber(Word buffer, long number) {
+ long tmpNumber = number;
+ int offset;
+ if (tmpNumber <= 0) {
+ tmpNumber = -tmpNumber;
+ offset = 1;
+ } else {
+ offset = 0;
+ }
+ while (tmpNumber > 0) {
+ tmpNumber /= 10;
+ offset++;
+ }
+ tmpNumber = number < 0 ? -number : number;
+ Word ptr = buffer.add(offset);
+ do {
+ long digit = tmpNumber % 10;
+ tmpNumber /= 10;
+ ptr = ptr.subtract(1);
+ ptr.writeByte(0, (byte) ('0' + digit));
+ } while (tmpNumber > 0);
+
+ if (number < 0) {
+ ptr = ptr.subtract(1);
+ ptr.writeByte(0, (byte) '-');
+ }
+ return buffer.add(offset);
+ }
+
+ /**
+ * Copy {@code javaString} bytes to the memory location {@code ptr}.
+ *
+ * @param buffer
+ * @param javaString
+ * @return A pointer pointing one byte right after the last byte copied from {@code javaString}
+ * to {@code ptr}
+ */
+ public static Word printString(Word buffer, String javaString) {
+ Word string = cstring(javaString);
+ int i = 0;
+ byte b;
+ while ((b = string.readByte(i)) != 0) {
+ buffer.writeByte(i, b);
+ i++;
+ }
+ return buffer.add(i);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java Thu May 31 10:38:05 2018 -0700
@@ -31,6 +31,7 @@
import static org.graalvm.compiler.bytecode.Bytecodes.BASTORE;
import static org.graalvm.compiler.bytecode.Bytecodes.CALOAD;
import static org.graalvm.compiler.bytecode.Bytecodes.CASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.CHECKCAST;
import static org.graalvm.compiler.bytecode.Bytecodes.DALOAD;
import static org.graalvm.compiler.bytecode.Bytecodes.DASTORE;
import static org.graalvm.compiler.bytecode.Bytecodes.DRETURN;
@@ -43,6 +44,7 @@
import static org.graalvm.compiler.bytecode.Bytecodes.GOTO_W;
import static org.graalvm.compiler.bytecode.Bytecodes.IALOAD;
import static org.graalvm.compiler.bytecode.Bytecodes.IASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.IDIV;
import static org.graalvm.compiler.bytecode.Bytecodes.IFEQ;
import static org.graalvm.compiler.bytecode.Bytecodes.IFGE;
import static org.graalvm.compiler.bytecode.Bytecodes.IFGT;
@@ -64,12 +66,15 @@
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESPECIAL;
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKESTATIC;
import static org.graalvm.compiler.bytecode.Bytecodes.INVOKEVIRTUAL;
+import static org.graalvm.compiler.bytecode.Bytecodes.IREM;
import static org.graalvm.compiler.bytecode.Bytecodes.IRETURN;
import static org.graalvm.compiler.bytecode.Bytecodes.JSR;
import static org.graalvm.compiler.bytecode.Bytecodes.JSR_W;
import static org.graalvm.compiler.bytecode.Bytecodes.LALOAD;
import static org.graalvm.compiler.bytecode.Bytecodes.LASTORE;
+import static org.graalvm.compiler.bytecode.Bytecodes.LDIV;
import static org.graalvm.compiler.bytecode.Bytecodes.LOOKUPSWITCH;
+import static org.graalvm.compiler.bytecode.Bytecodes.LREM;
import static org.graalvm.compiler.bytecode.Bytecodes.LRETURN;
import static org.graalvm.compiler.bytecode.Bytecodes.PUTFIELD;
import static org.graalvm.compiler.bytecode.Bytecodes.PUTSTATIC;
@@ -650,6 +655,10 @@
}
break;
}
+ case IDIV:
+ case IREM:
+ case LDIV:
+ case LREM:
case IASTORE:
case LASTORE:
case FASTORE:
@@ -667,6 +676,7 @@
case CALOAD:
case SALOAD:
case ARRAYLENGTH:
+ case CHECKCAST:
case PUTSTATIC:
case GETSTATIC:
case PUTFIELD:
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 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
@@ -377,7 +377,10 @@
import org.graalvm.compiler.nodes.extended.AnchoringNode;
import org.graalvm.compiler.nodes.extended.BranchProbabilityNode;
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode;
import org.graalvm.compiler.nodes.extended.LoadHubNode;
import org.graalvm.compiler.nodes.extended.LoadMethodNode;
import org.graalvm.compiler.nodes.extended.MembarNode;
@@ -398,6 +401,7 @@
import org.graalvm.compiler.nodes.java.ArrayLengthNode;
import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
import org.graalvm.compiler.nodes.java.FinalFieldBarrierNode;
+import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
import org.graalvm.compiler.nodes.java.InstanceOfNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
@@ -423,6 +427,7 @@
import jdk.vm.ci.code.BytecodeFrame;
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.code.site.InfopointReason;
+import jdk.vm.ci.meta.Constant;
import jdk.vm.ci.meta.ConstantPool;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.DeoptimizationAction;
@@ -1133,12 +1138,12 @@
finishedDispatch.setNext(target);
}
- protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, JavaKind kind) {
- return LoadIndexedNode.create(graph.getAssumptions(), array, index, kind, metaAccess, constantReflection);
- }
-
- protected void genStoreIndexed(ValueNode array, ValueNode index, JavaKind kind, ValueNode value) {
- add(new StoreIndexedNode(array, index, kind, value));
+ protected ValueNode genLoadIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind kind) {
+ return LoadIndexedNode.create(graph.getAssumptions(), array, index, boundsCheck, kind, metaAccess, constantReflection);
+ }
+
+ protected void genStoreIndexed(ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind kind, ValueNode value) {
+ add(new StoreIndexedNode(array, index, boundsCheck, storeCheck, kind, value));
}
protected ValueNode genIntegerAdd(ValueNode x, ValueNode y) {
@@ -1173,12 +1178,12 @@
return RemNode.create(x, y, NodeView.DEFAULT);
}
- protected ValueNode genIntegerDiv(ValueNode x, ValueNode y) {
- return SignedDivNode.create(x, y, NodeView.DEFAULT);
- }
-
- protected ValueNode genIntegerRem(ValueNode x, ValueNode y) {
- return SignedRemNode.create(x, y, NodeView.DEFAULT);
+ protected ValueNode genIntegerDiv(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ return SignedDivNode.create(x, y, zeroCheck, NodeView.DEFAULT);
+ }
+
+ protected ValueNode genIntegerRem(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ return SignedRemNode.create(x, y, zeroCheck, NodeView.DEFAULT);
}
protected ValueNode genNegateOp(ValueNode x) {
@@ -1267,10 +1272,12 @@
protected void genThrow() {
genInfoPointNode(InfopointReason.BYTECODE_POSITION, null);
- ValueNode exception = frameState.pop(JavaKind.Object);
- FixedGuardNode nullCheck = append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
- ValueNode nonNullException = graph.maybeAddOrUnique(PiNode.create(exception, exception.stamp(NodeView.DEFAULT).join(objectNonNull()), nullCheck));
- lastInstr.setNext(handleException(nonNullException, bci(), false));
+ ValueNode exception = maybeEmitExplicitNullCheck(frameState.pop(JavaKind.Object));
+ if (!StampTool.isPointerNonNull(exception.stamp(NodeView.DEFAULT))) {
+ FixedGuardNode nullCheck = append(new FixedGuardNode(graph.addOrUniqueWithInputs(IsNullNode.create(exception)), NullCheckException, InvalidateReprofile, true));
+ exception = graph.maybeAddOrUnique(PiNode.create(exception, exception.stamp(NodeView.DEFAULT).join(objectNonNull()), nullCheck));
+ }
+ lastInstr.setNext(handleException(exception, bci(), false));
}
protected LogicNode createInstanceOf(TypeReference type, ValueNode object) {
@@ -1324,30 +1331,61 @@
return new StateSplitProxyNode(fieldRead);
}
- protected ValueNode emitExplicitNullCheck(ValueNode receiver) {
- if (StampTool.isPointerNonNull(receiver.stamp(NodeView.DEFAULT))) {
+ protected ValueNode maybeEmitExplicitNullCheck(ValueNode receiver) {
+ if (StampTool.isPointerNonNull(receiver.stamp(NodeView.DEFAULT)) || !needsExplicitNullCheckException(receiver)) {
return receiver;
}
- BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, NullPointerException.class));
- AbstractBeginNode falseSucc = graph.add(new BeginNode());
- ValueNode nonNullReceiver = graph.addOrUniqueWithInputs(PiNode.create(receiver, objectNonNull(), falseSucc));
- append(new IfNode(graph.addOrUniqueWithInputs(IsNullNode.create(receiver)), exception, falseSucc, SLOW_PATH_PROBABILITY));
- lastInstr = falseSucc;
+ LogicNode condition = genUnique(IsNullNode.create(receiver));
+ AbstractBeginNode passingSuccessor = emitBytecodeExceptionCheck(condition, false, BytecodeExceptionKind.NULL_POINTER);
+ return genUnique(PiNode.create(receiver, objectNonNull(), passingSuccessor));
+ }
+
+ protected GuardingNode maybeEmitExplicitBoundsCheck(ValueNode receiver, ValueNode index) {
+ if (!needsExplicitBoundsCheckException(receiver, index)) {
+ return null;
+ }
+ ValueNode length = append(genArrayLength(receiver));
+ LogicNode condition = genUnique(IntegerBelowNode.create(constantReflection, metaAccess, options, null, index, length, NodeView.DEFAULT));
+ return emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.OUT_OF_BOUNDS, index, length);
+ }
+
+ protected GuardingNode maybeEmitExplicitStoreCheck(ValueNode array, JavaKind elementKind, ValueNode value) {
+ if (elementKind != JavaKind.Object || StampTool.isPointerAlwaysNull(value) || !needsExplicitStoreCheckException(array, value)) {
+ return null;
+ }
+ ValueNode arrayClass = genUnique(LoadHubNode.create(array, stampProvider, metaAccess, constantReflection));
+ ValueNode componentHub = append(LoadArrayComponentHubNode.create(arrayClass, stampProvider, metaAccess, constantReflection));
+ LogicNode condition = genUnique(InstanceOfDynamicNode.create(graph.getAssumptions(), getConstantReflection(), componentHub, value, true));
+ return emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.ARRAY_STORE, value);
+ }
+
+ protected GuardingNode maybeEmitExplicitDivisionByZeroCheck(ValueNode y) {
+ if (!((IntegerStamp) y.stamp(NodeView.DEFAULT)).contains(0) || !needsExplicitDivisionByZeroException(y)) {
+ return null;
+ }
+ ConstantNode zero = ConstantNode.defaultForKind(y.getStackKind(), graph);
+ LogicNode condition = genUnique(IntegerEqualsNode.create(constantReflection, metaAccess, options, null, y, zero, NodeView.DEFAULT));
+ return emitBytecodeExceptionCheck(condition, false, BytecodeExceptionKind.DIVISION_BY_ZERO);
+ }
+
+ private AbstractBeginNode emitBytecodeExceptionCheck(LogicNode condition, boolean passingOnTrue, BytecodeExceptionKind exceptionKind, ValueNode... arguments) {
+ if (passingOnTrue ? condition.isTautology() : condition.isContradiction()) {
+ return null;
+ }
+
+ BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, exceptionKind, arguments));
+ AbstractBeginNode passingSuccessor = graph.add(new BeginNode());
+
+ FixedNode trueSuccessor = passingOnTrue ? passingSuccessor : exception;
+ FixedNode falseSuccessor = passingOnTrue ? exception : passingSuccessor;
+ append(new IfNode(condition, trueSuccessor, falseSuccessor, SLOW_PATH_PROBABILITY));
+ lastInstr = passingSuccessor;
exception.setStateAfter(createFrameState(bci(), exception));
exception.setNext(handleException(exception, bci(), false));
EXPLICIT_EXCEPTIONS.increment(debug);
- return nonNullReceiver;
- }
-
- protected void emitExplicitBoundsCheck(ValueNode index, ValueNode length) {
- AbstractBeginNode trueSucc = graph.add(new BeginNode());
- BytecodeExceptionNode exception = graph.add(new BytecodeExceptionNode(metaAccess, ArrayIndexOutOfBoundsException.class, index));
- append(new IfNode(genUnique(IntegerBelowNode.create(constantReflection, metaAccess, options, null, index, length, NodeView.DEFAULT)), trueSucc, exception, FAST_PATH_PROBABILITY));
- lastInstr = trueSucc;
-
- exception.setStateAfter(createFrameState(bci(), exception));
- exception.setNext(handleException(exception, bci(), false));
+
+ return passingSuccessor;
}
protected ValueNode genArrayLength(ValueNode x) {
@@ -1617,7 +1655,7 @@
returnType = returnType.resolve(targetMethod.getDeclaringClass());
}
if (invokeKind.hasReceiver()) {
- args[0] = emitExplicitExceptions(args[0]);
+ args[0] = maybeEmitExplicitNullCheck(args[0]);
}
if (initialInvokeKind == InvokeKind.Special && !targetMethod.isConstructor()) {
@@ -1910,8 +1948,8 @@
/**
* Weaves a test of the receiver type to ensure the dispatch will select {@code targetMethod}
- * and not another method that overrides it. This should only be called if there is an intrinsic
- * (i.e., an {@link InvocationPlugin}) for {@code targetMethod} and the invocation is indirect.
+ * and not another method that overrides it. This should only be called if there is an
+ * {@link InvocationPlugin} for {@code targetMethod} and the invocation is indirect.
*
* The control flow woven around the intrinsic is as follows:
*
@@ -2066,9 +2104,7 @@
if (plugin != null) {
if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) {
- // Self recursive intrinsic means the original
- // method should be called.
- assert !targetMethod.hasBytecodes() : "TODO: when does this happen?";
+ // Self recursive intrinsic means the original method should be called.
return false;
}
@@ -2088,7 +2124,7 @@
try (DebugCloseable context = openNodeContext(targetMethod)) {
if (plugin.execute(this, targetMethod, pluginReceiver, args)) {
afterInvocationPluginExecution(true, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
- return true;
+ return !plugin.isDecorator();
} else {
afterInvocationPluginExecution(false, assertions, intrinsicGuard, invokeKind, args, targetMethod, resultType, returnType);
}
@@ -2911,75 +2947,87 @@
}
}
+ @SuppressWarnings("try")
private void createUnwind() {
assert frameState.stackSize() == 1 : frameState;
synchronizedEpilogue(BytecodeFrame.AFTER_EXCEPTION_BCI, null, null);
- ValueNode exception = frameState.pop(JavaKind.Object);
- append(new UnwindNode(exception));
- }
-
+ try (DebugCloseable context = openNodeContext(frameState, BytecodeFrame.UNWIND_BCI)) {
+ ValueNode exception = frameState.pop(JavaKind.Object);
+ append(new UnwindNode(exception));
+ }
+ }
+
+ @SuppressWarnings("try")
private void synchronizedEpilogue(int bci, ValueNode currentReturnValue, JavaKind currentReturnValueKind) {
- if (method.isSynchronized()) {
- if (currentReturnValue != null) {
- frameState.push(currentReturnValueKind, currentReturnValue);
+ try (DebugCloseable context = openNodeContext(frameState, bci)) {
+ if (method.isSynchronized()) {
+ if (currentReturnValue != null) {
+ frameState.push(currentReturnValueKind, currentReturnValue);
+ }
+ genMonitorExit(methodSynchronizedObject, currentReturnValue, bci);
+ assert !frameState.rethrowException();
+ finishPrepare(lastInstr, bci);
}
- genMonitorExit(methodSynchronizedObject, currentReturnValue, bci);
- assert !frameState.rethrowException();
- finishPrepare(lastInstr, bci);
- }
- if (frameState.lockDepth(false) != 0) {
- throw bailout("unbalanced monitors: too few exits exiting frame");
- }
- }
-
+ if (frameState.lockDepth(false) != 0) {
+ throw bailout("unbalanced monitors: too few exits exiting frame");
+ }
+ }
+ }
+
+ @SuppressWarnings("try")
private void createExceptionDispatch(ExceptionDispatchBlock block) {
- lastInstr = finishInstruction(lastInstr, frameState);
-
- assert frameState.stackSize() == 1 : frameState;
- if (block.handler.isCatchAll()) {
- assert block.getSuccessorCount() == 1;
- appendGoto(block.getSuccessor(0));
- return;
- }
-
- JavaType catchType = block.handler.getCatchType();
- if (graphBuilderConfig.eagerResolving()) {
- catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF);
- }
- if (catchType instanceof ResolvedJavaType) {
- TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType);
-
- if (graphBuilderConfig.getSkippedExceptionTypes() != null) {
- for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
- if (skippedType.isAssignableFrom(checkedCatchType.getType())) {
- BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
- ValueNode exception = frameState.stack[0];
- FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
- FixedNode nextDispatch = createTarget(nextBlock, frameState);
- append(new IfNode(graph.addOrUniqueWithInputs(createInstanceOf(checkedCatchType, exception)), trueSuccessor, nextDispatch, 0));
- return;
+ try (DebugCloseable context = openNodeContext(frameState, BytecodeFrame.AFTER_EXCEPTION_BCI)) {
+ lastInstr = finishInstruction(lastInstr, frameState);
+
+ assert frameState.stackSize() == 1 : frameState;
+ if (block.handler.isCatchAll()) {
+ assert block.getSuccessorCount() == 1;
+ appendGoto(block.getSuccessor(0));
+ return;
+ }
+
+ JavaType catchType = block.handler.getCatchType();
+ if (graphBuilderConfig.eagerResolving()) {
+ catchType = lookupType(block.handler.catchTypeCPI(), INSTANCEOF);
+ }
+ if (catchType instanceof ResolvedJavaType) {
+ TypeReference checkedCatchType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) catchType);
+
+ if (graphBuilderConfig.getSkippedExceptionTypes() != null) {
+ for (ResolvedJavaType skippedType : graphBuilderConfig.getSkippedExceptionTypes()) {
+ if (skippedType.isAssignableFrom(checkedCatchType.getType())) {
+ BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
+ ValueNode exception = frameState.stack[0];
+ FixedNode trueSuccessor = graph.add(new DeoptimizeNode(InvalidateReprofile, UnreachedCode));
+ FixedNode nextDispatch = createTarget(nextBlock, frameState);
+ append(new IfNode(graph.addOrUniqueWithInputs(createInstanceOf(checkedCatchType, exception)), trueSuccessor, nextDispatch, 0));
+ return;
+ }
}
}
+
+ BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
+ ValueNode exception = frameState.stack[0];
+ /*
+ * Anchor for the piNode, which must be before any LoopExit inserted by
+ * createTarget.
+ */
+ BeginNode piNodeAnchor = graph.add(new BeginNode());
+ ObjectStamp checkedStamp = StampFactory.objectNonNull(checkedCatchType);
+ PiNode piNode = graph.addWithoutUnique(new PiNode(exception, checkedStamp));
+ frameState.pop(JavaKind.Object);
+ frameState.push(JavaKind.Object, piNode);
+ FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState);
+ frameState.pop(JavaKind.Object);
+ frameState.push(JavaKind.Object, exception);
+ FixedNode nextDispatch = createTarget(nextBlock, frameState);
+ piNodeAnchor.setNext(catchSuccessor);
+ IfNode ifNode = append(new IfNode(graph.unique(createInstanceOf(checkedCatchType, exception)), piNodeAnchor, nextDispatch, 0.5));
+ assert ifNode.trueSuccessor() == piNodeAnchor;
+ piNode.setGuard(ifNode.trueSuccessor());
+ } else {
+ handleUnresolvedExceptionType(catchType);
}
-
- BciBlock nextBlock = block.getSuccessorCount() == 1 ? blockMap.getUnwindBlock() : block.getSuccessor(1);
- ValueNode exception = frameState.stack[0];
- /* Anchor for the piNode, which must be before any LoopExit inserted by createTarget. */
- BeginNode piNodeAnchor = graph.add(new BeginNode());
- ObjectStamp checkedStamp = StampFactory.objectNonNull(checkedCatchType);
- PiNode piNode = graph.addWithoutUnique(new PiNode(exception, checkedStamp));
- frameState.pop(JavaKind.Object);
- frameState.push(JavaKind.Object, piNode);
- FixedNode catchSuccessor = createTarget(block.getSuccessor(0), frameState);
- frameState.pop(JavaKind.Object);
- frameState.push(JavaKind.Object, exception);
- FixedNode nextDispatch = createTarget(nextBlock, frameState);
- piNodeAnchor.setNext(catchSuccessor);
- IfNode ifNode = append(new IfNode(graph.unique(createInstanceOf(checkedCatchType, exception)), piNodeAnchor, nextDispatch, 0.5));
- assert ifNode.trueSuccessor() == piNodeAnchor;
- piNode.setGuard(ifNode.trueSuccessor());
- } else {
- handleUnresolvedExceptionType(catchType);
}
}
@@ -3220,22 +3268,22 @@
}
protected double getProfileProbability(boolean negate) {
- double probability;
if (profilingInfo == null) {
- probability = 0.5;
- } else {
- assert assertAtIfBytecode();
- probability = profilingInfo.getBranchTakenProbability(bci());
- if (probability < 0) {
- assert probability == -1 : "invalid probability";
- debug.log("missing probability in %s at bci %d", code, bci());
- probability = 0.5;
- } else {
- if (negate) {
- // the probability coming from profile is about the original condition
- probability = 1 - probability;
- }
- }
+ return 0.5;
+ }
+
+ assert assertAtIfBytecode();
+ double probability = profilingInfo.getBranchTakenProbability(bci());
+
+ if (probability < 0) {
+ assert probability == -1 : "invalid probability";
+ debug.log("missing probability in %s at bci %d", code, bci());
+ return 0.5;
+ }
+
+ if (negate && shouldComplementProbability()) {
+ // the probability coming from profile is about the original condition
+ probability = 1 - probability;
}
return probability;
}
@@ -3277,7 +3325,10 @@
BciBlock tmpBlock = trueBlock;
trueBlock = falseBlock;
falseBlock = tmpBlock;
- probability = 1 - probability;
+ if (shouldComplementProbability()) {
+ // the probability coming from profile is about the original condition
+ probability = 1 - probability;
+ }
condition = logicNegationNode.getValue();
}
@@ -3288,9 +3339,13 @@
condition = genUnique(condition);
}
+ NodeSourcePosition currentPosition = graph.currentNodeSourcePosition();
if (isNeverExecutedCode(probability)) {
if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != trueBlock.startBci) {
- append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true));
+ NodeSourcePosition survivingSuccessorPosition = graph.trackNodeSourcePosition()
+ ? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), falseBlock.startBci)
+ : null;
+ append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true, survivingSuccessorPosition));
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
profilingPlugin.profileGoto(this, method, bci(), falseBlock.startBci, stateBefore);
}
@@ -3299,7 +3354,10 @@
}
} else if (isNeverExecutedCode(1 - probability)) {
if (!graph.isOSR() || getParent() != null || graph.getEntryBCI() != falseBlock.startBci) {
- append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false));
+ NodeSourcePosition survivingSuccessorPosition = graph.trackNodeSourcePosition()
+ ? new NodeSourcePosition(currentPosition.getCaller(), currentPosition.getMethod(), trueBlock.startBci)
+ : null;
+ append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, false, survivingSuccessorPosition));
if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
profilingPlugin.profileGoto(this, method, bci(), trueBlock.startBci, stateBefore);
}
@@ -3333,6 +3391,14 @@
}
/**
+ * Hook for subclasses to decide whether the IfNode probability should be complemented during
+ * conversion to Graal IR.
+ */
+ protected boolean shouldComplementProbability() {
+ return true;
+ }
+
+ /**
* Hook for subclasses to generate custom nodes before an IfNode.
*/
@SuppressWarnings("unused")
@@ -3587,29 +3653,36 @@
private void genLoadIndexed(JavaKind kind) {
ValueNode index = frameState.pop(JavaKind.Int);
- ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index);
+ ValueNode array = frameState.pop(JavaKind.Object);
+
+ array = maybeEmitExplicitNullCheck(array);
+ GuardingNode boundsCheck = maybeEmitExplicitBoundsCheck(array, index);
for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
- if (plugin.handleLoadIndexed(this, array, index, kind)) {
+ if (plugin.handleLoadIndexed(this, array, index, boundsCheck, kind)) {
return;
}
}
- frameState.push(kind, append(genLoadIndexed(array, index, kind)));
+ frameState.push(kind, append(genLoadIndexed(array, index, boundsCheck, kind)));
}
private void genStoreIndexed(JavaKind kind) {
ValueNode value = frameState.pop(kind);
ValueNode index = frameState.pop(JavaKind.Int);
- ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object), index);
+ ValueNode array = frameState.pop(JavaKind.Object);
+
+ array = maybeEmitExplicitNullCheck(array);
+ GuardingNode boundsCheck = maybeEmitExplicitBoundsCheck(array, index);
+ GuardingNode storeCheck = maybeEmitExplicitStoreCheck(array, kind, value);
for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
- if (plugin.handleStoreIndexed(this, array, index, kind, value)) {
+ if (plugin.handleStoreIndexed(this, array, index, boundsCheck, storeCheck, kind, value)) {
return;
}
}
- genStoreIndexed(array, index, kind, value);
+ genStoreIndexed(array, index, boundsCheck, storeCheck, kind, value);
}
private void genArithmeticOp(JavaKind kind, int opcode) {
@@ -3658,15 +3731,18 @@
private void genIntegerDivOp(JavaKind kind, int opcode) {
ValueNode y = frameState.pop(kind);
ValueNode x = frameState.pop(kind);
+
+ GuardingNode zeroCheck = maybeEmitExplicitDivisionByZeroCheck(y);
+
ValueNode v;
switch (opcode) {
case IDIV:
case LDIV:
- v = genIntegerDiv(x, y);
+ v = genIntegerDiv(x, y, zeroCheck);
break;
case IREM:
case LREM:
- v = genIntegerRem(x, y);
+ v = genIntegerRem(x, y, zeroCheck);
break;
default:
throw shouldNotReachHere();
@@ -3871,7 +3947,8 @@
handleUnresolvedCheckCast(type, object);
return;
}
- TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), (ResolvedJavaType) type);
+ ResolvedJavaType resolvedType = (ResolvedJavaType) type;
+ TypeReference checkedType = TypeReference.createTrusted(graph.getAssumptions(), resolvedType);
JavaTypeProfile profile = getProfileForTypeCheck(checkedType);
for (NodePlugin plugin : graphBuilderConfig.getPlugins().getNodePlugins()) {
@@ -3903,8 +3980,16 @@
if (condition.isTautology()) {
castNode = object;
} else {
- FixedGuardNode fixedGuard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
- castNode = append(PiNode.create(object, StampFactory.object(checkedType, nonNull), fixedGuard));
+ GuardingNode guard;
+ if (needsExplicitClassCastException(object)) {
+ Constant hub = getConstantReflection().asObjectHub(resolvedType);
+ Stamp hubStamp = getStampProvider().createHubStamp(StampFactory.object(TypeReference.createExactTrusted(resolvedType)));
+ ConstantNode hubConstant = ConstantNode.forConstant(hubStamp, hub, getMetaAccess(), graph);
+ guard = emitBytecodeExceptionCheck(condition, true, BytecodeExceptionKind.CLASS_CAST, object, hubConstant);
+ } else {
+ guard = append(new FixedGuardNode(condition, DeoptimizationReason.ClassCastException, DeoptimizationAction.InvalidateReprofile, false));
+ }
+ castNode = append(PiNode.create(object, StampFactory.object(checkedType, nonNull), guard.asNode()));
}
}
frameState.push(JavaKind.Object, castNode);
@@ -4124,7 +4209,7 @@
}
private void genGetField(JavaField field, ValueNode receiverInput) {
- ValueNode receiver = emitExplicitExceptions(receiverInput);
+ ValueNode receiver = maybeEmitExplicitNullCheck(receiverInput);
if (field instanceof ResolvedJavaField) {
ResolvedJavaField resolvedField = (ResolvedJavaField) field;
genGetField(resolvedField, receiver);
@@ -4163,29 +4248,56 @@
}
/**
- * @param receiver the receiver of an object based operation
- * @param index the index of an array based operation that is to be tested for out of bounds.
- * This is null for a non-array operation.
- * @return the receiver value possibly modified to have a non-null stamp
+ * Returns true if an explicit null check should be emitted for the given object.
+ *
+ * @param object The object that is accessed.
+ */
+ protected boolean needsExplicitNullCheckException(ValueNode object) {
+ return needsExplicitException();
+ }
+
+ /**
+ * Returns true if an explicit null check should be emitted for the given object.
+ *
+ * @param array The array that is accessed.
+ * @param index The array index that is accessed.
+ */
+ protected boolean needsExplicitBoundsCheckException(ValueNode array, ValueNode index) {
+ return needsExplicitException();
+ }
+
+ /**
+ * Returns true if an explicit check for a {@link ClassCastException} should be emitted for the
+ * given object.
+ *
+ * @param object The object that is accessed.
*/
- protected ValueNode emitExplicitExceptions(ValueNode receiver, ValueNode index) {
- if (needsExplicitException()) {
- ValueNode nonNullReceiver = emitExplicitNullCheck(receiver);
- ValueNode length = append(genArrayLength(nonNullReceiver));
- emitExplicitBoundsCheck(index, length);
- return nonNullReceiver;
- }
- return receiver;
- }
-
- protected ValueNode emitExplicitExceptions(ValueNode receiver) {
- if (StampTool.isPointerNonNull(receiver) || !needsExplicitException()) {
- return receiver;
- } else {
- return emitExplicitNullCheck(receiver);
- }
- }
-
+ protected boolean needsExplicitClassCastException(ValueNode object) {
+ return needsExplicitException();
+ }
+
+ /**
+ * Returns true if an explicit null check should be emitted for the given object.
+ *
+ * @param array The array that is accessed.
+ * @param value The value that is stored into the array.
+ */
+ protected boolean needsExplicitStoreCheckException(ValueNode array, ValueNode value) {
+ return needsExplicitException();
+ }
+
+ /**
+ * Returns true if an explicit null check should be emitted for the given object.
+ *
+ * @param y The dividend.
+ */
+ protected boolean needsExplicitDivisionByZeroException(ValueNode y) {
+ return needsExplicitException();
+ }
+
+ /**
+ * Returns true if an explicit exception check should be emitted.
+ */
protected boolean needsExplicitException() {
BytecodeExceptionMode exceptionMode = graphBuilderConfig.getBytecodeExceptionMode();
if (exceptionMode == BytecodeExceptionMode.CheckAll || StressExplicitExceptionCode.getValue(options)) {
@@ -4206,7 +4318,8 @@
}
private void genPutField(JavaField field, ValueNode value) {
- ValueNode receiver = emitExplicitExceptions(frameState.pop(JavaKind.Object));
+ ValueNode receiver = maybeEmitExplicitNullCheck(frameState.pop(JavaKind.Object));
+
if (field instanceof ResolvedJavaField) {
ResolvedJavaField resolvedField = (ResolvedJavaField) field;
@@ -4703,7 +4816,7 @@
}
private void genArrayLength() {
- ValueNode array = emitExplicitExceptions(frameState.pop(JavaKind.Object));
+ ValueNode array = maybeEmitExplicitNullCheck(frameState.pop(JavaKind.Object));
frameState.push(JavaKind.Int, append(genArrayLength(array)));
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/jdk/UnsafeAllocateInstance01.java Thu May 31 10:38:05 2018 -0700
@@ -67,6 +67,7 @@
runTest("testInstance");
}
+ @Ignore("https://bugs.openjdk.java.net/browse/JDK-8153540")
@Test
public void run1() throws Throwable {
runTest("testClassForException", UnsafeAllocateInstance01[].class);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/CE_InstanceOf.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,114 @@
+/*
+ * 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.jtt.optimize;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.junit.Test;
+
+public class CE_InstanceOf extends JTTTest {
+
+ static class A {
+ }
+
+ static class B extends A {
+ }
+
+ static class C extends A {
+ }
+
+ public static A testRedundantCast(Object value) {
+ if (value != null && value.getClass() == A.class) {
+ return (A) value;
+ }
+ return null;
+ }
+
+ public static boolean testRedundantInstanceOf(Object value) {
+ if (value != null && value.getClass() == A.class) {
+ return (value instanceof A);
+ }
+ return false;
+ }
+
+ public static boolean testRedundantInstanceOf2(Object value) {
+ if (value.getClass() == A.class) {
+ return (value instanceof A);
+ }
+ return false;
+ }
+
+ public static boolean testNonRedundantInstanceOf(Object value) {
+ if (value instanceof A) {
+ return (value != null && value.getClass() == A.class);
+ }
+ return false;
+ }
+
+ public static Object testNonRedundantInstanceOf2(Object value) {
+ if (value != null && value.getClass() == Object[].class) {
+ return ((Object[]) value)[0];
+ }
+ return null;
+ }
+
+ private static final List<A> testArgs = Collections.unmodifiableList(Arrays.asList(new A(), new B(), null));
+
+ @Test
+ public void run0() throws Throwable {
+ for (A a : testArgs) {
+ runTest("testRedundantCast", a);
+ }
+ }
+
+ @Test
+ public void run1() throws Throwable {
+ for (A a : testArgs) {
+ runTest("testRedundantInstanceOf", a);
+ }
+ }
+
+ @Test
+ public void run2() throws Throwable {
+ for (A a : testArgs) {
+ runTest("testRedundantInstanceOf2", a);
+ }
+ }
+
+ @Test
+ public void run3() throws Throwable {
+ for (A a : testArgs) {
+ runTest("testNonRedundantInstanceOf", a);
+ }
+ }
+
+ @Test
+ public void run4() throws Throwable {
+ for (A a : testArgs) {
+ runTest("testNonRedundantInstanceOf2", a);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.jtt/src/org/graalvm/compiler/jtt/optimize/InstanceOf.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,74 @@
+/*
+ * 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.jtt.optimize;
+
+import org.graalvm.compiler.jtt.JTTTest;
+import org.graalvm.compiler.nodes.LogicNode;
+import org.graalvm.compiler.nodes.java.InstanceOfNode;
+import org.junit.Test;
+
+/**
+ * A few tests of expected simplifications by {@link InstanceOfNode#implies(boolean, LogicNode)}.
+ */
+public class InstanceOf extends JTTTest {
+
+ static class A {
+ }
+
+ static class B extends A {
+ }
+
+ static class C extends B {
+ }
+
+ public boolean testSnippet1(Object o) {
+ if (o instanceof B) {
+ if (o instanceof A) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean testSnippet2(Object o) {
+ if (o instanceof A) {
+ return true;
+ } else {
+ return o instanceof B;
+ }
+ }
+
+ @Test
+ public void test1() {
+ runTest("testSnippet1", new A());
+ runTest("testSnippet1", new B());
+ runTest("testSnippet1", new C());
+ }
+
+ @Test
+ public void test2() {
+ runTest("testSnippet2", new A());
+ runTest("testSnippet2", new B());
+ runTest("testSnippet2", new C());
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticLIRGeneratorTool.java Thu May 31 10:38:05 2018 -0700
@@ -37,5 +37,20 @@
Value emitCountTrailingZeros(Value value);
+ enum RoundingMode {
+ NEAREST(0),
+ DOWN(1),
+ UP(2),
+ TRUNCATE(3);
+
+ public final int encoding;
+
+ RoundingMode(int encoding) {
+ this.encoding = encoding;
+ }
+ }
+
+ Value emitRound(Value value, RoundingMode mode);
+
void emitCompareOp(AArch64Kind cmpKind, Variable left, Value right);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArithmeticOp.java Thu May 31 10:38:05 2018 -0700
@@ -74,6 +74,9 @@
FREM,
FNEG,
FABS,
+ FRINTM,
+ FRINTN,
+ FRINTP,
SQRT;
/**
@@ -133,6 +136,15 @@
case FABS:
masm.fabs(size, dst, src);
break;
+ case FRINTM:
+ masm.frintm(size, dst, src);
+ break;
+ case FRINTN:
+ masm.frintn(size, dst, src);
+ break;
+ case FRINTP:
+ masm.frintp(size, dst, src);
+ break;
case SQRT:
masm.fsqrt(size, dst, src);
break;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64AtomicMove.java Thu May 31 10:38:05 2018 -0700
@@ -26,13 +26,12 @@
import org.graalvm.compiler.asm.Label;
import org.graalvm.compiler.asm.aarch64.AArch64Assembler;
+import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ShiftType;
import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
import org.graalvm.compiler.lir.LIRInstructionClass;
import org.graalvm.compiler.lir.Opcode;
import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
-import jdk.vm.ci.aarch64.AArch64.CPUFeature;
-import jdk.vm.ci.aarch64.AArch64.Flag;
import jdk.vm.ci.aarch64.AArch64Kind;
import jdk.vm.ci.code.Register;
import jdk.vm.ci.meta.AllocatableValue;
@@ -76,15 +75,15 @@
Register address = asRegister(addressValue);
Register result = asRegister(resultValue);
Register newVal = asRegister(newValue);
- if (masm.supports(CPUFeature.LSE) || masm.isFlagSet(Flag.UseLSE)) {
+ if (AArch64LIRFlagsVersioned.useLSE(masm)) {
Register expected = asRegister(expectedValue);
masm.mov(size, result, expected);
- masm.cas(size, expected, newVal, address, true /*acquire*/, true /*release*/);
+ masm.cas(size, expected, newVal, address, true /* acquire */, true /* release */);
AArch64Compare.gpCompare(masm, resultValue, expectedValue);
} else {
- // We could avoid using a scratch register here, by reusing resultValue for the stlxr
- // success flag and issue a mov resultValue, expectedValue in case of success before
- // returning.
+ // We could avoid using a scratch register here, by reusing resultValue for the
+ // stlxr success flag and issue a mov resultValue, expectedValue in case of success
+ // before returning.
Register scratch = asRegister(scratchValue);
Label retry = new Label();
Label fail = new Label();
@@ -99,4 +98,59 @@
}
}
}
+
+ /**
+ * Load (Read) and Add instruction. Does the following atomically: <code>
+ * ATOMIC_READ_AND_ADD(addend, result, address):
+ * result = *address
+ * *address = result + addend
+ * return result
+ * </code>
+ */
+ @Opcode("ATOMIC_READ_AND_ADD")
+ public static final class AtomicReadAndAddOp extends AArch64LIRInstruction {
+ public static final LIRInstructionClass<AtomicReadAndAddOp> TYPE = LIRInstructionClass.create(AtomicReadAndAddOp.class);
+
+ private final AArch64Kind accessKind;
+
+ @Def protected AllocatableValue resultValue;
+ @Alive protected AllocatableValue addressValue;
+ @Alive protected Value deltaValue;
+ @Temp protected AllocatableValue scratchValue1;
+ @Temp protected AllocatableValue scratchValue2;
+
+ public AtomicReadAndAddOp(AArch64Kind kind, AllocatableValue result, AllocatableValue address, Value delta, AllocatableValue scratch1, AllocatableValue scratch2) {
+ super(TYPE);
+ this.accessKind = kind;
+ this.resultValue = result;
+ this.addressValue = address;
+ this.deltaValue = delta;
+ this.scratchValue1 = scratch1;
+ this.scratchValue2 = scratch2;
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ assert accessKind.isInteger();
+ final int size = accessKind.getSizeInBytes() * Byte.SIZE;
+
+ Register address = asRegister(addressValue);
+ Register delta = asRegister(deltaValue);
+ Register result = asRegister(resultValue);
+
+ if (AArch64LIRFlagsVersioned.useLSE(masm)) {
+ masm.ldadd(size, delta, result, address, true, true);
+ } else {
+ Register scratch1 = asRegister(scratchValue1);
+ Register scratch2 = asRegister(scratchValue2);
+ Label retry = new Label();
+ masm.bind(retry);
+ masm.ldaxr(size, result, address);
+ masm.add(size, scratch1, result, delta, ShiftType.LSL, 0);
+ masm.stlxr(size, scratch2, scratch1, address);
+ // if scratch2 == 0 then write successful, else retry
+ masm.cbnz(32, scratch2, retry);
+ }
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Call.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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
@@ -22,6 +23,7 @@
*/
package org.graalvm.compiler.lir.aarch64;
+import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
@@ -198,12 +200,16 @@
public static void directCall(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget, Register scratch, LIRFrameState info, Label label) {
int before = masm.position();
if (scratch != null) {
- /*
- * Offset might not fit into a 28-bit immediate, generate an indirect call with a 64-bit
- * immediate address which is fixed up by HotSpot.
- */
- masm.movNativeAddress(scratch, 0L);
- masm.blr(scratch);
+ if (GeneratePIC.getValue(crb.getOptions())) {
+ masm.bl(0);
+ } else {
+ /*
+ * Offset might not fit into a 28-bit immediate, generate an indirect call with a
+ * 64-bit immediate address which is fixed up by HotSpot.
+ */
+ masm.movNativeAddress(scratch, 0L);
+ masm.blr(scratch);
+ }
} else {
// Address is fixed up by HotSpot.
masm.bl(0);
@@ -230,8 +236,12 @@
public static void directJmp(CompilationResultBuilder crb, AArch64MacroAssembler masm, InvokeTarget callTarget) {
try (AArch64MacroAssembler.ScratchRegister scratch = masm.getScratchRegister()) {
int before = masm.position();
- masm.movNativeAddress(scratch.getRegister(), 0L);
- masm.jmp(scratch.getRegister());
+ if (GeneratePIC.getValue(crb.getOptions())) {
+ masm.jmp();
+ } else {
+ masm.movNativeAddress(scratch.getRegister(), 0L);
+ masm.jmp(scratch.getRegister());
+ }
int after = masm.position();
crb.recordDirectCall(before, after, callTarget, null);
masm.ensureUniquePC();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64LIRFlagsVersioned.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,34 @@
+/*
+ * 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.aarch64;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+
+import jdk.vm.ci.aarch64.AArch64.CPUFeature;
+import jdk.vm.ci.aarch64.AArch64.Flag;
+
+public class AArch64LIRFlagsVersioned {
+ public static boolean useLSE(AArch64MacroAssembler masm) {
+ return masm.supports(CPUFeature.LSE) || masm.isFlagSet(Flag.UseLSE);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64Move.java Thu May 31 10:38:05 2018 -0700
@@ -162,7 +162,12 @@
@Override
public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
Register dst = asRegister(result);
- masm.loadAddress(dst, (AArch64Address) crb.recordDataReferenceInCode(data), data.getAlignment());
+ if (crb.compilationResult.isImmutablePIC()) {
+ crb.recordDataReferenceInCode(data);
+ masm.addressOf(dst);
+ } else {
+ masm.loadAddress(dst, (AArch64Address) crb.recordDataReferenceInCode(data), data.getAlignment());
+ }
}
}
@@ -192,6 +197,7 @@
public static class MembarOp extends AArch64LIRInstruction {
public static final LIRInstructionClass<MembarOp> TYPE = LIRInstructionClass.create(MembarOp.class);
+ // For future use.
@SuppressWarnings("unused") private final int barriers;
public MembarOp(int barriers) {
@@ -200,14 +206,15 @@
}
@Override
- public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ // The odd-looking @SuppressWarnings("all") is here because of
+ // a compiler bug which warns that crb is unused, and also
+ // warns that @SuppressWarnings("unused") is unnecessary.
+ public void emitCode(@SuppressWarnings("all") CompilationResultBuilder crb, AArch64MacroAssembler masm) {
// As I understand it load acquire/store release have the same semantics as on IA64
// and allow us to handle LoadStore, LoadLoad and StoreStore without an explicit
// barrier.
// But Graal support to figure out if a load/store is volatile is non-existant so for
- // now
- // just use
- // memory barriers everywhere.
+ // now just use memory barriers everywhere.
// if ((barrier & MemoryBarriers.STORE_LOAD) != 0) {
masm.dmb(AArch64MacroAssembler.BarrierKind.ANY_ANY);
// }
@@ -408,7 +415,7 @@
}
}
- private static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+ static void reg2stack(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
AArch64Address dest = loadStackSlotAddress(crb, masm, asStackSlot(result), Value.ILLEGAL);
Register src = asRegister(input);
// use the slot kind to define the operand size
@@ -421,7 +428,7 @@
}
}
- private static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
+ static void stack2reg(CompilationResultBuilder crb, AArch64MacroAssembler masm, AllocatableValue result, AllocatableValue input) {
AArch64Kind kind = (AArch64Kind) input.getPlatformKind();
// use the slot kind to define the operand size
final int size = kind.getSizeInBytes() * Byte.SIZE;
@@ -466,6 +473,12 @@
case Float:
if (AArch64MacroAssembler.isFloatImmediate(input.asFloat())) {
masm.fmov(32, dst, input.asFloat());
+ } else if (crb.compilationResult.isImmutablePIC()) {
+ try (ScratchRegister scr = masm.getScratchRegister()) {
+ Register scratch = scr.getRegister();
+ masm.mov(scratch, Float.floatToRawIntBits(input.asFloat()));
+ masm.fmov(32, dst, scratch);
+ }
} else {
masm.fldr(32, dst, (AArch64Address) crb.asFloatConstRef(input));
}
@@ -473,6 +486,12 @@
case Double:
if (AArch64MacroAssembler.isDoubleImmediate(input.asDouble())) {
masm.fmov(64, dst, input.asDouble());
+ } else if (crb.compilationResult.isImmutablePIC()) {
+ try (ScratchRegister scr = masm.getScratchRegister()) {
+ Register scratch = scr.getRegister();
+ masm.mov(scratch, Double.doubleToRawLongBits(input.asDouble()));
+ masm.fmov(64, dst, scratch);
+ }
} else {
masm.fldr(64, dst, (AArch64Address) crb.asDoubleConstRef(input));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64RestoreRegistersOp.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. 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.aarch64;
+
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+
+import java.util.Arrays;
+
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Restores registers from stack slots.
+ */
+@Opcode("RESTORE_REGISTER")
+public class AArch64RestoreRegistersOp extends AArch64LIRInstruction {
+ public static final LIRInstructionClass<AArch64RestoreRegistersOp> TYPE = LIRInstructionClass.create(AArch64RestoreRegistersOp.class);
+
+ /**
+ * The slots from which the registers are restored.
+ */
+ @Use(STACK) protected final AllocatableValue[] slots;
+
+ /**
+ * The operation that saved the registers restored by this operation.
+ */
+ private final AArch64SaveRegistersOp save;
+
+ public AArch64RestoreRegistersOp(AllocatableValue[] values, AArch64SaveRegistersOp save) {
+ this(TYPE, values, save);
+ }
+
+ protected AArch64RestoreRegistersOp(LIRInstructionClass<? extends AArch64RestoreRegistersOp> c, AllocatableValue[] values, AArch64SaveRegistersOp save) {
+ super(c);
+ assert Arrays.asList(values).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
+ this.slots = values;
+ this.save = save;
+ }
+
+ protected Register[] getSavedRegisters() {
+ return save.savedRegisters;
+ }
+
+ protected void restoreRegister(CompilationResultBuilder crb, AArch64MacroAssembler masm, Register result, StackSlot input) {
+ AArch64Move.stack2reg(crb, masm, result.asValue(), input);
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ Register[] savedRegisters = getSavedRegisters();
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+ restoreRegister(crb, masm, savedRegisters[i], asStackSlot(slots[i]));
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64SaveRegistersOp.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.aarch64;
+
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
+
+import java.util.Arrays;
+
+import jdk.internal.vm.compiler.collections.EconomicSet;
+import org.graalvm.compiler.asm.aarch64.AArch64MacroAssembler;
+import org.graalvm.compiler.lir.LIRInstructionClass;
+import org.graalvm.compiler.lir.LIRValueUtil;
+import org.graalvm.compiler.lir.Opcode;
+import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
+import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
+import org.graalvm.compiler.lir.framemap.FrameMap;
+
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterSaveLayout;
+import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.meta.AllocatableValue;
+
+/**
+ * Saves registers to stack slots.
+ */
+@Opcode("SAVE_REGISTER")
+public class AArch64SaveRegistersOp extends AArch64LIRInstruction implements SaveRegistersOp {
+ public static final LIRInstructionClass<AArch64SaveRegistersOp> TYPE = LIRInstructionClass.create(AArch64SaveRegistersOp.class);
+
+ /**
+ * The registers (potentially) saved by this operation.
+ */
+ protected final Register[] savedRegisters;
+
+ /**
+ * The slots to which the registers are saved.
+ */
+ @Def(STACK) protected final AllocatableValue[] slots;
+
+ /**
+ * Specifies if {@link #remove(EconomicSet)} should have an effect.
+ */
+ protected final boolean supportsRemove;
+
+ /**
+ *
+ * @param savedRegisters the registers saved by this operation which may be subject to
+ * {@linkplain #remove(EconomicSet) pruning}
+ * @param savedRegisterLocations the slots to which the registers are saved
+ * @param supportsRemove determines if registers can be {@linkplain #remove(EconomicSet) pruned}
+ */
+ public AArch64SaveRegistersOp(Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+ this(TYPE, savedRegisters, savedRegisterLocations, supportsRemove);
+ }
+
+ public AArch64SaveRegistersOp(LIRInstructionClass<? extends AArch64SaveRegistersOp> c, Register[] savedRegisters, AllocatableValue[] savedRegisterLocations, boolean supportsRemove) {
+ super(c);
+ assert Arrays.asList(savedRegisterLocations).stream().allMatch(LIRValueUtil::isVirtualStackSlot);
+ this.savedRegisters = savedRegisters;
+ this.slots = savedRegisterLocations;
+ this.supportsRemove = supportsRemove;
+ }
+
+ protected void saveRegister(CompilationResultBuilder crb, AArch64MacroAssembler masm, StackSlot result, Register input) {
+ AArch64Move.reg2stack(crb, masm, result, input.asValue());
+ }
+
+ @Override
+ public void emitCode(CompilationResultBuilder crb, AArch64MacroAssembler masm) {
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+ saveRegister(crb, masm, asStackSlot(slots[i]), savedRegisters[i]);
+ }
+ }
+ }
+
+ public AllocatableValue[] getSlots() {
+ return slots;
+ }
+
+ @Override
+ public boolean supportsRemove() {
+ return supportsRemove;
+ }
+
+ @Override
+ public int remove(EconomicSet<Register> doNotSave) {
+ if (!supportsRemove) {
+ throw new UnsupportedOperationException();
+ }
+ return prune(doNotSave, savedRegisters);
+ }
+
+ static int prune(EconomicSet<Register> toRemove, Register[] registers) {
+ int pruned = 0;
+ for (int i = 0; i < registers.length; i++) {
+ if (registers[i] != null) {
+ if (toRemove.contains(registers[i])) {
+ registers[i] = null;
+ pruned++;
+ }
+ }
+ }
+ return pruned;
+ }
+
+ @Override
+ public RegisterSaveLayout getMap(FrameMap frameMap) {
+ int total = 0;
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ total++;
+ }
+ }
+ Register[] keys = new Register[total];
+ int[] values = new int[total];
+ if (total != 0) {
+ int mapIndex = 0;
+ for (int i = 0; i < savedRegisters.length; i++) {
+ if (savedRegisters[i] != null) {
+ keys[mapIndex] = savedRegisters[i];
+ assert isStackSlot(slots[i]) : "not a StackSlot: " + slots[i];
+ StackSlot slot = asStackSlot(slots[i]);
+ values[mapIndex] = indexForStackSlot(frameMap, slot);
+ mapIndex++;
+ }
+ }
+ assert mapIndex == total;
+ }
+ return new RegisterSaveLayout(keys, values);
+ }
+
+ /**
+ * Computes the index of a stack slot relative to slot 0. This is also the bit index of stack
+ * slots in the reference map.
+ *
+ * @param slot a stack slot
+ * @return the index of the stack slot
+ */
+ private static int indexForStackSlot(FrameMap frameMap, StackSlot slot) {
+ assert frameMap.offsetForStackSlot(slot) % frameMap.getTarget().wordSize == 0;
+ int value = frameMap.offsetForStackSlot(slot) / frameMap.getTarget().wordSize;
+ return value;
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java Thu May 31 10:38:05 2018 -0700
@@ -431,6 +431,12 @@
masm.lock();
}
switch (accessKind) {
+ case BYTE:
+ masm.cmpxchgb(asRegister(newValue), address.toAddress());
+ break;
+ case WORD:
+ masm.cmpxchgw(asRegister(newValue), address.toAddress());
+ break;
case DWORD:
masm.cmpxchgl(asRegister(newValue), address.toAddress());
break;
@@ -468,6 +474,12 @@
masm.lock();
}
switch (accessKind) {
+ case BYTE:
+ masm.xaddb(address.toAddress(), asRegister(result));
+ break;
+ case WORD:
+ masm.xaddw(address.toAddress(), asRegister(result));
+ break;
case DWORD:
masm.xaddl(address.toAddress(), asRegister(result));
break;
@@ -502,6 +514,12 @@
public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
move(accessKind, crb, masm, result, newValue);
switch (accessKind) {
+ case BYTE:
+ masm.xchgb(asRegister(result), address.toAddress());
+ break;
+ case WORD:
+ masm.xchgw(asRegister(result), address.toAddress());
+ break;
case DWORD:
masm.xchgl(asRegister(result), address.toAddress());
break;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGeneratorTool.java Thu May 31 10:38:05 2018 -0700
@@ -142,17 +142,18 @@
void emitNullCheck(Value address, LIRFrameState state);
- Variable emitLogicCompareAndSwap(Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
+ Variable emitLogicCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue, Value trueValue, Value falseValue);
- Value emitValueCompareAndSwap(Value address, Value expectedValue, Value newValue);
+ Value emitValueCompareAndSwap(LIRKind accessKind, Value address, Value expectedValue, Value newValue);
/**
* Emit an atomic read-and-add instruction.
*
* @param address address of the value to be read and written
+ * @param valueKind the access kind for the value to be written
* @param delta the value to be added
*/
- default Value emitAtomicReadAndAdd(Value address, Value delta) {
+ default Value emitAtomicReadAndAdd(Value address, ValueKind<?> valueKind, Value delta) {
throw GraalError.unimplemented();
}
@@ -160,9 +161,10 @@
* Emit an atomic read-and-write instruction.
*
* @param address address of the value to be read and written
+ * @param valueKind the access kind for the value to be written
* @param newValue the new value to be written
*/
- default Value emitAtomicReadAndWrite(Value address, Value newValue) {
+ default Value emitAtomicReadAndWrite(Value address, ValueKind<?> valueKind, Value newValue) {
throw GraalError.unimplemented();
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java Thu May 31 10:38:05 2018 -0700
@@ -116,12 +116,14 @@
Position firstPosition = successors.next();
AbstractBeginNode originalLoopBegin = BeginNode.begin(originalLoop.entryPoint());
firstPosition.set(newControlSplit, originalLoopBegin);
+ originalLoopBegin.setNodeSourcePosition(firstPosition.get(firstNode).getNodeSourcePosition());
while (successors.hasNext()) {
Position position = successors.next();
// create a new loop duplicate and connect it.
LoopFragmentWhole duplicateLoop = originalLoop.duplicate();
AbstractBeginNode newBegin = BeginNode.begin(duplicateLoop.entryPoint());
+ newBegin.setNodeSourcePosition(position.get(firstNode).getNodeSourcePosition());
position.set(newControlSplit, newBegin);
// For each cloned ControlSplitNode, simplify the proper path
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java Thu May 31 10:38:05 2018 -0700
@@ -118,7 +118,7 @@
}
// round-away-from-zero divison: (range + stride -/+ 1) / stride
ValueNode denominator = add(graph, range, sub(graph, absStride, one));
- ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride);
+ ValueNode div = unsignedDivBefore(graph, loop.entryPoint(), denominator, absStride, null);
if (assumePositive) {
return div;
@@ -251,7 +251,7 @@
}
assert graph.getGuardsStage().allowsFloatingGuards();
overflowGuard = graph.unique(new GuardNode(cond, AbstractBeginNode.prevBegin(loop.entryPoint()), DeoptimizationReason.LoopLimitCheck, DeoptimizationAction.InvalidateRecompile, true,
- JavaConstant.NULL_POINTER)); // TODO gd: use speculation
+ JavaConstant.NULL_POINTER, null)); // TODO gd: use speculation
loop.loopBegin().setOverflowGuard(overflowGuard);
return overflowGuard;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java Thu May 31 10:38:05 2018 -0700
@@ -543,6 +543,7 @@
}
}
+ @SuppressWarnings("try")
private AbstractBeginNode mergeEnds() {
assert isDuplicate();
List<EndNode> endsToMerge = new LinkedList<>();
@@ -562,9 +563,11 @@
if (endsToMerge.size() == 1) {
AbstractEndNode end = endsToMerge.get(0);
assert end.hasNoUsages();
- newExit = graph.add(new BeginNode());
- end.replaceAtPredecessor(newExit);
- end.safeDelete();
+ try (DebugCloseable position = end.withNodeSourcePosition()) {
+ newExit = graph.add(new BeginNode());
+ end.replaceAtPredecessor(newExit);
+ end.safeDelete();
+ }
} else {
assert endsToMerge.size() > 1;
AbstractMergeNode newExitMerge = graph.add(new MergeNode());
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/MathUtil.java Thu May 31 10:38:05 2018 -0700
@@ -31,6 +31,7 @@
import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
import org.graalvm.compiler.nodes.calc.SignedDivNode;
import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import java.util.function.BiFunction;
@@ -73,12 +74,12 @@
return BinaryArithmeticNode.sub(graph, v1, v2, NodeView.DEFAULT);
}
- public static ValueNode divBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) {
- return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> SignedDivNode.create(dend, sor, NodeView.DEFAULT));
+ public static ValueNode divBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor, GuardingNode zeroCheck) {
+ return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> SignedDivNode.create(dend, sor, zeroCheck, NodeView.DEFAULT));
}
- public static ValueNode unsignedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor) {
- return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> UnsignedDivNode.create(dend, sor, NodeView.DEFAULT));
+ public static ValueNode unsignedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor, GuardingNode zeroCheck) {
+ return fixedDivBefore(graph, before, dividend, divisor, (dend, sor) -> UnsignedDivNode.create(dend, sor, zeroCheck, NodeView.DEFAULT));
}
private static ValueNode fixedDivBefore(StructuredGraph graph, FixedNode before, ValueNode dividend, ValueNode divisor, BiFunction<ValueNode, ValueNode, ValueNode> createDiv) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/lir/GraalCompilerState.java Thu May 31 10:38:05 2018 -0700
@@ -319,7 +319,8 @@
assert !graph.isFrozen();
ResolvedJavaMethod installedCodeOwner = graph.method();
request = new Request<>(graph, installedCodeOwner, getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL,
- graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default);
+ graph.getProfilingInfo(), createSuites(getOptions()), createLIRSuites(getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default,
+ true);
}
/**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -31,13 +31,12 @@
import java.util.Set;
import java.util.stream.Collectors;
-import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.FilerException;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
@@ -45,11 +44,16 @@
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.processor.AbstractProcessor;
+/**
+ * Processor for {@value #NODE_INFO_CLASS_NAME} annotation.
+ */
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes({"org.graalvm.compiler.nodeinfo.NodeInfo"})
public class GraphNodeProcessor extends AbstractProcessor {
+ private static final String NODE_INFO_CLASS_NAME = "org.graalvm.compiler.nodeinfo.NodeInfo";
+
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
@@ -106,10 +110,6 @@
message(kind, element, "Exception thrown during processing: %s", buf.toString());
}
- ProcessingEnvironment getProcessingEnv() {
- return processingEnv;
- }
-
boolean isNodeType(Element element) {
if (element.getKind() != ElementKind.CLASS) {
return false;
@@ -134,17 +134,17 @@
GraphNodeVerifier verifier = new GraphNodeVerifier(this);
- for (Element element : roundEnv.getElementsAnnotatedWith(NodeInfo.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(getTypeElement(NODE_INFO_CLASS_NAME))) {
scope = element;
try {
if (!isNodeType(element)) {
- errorMessage(element, "%s can only be applied to Node subclasses", NodeInfo.class.getSimpleName());
+ errorMessage(element, "%s can only be applied to Node subclasses", getSimpleName(NODE_INFO_CLASS_NAME));
continue;
}
- NodeInfo nodeInfo = element.getAnnotation(NodeInfo.class);
+ AnnotationMirror nodeInfo = getAnnotation(element, getType(NODE_INFO_CLASS_NAME));
if (nodeInfo == null) {
- errorMessage(element, "Cannot get %s annotation from annotated element", NodeInfo.class.getSimpleName());
+ errorMessage(element, "Cannot get %s annotation from annotated element", getSimpleName(NODE_INFO_CLASS_NAME));
continue;
}
@@ -154,7 +154,7 @@
if (!modifiers.contains(Modifier.FINAL) && !modifiers.contains(Modifier.ABSTRACT)) {
// TODO(thomaswue): Reenable this check.
// errorMessage(element, "%s annotated class must be either final or abstract",
- // NodeInfo.class.getSimpleName());
+ // getSimpleName(NODE_INFO_CLASS_NAME));
// continue;
}
boolean found = false;
@@ -167,7 +167,7 @@
}
}
if (!found) {
- errorMessage(element, "%s annotated class must have a field named TYPE", NodeInfo.class.getSimpleName());
+ errorMessage(element, "%s annotated class must have a field named TYPE", getSimpleName(NODE_INFO_CLASS_NAME));
}
if (!typeElement.equals(verifier.Node) && !modifiers.contains(Modifier.ABSTRACT)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeVerifier.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodeinfo.processor/src/org/graalvm/compiler/nodeinfo/processor/GraphNodeVerifier.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 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
@@ -32,7 +32,6 @@
import java.util.List;
import java.util.Set;
-import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
@@ -42,17 +41,16 @@
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
-import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
+import org.graalvm.compiler.processor.AbstractProcessor;
+
/**
* Verifies static constraints on nodes.
*/
public class GraphNodeVerifier {
- private final GraphNodeProcessor env;
- private final Types types;
- private final Elements elements;
+ private final AbstractProcessor processor;
// Checkstyle: stop
private final TypeElement Input;
@@ -67,12 +65,8 @@
// Checkstyle: resume
- public GraphNodeVerifier(GraphNodeProcessor processor) {
- this.env = processor;
-
- this.types = processor.getProcessingEnv().getTypeUtils();
- this.elements = processor.getProcessingEnv().getElementUtils();
-
+ public GraphNodeVerifier(AbstractProcessor processor) {
+ this.processor = processor;
this.Input = getTypeElement("org.graalvm.compiler.graph.Node.Input");
this.OptionalInput = getTypeElement("org.graalvm.compiler.graph.Node.OptionalInput");
this.Successor = getTypeElement("org.graalvm.compiler.graph.Node.Successor");
@@ -88,11 +82,7 @@
* @throw {@link NoClassDefFoundError} if a type element does not exist for {@code name}
*/
public TypeElement getTypeElement(String name) {
- TypeElement typeElement = elements.getTypeElement(name);
- if (typeElement == null) {
- throw new NoClassDefFoundError(name);
- }
- return typeElement;
+ return processor.getTypeElement(name);
}
public TypeElement getTypeElement(Class<?> cls) {
@@ -103,11 +93,8 @@
return getTypeElement(name).asType();
}
- public ProcessingEnvironment getProcessingEnv() {
- return env.getProcessingEnv();
- }
-
public boolean isAssignableWithErasure(Element from, Element to) {
+ Types types = processor.env().getTypeUtils();
TypeMirror fromType = types.erasure(from.asType());
TypeMirror toType = types.erasure(to.asType());
return types.isAssignable(fromType, toType);
@@ -204,12 +191,12 @@
}
private boolean sameType(TypeMirror type1, TypeMirror type2) {
- return env.getProcessingEnv().getTypeUtils().isSameType(type1, type2);
+ return processor.env().getTypeUtils().isSameType(type1, type2);
}
private TypeElement getSuperType(TypeElement element) {
if (element.getSuperclass() != null) {
- return (TypeElement) env.getProcessingEnv().getTypeUtils().asElement(element.getSuperclass());
+ return processor.asTypeElement(element.getSuperclass());
}
return null;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IntegerStampTest.java Thu May 31 10:38:05 2018 -0700
@@ -27,7 +27,11 @@
import static org.junit.Assert.assertFalse;
import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
import org.graalvm.compiler.core.common.type.ArithmeticOpTable.ShiftOp;
@@ -582,4 +586,58 @@
assertEquals(longStamp.join(longEmpty), longEmpty);
assertEquals(longStamp.meet(longEmpty), longStamp);
}
+
+ @Test
+ public void testUnaryOpFoldEmpty() {
+ // boolean?, byte, short, int, long
+ Stream.of(1, 8, 16, 32, 64).map(bits -> StampFactory.forInteger(bits).empty()).forEach(empty -> {
+ for (ArithmeticOpTable.UnaryOp<?> op : IntegerStamp.OPS.getUnaryOps()) {
+ if (op != null) {
+ Assert.assertTrue(op.foldStamp(empty).isEmpty());
+ }
+ }
+ });
+ }
+
+ @Test
+ public void testIntegerConvertOpWithEmpty() {
+ int[] bits = new int[]{1, 8, 16, 32, 64};
+
+ List<IntegerConvertOp<?>> extendOps = Arrays.asList(
+ IntegerStamp.OPS.getSignExtend(),
+ IntegerStamp.OPS.getZeroExtend());
+
+ for (int inputBits : bits) {
+ IntegerStamp emptyIn = StampFactory.forInteger(inputBits).empty();
+ for (int outputBits : bits) {
+ IntegerStamp emptyOut = StampFactory.forInteger(outputBits).empty();
+ if (inputBits <= outputBits) {
+ for (IntegerConvertOp<?> stamp : extendOps) {
+ IntegerStamp folded = (IntegerStamp) stamp.foldStamp(inputBits, outputBits, emptyIn);
+ Assert.assertTrue(folded.isEmpty());
+ Assert.assertEquals(outputBits, folded.getBits());
+
+ // Widening is lossless, inversion is well-defined.
+ IntegerStamp inverted = (IntegerStamp) stamp.invertStamp(inputBits, outputBits, emptyOut);
+ Assert.assertTrue(inverted.isEmpty());
+ Assert.assertEquals(inputBits, inverted.getBits());
+ }
+ }
+
+ if (inputBits >= outputBits) {
+ IntegerConvertOp<?> narrow = IntegerStamp.OPS.getNarrow();
+ IntegerStamp folded = (IntegerStamp) narrow.foldStamp(inputBits, outputBits, emptyIn);
+ Assert.assertTrue(folded.isEmpty());
+ Assert.assertEquals(outputBits, folded.getBits());
+
+ // Narrowing is lossy, inversion can potentially yield empty or unknown (null).
+ IntegerStamp inverted = (IntegerStamp) narrow.invertStamp(inputBits, outputBits, emptyOut);
+ Assert.assertTrue(inverted == null || inverted.isEmpty());
+ if (inverted != null) {
+ Assert.assertEquals(inputBits, inverted.getBits());
+ }
+ }
+ }
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractFixedGuardNode.java Thu May 31 10:38:05 2018 -0700
@@ -25,6 +25,7 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.spi.Simplifiable;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.InputType;
@@ -46,6 +47,7 @@
protected DeoptimizationAction action;
protected JavaConstant speculation;
protected boolean negated;
+ protected NodeSourcePosition noDeoptSuccessorPosition;
@Override
public LogicNode getCondition() {
@@ -73,6 +75,12 @@
this.reason = deoptReason;
}
+ protected AbstractFixedGuardNode(NodeClass<? extends AbstractFixedGuardNode> c, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation,
+ boolean negated, NodeSourcePosition noDeoptSuccessorPosition) {
+ this(c, condition, deoptReason, action, speculation, negated);
+ this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
+ }
+
@Override
public DeoptimizationReason getReason() {
return reason;
@@ -126,6 +134,7 @@
ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1));
noDeoptSuccessor = ifNode.trueSuccessor();
}
+ noDeoptSuccessor.setNodeSourcePosition(getNoDeoptSuccessorPosition());
((FixedWithNextNode) predecessor()).setNext(ifNode);
this.replaceAtUsages(noDeoptSuccessor);
GraphUtil.killWithUnusedFloatingInputs(this);
@@ -148,4 +157,14 @@
public void setReason(DeoptimizationReason reason) {
this.reason = reason;
}
+
+ @Override
+ public NodeSourcePosition getNoDeoptSuccessorPosition() {
+ return noDeoptSuccessorPosition;
+ }
+
+ @Override
+ public void setNoDeoptSuccessorPosition(NodeSourcePosition noDeoptSuccessorPosition) {
+ this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractMergeNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractMergeNode.java Thu May 31 10:38:05 2018 -0700
@@ -28,6 +28,7 @@
import java.util.List;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
@@ -158,6 +159,7 @@
* canonicalization.
*/
@Override
+ @SuppressWarnings("try")
public void simplify(SimplifierTool tool) {
FixedNode currentNext = next();
if (currentNext instanceof AbstractEndNode) {
@@ -190,12 +192,14 @@
tool.addToWorkList(end);
}
AbstractEndNode newEnd;
- if (merge instanceof LoopBeginNode) {
- newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
- } else {
- EndNode tmpEnd = graph().add(new EndNode());
- merge.addForwardEnd(tmpEnd);
- newEnd = tmpEnd;
+ try (DebugCloseable position = end.withNodeSourcePosition()) {
+ if (merge instanceof LoopBeginNode) {
+ newEnd = graph().add(new LoopEndNode((LoopBeginNode) merge));
+ } else {
+ EndNode tmpEnd = graph().add(new EndNode());
+ merge.addForwardEnd(tmpEnd);
+ newEnd = tmpEnd;
+ }
}
for (PhiNode phi : merge.phis()) {
ValueNode v = phi.valueAt(origLoopEnd);
@@ -233,11 +237,13 @@
ValuePhiNode returnValuePhi = returnNode.result() == null || !isPhiAtMerge(returnNode.result()) ? null : (ValuePhiNode) returnNode.result();
List<EndNode> endNodes = forwardEnds().snapshot();
for (EndNode end : endNodes) {
- ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
- if (tool != null) {
- tool.addToWorkList(end.predecessor());
+ try (DebugCloseable position = returnNode.withNodeSourcePosition()) {
+ ReturnNode newReturn = graph().add(new ReturnNode(returnValuePhi == null ? returnNode.result() : returnValuePhi.valueAt(end)));
+ if (tool != null) {
+ tool.addToWorkList(end.predecessor());
+ }
+ end.replaceAtPredecessor(newReturn);
}
- end.replaceAtPredecessor(newReturn);
}
GraphUtil.killCFG(this);
for (EndNode end : endNodes) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java Thu May 31 10:38:05 2018 -0700
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.nodes;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.nodes.extended.GuardingNode;
/**
@@ -35,4 +36,16 @@
void setCondition(LogicNode x, boolean negated);
boolean isNegated();
+
+ NodeSourcePosition getNoDeoptSuccessorPosition();
+
+ void setNoDeoptSuccessorPosition(NodeSourcePosition noDeoptSuccessorPosition);
+
+ default void addCallerToNoDeoptSuccessorPosition(NodeSourcePosition caller) {
+ NodeSourcePosition noDeoptSuccessorPosition = getNoDeoptSuccessorPosition();
+ if (noDeoptSuccessorPosition == null) {
+ return;
+ }
+ setNoDeoptSuccessorPosition(new NodeSourcePosition(caller, noDeoptSuccessorPosition.getMethod(), noDeoptSuccessorPosition.getBCI()));
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java Thu May 31 10:38:05 2018 -0700
@@ -23,12 +23,14 @@
package org.graalvm.compiler.nodes;
import org.graalvm.compiler.debug.DebugCloseable;
+
import static org.graalvm.compiler.nodeinfo.InputType.Guard;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.spi.Lowerable;
@@ -50,10 +52,18 @@
this(condition, deoptReason, action, JavaConstant.NULL_POINTER, negated);
}
+ public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, NodeSourcePosition noDeoptSuccessorPosition) {
+ this(condition, deoptReason, action, JavaConstant.NULL_POINTER, negated, noDeoptSuccessorPosition);
+ }
+
public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated) {
super(TYPE, condition, deoptReason, action, speculation, negated);
}
+ public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated, NodeSourcePosition noDeoptSuccessorPosition) {
+ super(TYPE, condition, deoptReason, action, speculation, negated, noDeoptSuccessorPosition);
+ }
+
@Override
public void simplify(SimplifierTool tool) {
super.simplify(tool);
@@ -75,8 +85,10 @@
} else if (getCondition() instanceof ShortCircuitOrNode) {
ShortCircuitOrNode shortCircuitOr = (ShortCircuitOrNode) getCondition();
if (isNegated() && hasNoUsages()) {
- graph().addAfterFixed(this, graph().add(new FixedGuardNode(shortCircuitOr.getY(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isYNegated())));
- graph().replaceFixedWithFixed(this, graph().add(new FixedGuardNode(shortCircuitOr.getX(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isXNegated())));
+ graph().addAfterFixed(this,
+ graph().add(new FixedGuardNode(shortCircuitOr.getY(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isYNegated(), getNoDeoptSuccessorPosition())));
+ graph().replaceFixedWithFixed(this,
+ graph().add(new FixedGuardNode(shortCircuitOr.getX(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isXNegated(), getNoDeoptSuccessorPosition())));
}
}
}
@@ -87,7 +99,7 @@
try (DebugCloseable position = this.withNodeSourcePosition()) {
if (graph().getGuardsStage().allowsFloatingGuards()) {
if (getAction() != DeoptimizationAction.None) {
- ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode();
+ ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated(), getNoDeoptSuccessorPosition()).asNode();
this.replaceAtUsages(guard);
graph().removeFixed(this);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java Thu May 31 10:38:05 2018 -0700
@@ -1022,7 +1022,11 @@
}
}
if (graph.trackNodeSourcePosition() && position != null) {
- node.setNodeSourcePosition(methodScope.getCallerBytecodePosition(position));
+ NodeSourcePosition callerBytecodePosition = methodScope.getCallerBytecodePosition(position);
+ node.setNodeSourcePosition(callerBytecodePosition);
+ if (node instanceof DeoptimizingGuard) {
+ ((DeoptimizingGuard) node).addCallerToNoDeoptSuccessorPosition(callerBytecodePosition.getCaller());
+ }
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GuardNode.java Thu May 31 10:38:05 2018 -0700
@@ -31,6 +31,7 @@
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -63,19 +64,22 @@
protected DeoptimizationAction action;
protected JavaConstant speculation;
protected boolean negated;
+ protected NodeSourcePosition noDeoptSuccessorPosition;
- public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
- this(TYPE, condition, anchor, reason, action, negated, speculation);
+ public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation,
+ NodeSourcePosition noDeoptSuccessorPosition) {
+ this(TYPE, condition, anchor, reason, action, negated, speculation, noDeoptSuccessorPosition);
}
protected GuardNode(NodeClass<? extends GuardNode> c, LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated,
- JavaConstant speculation) {
+ JavaConstant speculation, NodeSourcePosition noDeoptSuccessorPosition) {
super(c, StampFactory.forVoid(), anchor);
this.condition = condition;
this.reason = reason;
this.action = action;
this.negated = negated;
this.speculation = speculation;
+ this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
}
/**
@@ -130,7 +134,7 @@
public Node canonical(CanonicalizerTool tool) {
if (getCondition() instanceof LogicNegationNode) {
LogicNegationNode negation = (LogicNegationNode) getCondition();
- return new GuardNode(negation.getValue(), getAnchor(), reason, action, !negated, speculation);
+ return new GuardNode(negation.getValue(), getAnchor(), reason, action, !negated, speculation, noDeoptSuccessorPosition);
}
if (getCondition() instanceof LogicConstantNode) {
LogicConstantNode c = (LogicConstantNode) getCondition();
@@ -158,4 +162,14 @@
public void setReason(DeoptimizationReason reason) {
this.reason = reason;
}
+
+ @Override
+ public NodeSourcePosition getNoDeoptSuccessorPosition() {
+ return noDeoptSuccessorPosition;
+ }
+
+ @Override
+ public void setNoDeoptSuccessorPosition(NodeSourcePosition noDeoptSuccessorPosition) {
+ this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java Thu May 31 10:38:05 2018 -0700
@@ -29,18 +29,25 @@
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.Equivalence;
+import org.graalvm.compiler.bytecode.BytecodeDisassembler;
+import org.graalvm.compiler.bytecode.Bytecodes;
+import org.graalvm.compiler.bytecode.Bytes;
+import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
import org.graalvm.compiler.core.common.calc.Condition;
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.debug.CounterKey;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.Simplifiable;
@@ -67,6 +74,7 @@
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.PrimitiveConstant;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
/**
@@ -170,6 +178,60 @@
return super.verify();
}
+ private boolean compareCallContext(NodeSourcePosition successorPosition) {
+ NodeSourcePosition position = getNodeSourcePosition();
+ NodeSourcePosition successor = successorPosition;
+ while (position != null) {
+ assertTrue(Objects.equals(position.getMethod(), successor.getMethod()), "method mismatch");
+ position = position.getCaller();
+ successor = successor.getCaller();
+ }
+ assertTrue(successor == null, "successor position has more methods");
+ return true;
+ }
+
+ @Override
+ public boolean verifySourcePosition() {
+ NodeSourcePosition sourcePosition = getNodeSourcePosition();
+ assertTrue(sourcePosition != null, "missing IfNode source position");
+
+ NodeSourcePosition trueSuccessorPosition = trueSuccessor.getNodeSourcePosition();
+ assertTrue(trueSuccessorPosition != null, "missing IfNode true successor source position");
+
+ NodeSourcePosition falseSuccessorPosition = falseSuccessor.getNodeSourcePosition();
+ assertTrue(falseSuccessorPosition != null, "missing IfNode false successor source position");
+
+ int bci = sourcePosition.getBCI();
+ ResolvedJavaMethod method = sourcePosition.getMethod();
+ int bytecode = BytecodeDisassembler.getBytecodeAt(method, bci);
+
+ if (!Bytecodes.isIfBytecode(bytecode)) {
+ return true;
+ }
+
+ byte[] code = (new ResolvedJavaMethodBytecode(method)).getCode();
+ int targetBCI = bci + Bytes.beS2(code, bci + 1);
+ int nextBCI = bci + Bytecodes.lengthOf(bytecode);
+
+ // At least one successor should have the correct BCI to indicate any possible negation that
+ // occurred after bytecode parsing
+ boolean matchingSuccessorFound = false;
+ if (trueSuccessorPosition.getBCI() == nextBCI || trueSuccessorPosition.getBCI() == targetBCI) {
+ assertTrue(compareCallContext(trueSuccessorPosition), "call context different from IfNode in trueSuccessor");
+ matchingSuccessorFound = true;
+ }
+
+ if (falseSuccessorPosition.getBCI() == nextBCI || falseSuccessorPosition.getBCI() == targetBCI) {
+ assertTrue(compareCallContext(falseSuccessorPosition), "call context different from IfNode in falseSuccessor");
+ matchingSuccessorFound = true;
+ }
+
+ assertTrue(matchingSuccessorFound, "no matching successor position found in IfNode");
+ assertTrue(trueSuccessorPosition.getBCI() != falseSuccessorPosition.getBCI(), "successor positions same in IfNode");
+
+ return true;
+ }
+
public void eliminateNegation() {
AbstractBeginNode oldTrueSuccessor = trueSuccessor;
AbstractBeginNode oldFalseSuccessor = falseSuccessor;
@@ -249,6 +311,11 @@
nextIf.setFalseSuccessor(intermediateBegin);
intermediateBegin.setNext(this);
this.setFalseSuccessor(bothFalseBegin);
+
+ NodeSourcePosition intermediateBeginPosition = intermediateBegin.getNodeSourcePosition();
+ intermediateBegin.setNodeSourcePosition(bothFalseBegin.getNodeSourcePosition());
+ bothFalseBegin.setNodeSourcePosition(intermediateBeginPosition);
+
nextIf.setTrueSuccessorProbability(probabilityB);
if (probabilityB == 1.0) {
this.setTrueSuccessorProbability(0.0);
@@ -477,6 +544,7 @@
* @param tool
* @return true if a replacement was done.
*/
+ @SuppressWarnings("try")
private boolean checkForUnsignedCompare(SimplifierTool tool) {
assert trueSuccessor().hasNoUsages() && falseSuccessor().hasNoUsages();
if (condition() instanceof IntegerLessThanNode) {
@@ -516,18 +584,20 @@
}
}
if (below != null) {
- ifNode2.setTrueSuccessor(null);
- ifNode2.setFalseSuccessor(null);
+ try (DebugCloseable position = ifNode2.withNodeSourcePosition()) {
+ ifNode2.setTrueSuccessor(null);
+ ifNode2.setFalseSuccessor(null);
- IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
- // Remove the < 0 test.
- tool.deleteBranch(trueSuccessor);
- graph().removeSplit(this, falseSuccessor);
+ IfNode newIfNode = graph().add(new IfNode(below, falseSucc, trueSucc, 1 - trueSuccessorProbability));
+ // Remove the < 0 test.
+ tool.deleteBranch(trueSuccessor);
+ graph().removeSplit(this, falseSuccessor);
- // Replace the second test with the new one.
- ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
- ifNode2.safeDelete();
- return true;
+ // Replace the second test with the new one.
+ ifNode2.predecessor().replaceFirstSuccessor(ifNode2, newIfNode);
+ ifNode2.safeDelete();
+ return true;
+ }
}
}
}
@@ -850,6 +920,7 @@
*
* @param tool
*/
+ @SuppressWarnings("try")
private boolean splitIfAtPhi(SimplifierTool tool) {
if (graph().getGuardsStage().areFrameStatesAtSideEffects()) {
// Disabled until we make sure we have no FrameState-less merges at this stage
@@ -918,12 +989,16 @@
} else if (result != condition) {
// Build a new IfNode using the new condition
BeginNode trueBegin = graph().add(new BeginNode());
+ trueBegin.setNodeSourcePosition(trueSuccessor().getNodeSourcePosition());
BeginNode falseBegin = graph().add(new BeginNode());
+ falseBegin.setNodeSourcePosition(falseSuccessor().getNodeSourcePosition());
if (result.graph() == null) {
result = graph().addOrUniqueWithInputs(result);
+ result.setNodeSourcePosition(condition.getNodeSourcePosition());
}
IfNode newIfNode = graph().add(new IfNode(result, trueBegin, falseBegin, trueSuccessorProbability));
+ newIfNode.setNodeSourcePosition(getNodeSourcePosition());
merge.removeEnd(end);
((FixedWithNextNode) end.predecessor()).setNext(newIfNode);
@@ -1053,6 +1128,7 @@
}
}
+ @SuppressWarnings("try")
private MergeNode insertMerge(AbstractBeginNode begin) {
MergeNode merge = graph().add(new MergeNode());
if (!begin.anchored().isEmpty()) {
@@ -1066,9 +1142,11 @@
AbstractBeginNode theBegin = begin;
if (begin instanceof LoopExitNode) {
// Insert an extra begin to make it easier.
- theBegin = graph().add(new BeginNode());
- begin.replaceAtPredecessor(theBegin);
- theBegin.setNext(begin);
+ try (DebugCloseable position = begin.withNodeSourcePosition()) {
+ theBegin = graph().add(new BeginNode());
+ begin.replaceAtPredecessor(theBegin);
+ theBegin.setNext(begin);
+ }
}
FixedNode next = theBegin.next();
next.replaceAtPredecessor(merge);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java Thu May 31 10:38:05 2018 -0700
@@ -225,9 +225,11 @@
while (replacementEntries.advance()) {
Invokable replacementInvoke = replacementEntries.getKey();
Callsite replacementSite = replacementEntries.getValue();
- Invokable invoke = (Invokable) replacements.get((Node) replacementInvoke);
- Callsite site = mapping.get(replacementSite);
- leaves.put(invoke, site);
+ if (replacementInvoke.isAlive()) {
+ Invokable invoke = (Invokable) replacements.get((Node) replacementInvoke);
+ Callsite site = mapping.get(replacementSite);
+ leaves.put(invoke, site);
+ }
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNegationNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNegationNode.java Thu May 31 10:38:05 2018 -0700
@@ -31,6 +31,8 @@
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import jdk.vm.ci.meta.TriState;
+
/**
* Logic node that negates its argument.
*/
@@ -77,4 +79,11 @@
return this;
}
+ @Override
+ public TriState implies(boolean thisNegated, LogicNode other) {
+ if (other == getValue()) {
+ return TriState.get(thisNegated);
+ }
+ return getValue().implies(!thisNegated, other);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LogicNode.java Thu May 31 10:38:05 2018 -0700
@@ -25,6 +25,7 @@
import static org.graalvm.compiler.nodeinfo.InputType.Condition;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+import jdk.vm.ci.meta.TriState;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
import org.graalvm.compiler.graph.NodeClass;
@@ -75,4 +76,19 @@
return false;
}
+
+ /**
+ * Determines what this condition implies about the other.
+ *
+ * <ul>
+ * <li>If negate(this, thisNegated) => other, returns {@link TriState#TRUE}</li>
+ * <li>If negate(this, thisNegated) => !other, returns {@link TriState#FALSE}</li>
+ * </ul>
+ *
+ * @param thisNegated whether this condition should be considered as false.
+ * @param other the other condition.
+ */
+ public TriState implies(boolean thisNegated, LogicNode other) {
+ return TriState.UNKNOWN;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/LoopBeginNode.java Thu May 31 10:38:05 2018 -0700
@@ -25,6 +25,7 @@
import static org.graalvm.compiler.graph.iterators.NodePredicates.isNotA;
import org.graalvm.compiler.core.common.type.IntegerStamp;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
@@ -310,13 +311,16 @@
return loopEnds().first();
}
+ @SuppressWarnings("try")
public void removeExits() {
for (LoopExitNode loopexit : loopExits().snapshot()) {
- loopexit.removeProxies();
- FrameState loopStateAfter = loopexit.stateAfter();
- graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
- if (loopStateAfter != null) {
- GraphUtil.tryKillUnused(loopStateAfter);
+ try (DebugCloseable position = graph().withNodeSourcePosition(loopexit)) {
+ loopexit.removeProxies();
+ FrameState loopStateAfter = loopexit.stateAfter();
+ graph().replaceFixedWithFixed(loopexit, graph().add(new BeginNode()));
+ if (loopStateAfter != null) {
+ GraphUtil.tryKillUnused(loopStateAfter);
+ }
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/PiArrayNode.java Thu May 31 10:38:05 2018 -0700
@@ -46,7 +46,7 @@
@Input ValueNode length;
@Override
- public ValueNode length() {
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
return length;
}
@@ -57,7 +57,7 @@
@Override
public Node canonical(CanonicalizerTool tool) {
- if (GraphUtil.arrayLength(object()) != length()) {
+ if (GraphUtil.arrayLength(object(), ArrayLengthProvider.FindLengthMode.SEARCH_ONLY) != length) {
return this;
}
return super.canonical(tool);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ShortCircuitOrNode.java Thu May 31 10:38:05 2018 -0700
@@ -26,15 +26,19 @@
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.graph.IterableNodeType;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.Canonicalizable;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
+import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
+
+import jdk.vm.ci.meta.TriState;
@NodeInfo(cycles = CYCLES_0, size = SIZE_0)
public final class ShortCircuitOrNode extends LogicNode implements IterableNodeType, Canonicalizable.Binary<LogicNode> {
-
public static final NodeClass<ShortCircuitOrNode> TYPE = NodeClass.create(ShortCircuitOrNode.class);
@Input(Condition) LogicNode x;
@Input(Condition) LogicNode y;
@@ -169,9 +173,90 @@
return optimizeShortCircuit(inner, this.yNegated, this.xNegated, false);
}
}
+
+ // !X => Y constant
+ TriState impliedForY = forX.implies(!isXNegated(), forY);
+ if (impliedForY.isKnown()) {
+ boolean yResult = impliedForY.toBoolean() ^ isYNegated();
+ return yResult
+ ? LogicConstantNode.tautology()
+ : (isXNegated()
+ ? LogicNegationNode.create(forX)
+ : forX);
+ }
+
+ // if X >= 0:
+ // u < 0 || X < u ==>> X |<| u
+ if (!isXNegated() && !isYNegated()) {
+ LogicNode sym = simplifyComparison(forX, forY);
+ if (sym != null) {
+ return sym;
+ }
+ }
+
+ // if X >= 0:
+ // X |<| u || X < u ==>> X |<| u
+ if (forX instanceof IntegerBelowNode && forY instanceof IntegerLessThanNode && !isXNegated() && !isYNegated()) {
+ IntegerBelowNode xNode = (IntegerBelowNode) forX;
+ IntegerLessThanNode yNode = (IntegerLessThanNode) forY;
+ ValueNode xxNode = xNode.getX(); // X >= 0
+ ValueNode yxNode = yNode.getX(); // X >= 0
+ if (xxNode == yxNode && ((IntegerStamp) xxNode.stamp(NodeView.DEFAULT)).isPositive()) {
+ ValueNode xyNode = xNode.getY(); // u
+ ValueNode yyNode = yNode.getY(); // u
+ if (xyNode == yyNode) {
+ return forX;
+ }
+ }
+ }
+
+ // if X >= 0:
+ // u < 0 || (X < u || tail) ==>> X |<| u || tail
+ if (forY instanceof ShortCircuitOrNode && !isXNegated() && !isYNegated()) {
+ ShortCircuitOrNode yNode = (ShortCircuitOrNode) forY;
+ if (!yNode.isXNegated()) {
+ LogicNode sym = simplifyComparison(forX, yNode.getX());
+ if (sym != null) {
+ double p1 = getShortCircuitProbability();
+ double p2 = yNode.getShortCircuitProbability();
+ return new ShortCircuitOrNode(sym, isXNegated(), yNode.getY(), yNode.isYNegated(), p1 + (1 - p1) * p2);
+ }
+ }
+ }
+
return this;
}
+ private static LogicNode simplifyComparison(LogicNode forX, LogicNode forY) {
+ LogicNode sym = simplifyComparisonOrdered(forX, forY);
+ if (sym == null) {
+ return simplifyComparisonOrdered(forY, forX);
+ }
+ return sym;
+ }
+
+ private static LogicNode simplifyComparisonOrdered(LogicNode forX, LogicNode forY) {
+ // if X is >= 0:
+ // u < 0 || X < u ==>> X |<| u
+ if (forX instanceof IntegerLessThanNode && forY instanceof IntegerLessThanNode) {
+ IntegerLessThanNode xNode = (IntegerLessThanNode) forX;
+ IntegerLessThanNode yNode = (IntegerLessThanNode) forY;
+ ValueNode xyNode = xNode.getY(); // 0
+ if (xyNode.isConstant() && IntegerStamp.OPS.getAdd().isNeutral(xyNode.asConstant())) {
+ ValueNode yxNode = yNode.getX(); // X >= 0
+ IntegerStamp stamp = (IntegerStamp) yxNode.stamp(NodeView.DEFAULT);
+ if (stamp.isPositive()) {
+ if (xNode.getX() == yNode.getY()) {
+ ValueNode u = xNode.getX();
+ return IntegerBelowNode.create(yxNode, u, NodeView.DEFAULT);
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
private static LogicNode optimizeShortCircuit(ShortCircuitOrNode inner, boolean innerNegated, boolean matchNegated, boolean matchIsInnerX) {
boolean innerMatchNegated;
if (matchIsInnerX) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/SimplifyingGraphDecoder.java Thu May 31 10:38:05 2018 -0700
@@ -30,6 +30,7 @@
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.Canonicalizable;
@@ -273,55 +274,60 @@
return new CanonicalizeToNullNode(node.stamp);
}
+ @SuppressWarnings("try")
private void handleCanonicalization(LoopScope loopScope, int nodeOrderId, FixedNode node, Node c) {
assert c != node : "unnecessary call";
- Node canonical = c == null ? canonicalizeFixedNodeToNull(node) : c;
- if (!canonical.isAlive()) {
- assert !canonical.isDeleted();
- canonical = graph.addOrUniqueWithInputs(canonical);
- if (canonical instanceof FixedWithNextNode) {
- graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
- } else if (canonical instanceof ControlSinkNode) {
- FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor();
- predecessor.setNext((ControlSinkNode) canonical);
- List<Node> successorSnapshot = node.successors().snapshot();
- node.safeDelete();
- for (Node successor : successorSnapshot) {
- successor.safeDelete();
+ try (DebugCloseable position = graph.withNodeSourcePosition(node)) {
+ Node canonical = c == null ? canonicalizeFixedNodeToNull(node) : c;
+ if (!canonical.isAlive()) {
+ assert !canonical.isDeleted();
+ canonical = graph.addOrUniqueWithInputs(canonical);
+ if (canonical instanceof FixedWithNextNode) {
+ graph.addBeforeFixed(node, (FixedWithNextNode) canonical);
+ } else if (canonical instanceof ControlSinkNode) {
+ FixedWithNextNode predecessor = (FixedWithNextNode) node.predecessor();
+ predecessor.setNext((ControlSinkNode) canonical);
+ List<Node> successorSnapshot = node.successors().snapshot();
+ node.safeDelete();
+ for (Node successor : successorSnapshot) {
+ successor.safeDelete();
+ }
+ } else {
+ assert !(canonical instanceof FixedNode);
}
-
- } else {
- assert !(canonical instanceof FixedNode);
}
+ if (!node.isDeleted()) {
+ GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
+ node.replaceAtUsagesAndDelete(canonical);
+ }
+ assert lookupNode(loopScope, nodeOrderId) == node;
+ registerNode(loopScope, nodeOrderId, canonical, true, false);
}
- if (!node.isDeleted()) {
- GraphUtil.unlinkFixedNode((FixedWithNextNode) node);
- node.replaceAtUsagesAndDelete(canonical);
- }
- assert lookupNode(loopScope, nodeOrderId) == node;
- registerNode(loopScope, nodeOrderId, canonical, true, false);
}
@Override
+ @SuppressWarnings("try")
protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
if (node instanceof ValueNode) {
((ValueNode) node).inferStamp();
}
if (node instanceof Canonicalizable) {
- Node canonical = ((Canonicalizable) node).canonical(canonicalizerTool);
- if (canonical == null) {
- /*
- * This is a possible return value of canonicalization. However, we might need to
- * add additional usages later on for which we need a node. Therefore, we just do
- * nothing and leave the node in place.
- */
- } else if (canonical != node) {
- if (!canonical.isAlive()) {
- assert !canonical.isDeleted();
- canonical = graph.addOrUniqueWithInputs(canonical);
+ try (DebugCloseable context = graph.withNodeSourcePosition(node)) {
+ Node canonical = ((Canonicalizable) node).canonical(canonicalizerTool);
+ if (canonical == null) {
+ /*
+ * This is a possible return value of canonicalization. However, we might need
+ * to add additional usages later on for which we need a node. Therefore, we
+ * just do nothing and leave the node in place.
+ */
+ } else if (canonical != node) {
+ if (!canonical.isAlive()) {
+ assert !canonical.isDeleted();
+ canonical = graph.addOrUniqueWithInputs(canonical);
+ }
+ assert node.hasNoUsages();
+ return canonical;
}
- assert node.hasNoUsages();
- return canonical;
}
}
return node;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnaryOpLogicNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/UnaryOpLogicNode.java Thu May 31 10:38:05 2018 -0700
@@ -28,6 +28,7 @@
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.spi.ValueProxy;
import jdk.vm.ci.meta.TriState;
@@ -52,7 +53,58 @@
public void generate(NodeLIRBuilderTool gen) {
}
+ /**
+ * In general the input stamp cannot be trusted, this method is reserved for the cases when it's
+ * "safe" to use the input stamp. To ensure safety use
+ * {@link #getSucceedingStampForValue(boolean)} instead.
+ */
+ public Stamp getSucceedingStampForValue(boolean negated, Stamp valueStamp) {
+ Stamp succStamp = getSucceedingStampForValue(negated);
+ if (succStamp != null) {
+ succStamp = succStamp.join(valueStamp);
+ }
+ return succStamp;
+ }
+
+ /**
+ * The input stamp cannot be trusted, the returned stamp cannot use the input stamp to narrow
+ * itself or derive any assumptions. This method does not use the input stamp and is considered
+ * safe.
+ *
+ * It's responsibility of the caller to determine when it's "safe" to "trust" the input stamp
+ * and use {@link #getSucceedingStampForValue(boolean, Stamp)} instead.
+ */
public abstract Stamp getSucceedingStampForValue(boolean negated);
public abstract TriState tryFold(Stamp valueStamp);
+
+ @Override
+ public TriState implies(boolean thisNegated, LogicNode other) {
+ if (other instanceof UnaryOpLogicNode) {
+ UnaryOpLogicNode unaryY = (UnaryOpLogicNode) other;
+ if (this.getValue() == unaryY.getValue() || // fast path
+ skipThroughPisAndProxies(this.getValue()) == skipThroughPisAndProxies(unaryY.getValue())) {
+ Stamp succStamp = this.getSucceedingStampForValue(thisNegated);
+ TriState fold = unaryY.tryFold(succStamp);
+ if (fold.isKnown()) {
+ return fold;
+ }
+ }
+ }
+ return super.implies(thisNegated, other);
+ }
+
+ private static ValueNode skipThroughPisAndProxies(ValueNode node) {
+ ValueNode n = node;
+ while (n != null) {
+ if (n instanceof PiNode) {
+ n = ((PiNode) n).getOriginalNode();
+ } else if (n instanceof ValueProxy) {
+ n = ((ValueProxy) n).getOriginalNode();
+ } else {
+ break;
+ }
+ }
+ return n;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ValuePhiNode.java Thu May 31 10:38:05 2018 -0700
@@ -29,16 +29,14 @@
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.type.StampTool;
-import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.util.CollectionsUtil;
/**
* Value {@link PhiNode}s merge data flow values at control flow merges.
*/
@NodeInfo(nameTemplate = "Phi({i#values}, {p#valueDescription})")
-public class ValuePhiNode extends PhiNode implements ArrayLengthProvider {
+public class ValuePhiNode extends PhiNode {
public static final NodeClass<ValuePhiNode> TYPE = NodeClass.create(ValuePhiNode.class);
@Input protected NodeInputList<ValueNode> values;
@@ -80,26 +78,6 @@
}
@Override
- public ValueNode length() {
- if (merge() instanceof LoopBeginNode) {
- return null;
- }
- ValueNode length = null;
- for (ValueNode input : values()) {
- ValueNode l = GraphUtil.arrayLength(input);
- if (l == null) {
- return null;
- }
- if (length == null) {
- length = l;
- } else if (length != l) {
- return null;
- }
- }
- return length;
- }
-
- @Override
public boolean verify() {
Stamp s = null;
for (ValueNode input : values()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java Thu May 31 10:38:05 2018 -0700
@@ -30,6 +30,7 @@
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.LogicNegationNode;
import org.graalvm.compiler.nodes.LogicNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
@@ -38,6 +39,7 @@
import jdk.vm.ci.code.CodeUtil;
import jdk.vm.ci.meta.ConstantReflectionProvider;
import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.TriState;
@NodeInfo(shortName = "|<|")
public final class IntegerBelowNode extends IntegerLowerThanNode {
@@ -135,4 +137,36 @@
return new IntegerBelowNode(x, y);
}
}
+
+ @Override
+ public TriState implies(boolean thisNegated, LogicNode other) {
+ if (other instanceof LogicNegationNode) {
+ // Unwrap negations.
+ TriState result = implies(thisNegated, ((LogicNegationNode) other).getValue());
+ if (result.isKnown()) {
+ return TriState.get(!result.toBoolean());
+ }
+ }
+ if (!thisNegated) {
+ if (other instanceof IntegerLessThanNode) {
+ IntegerLessThanNode integerLessThanNode = (IntegerLessThanNode) other;
+ IntegerStamp stampL = (IntegerStamp) this.getY().stamp(NodeView.DEFAULT);
+ // if L >= 0:
+ if (stampL.isPositive()) { // L >= 0
+ if (this.getX() == integerLessThanNode.getX()) {
+ // x |<| L implies x < L
+ if (this.getY() == integerLessThanNode.getY()) {
+ return TriState.TRUE;
+ }
+ // x |<| L implies !(x < 0)
+ if (integerLessThanNode.getY().isConstant() &&
+ IntegerStamp.OPS.getAdd().isNeutral(integerLessThanNode.getY().asConstant())) {
+ return TriState.FALSE;
+ }
+ }
+ }
+ }
+ }
+ return super.implies(thisNegated, other);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerDivRemNode.java Thu May 31 10:38:05 2018 -0700
@@ -28,9 +28,11 @@
import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -49,19 +51,26 @@
UNSIGNED
}
+ @OptionalInput(InputType.Guard) private GuardingNode zeroCheck;
+
private final Op op;
private final Type type;
private final boolean canDeopt;
- protected IntegerDivRemNode(NodeClass<? extends IntegerDivRemNode> c, Stamp stamp, Op op, Type type, ValueNode x, ValueNode y) {
+ protected IntegerDivRemNode(NodeClass<? extends IntegerDivRemNode> c, Stamp stamp, Op op, Type type, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
super(c, stamp, x, y);
+ this.zeroCheck = zeroCheck;
this.op = op;
this.type = type;
// Assigning canDeopt during constructor, because it must never change during lifetime of
// the node.
IntegerStamp yStamp = (IntegerStamp) getY().stamp(NodeView.DEFAULT);
- this.canDeopt = yStamp.contains(0) || yStamp.contains(-1);
+ this.canDeopt = (yStamp.contains(0) && zeroCheck == null) || yStamp.contains(-1);
+ }
+
+ public final GuardingNode getZeroCheck() {
+ return zeroCheck;
}
public final Op getOp() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedDivNode.java Thu May 31 10:38:05 2018 -0700
@@ -31,6 +31,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -41,16 +42,16 @@
public static final NodeClass<SignedDivNode> TYPE = NodeClass.create(SignedDivNode.class);
- protected SignedDivNode(ValueNode x, ValueNode y) {
- this(TYPE, x, y);
+ protected SignedDivNode(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ this(TYPE, x, y, zeroCheck);
}
- protected SignedDivNode(NodeClass<? extends SignedDivNode> c, ValueNode x, ValueNode y) {
- super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(NodeView.DEFAULT), y.stamp(NodeView.DEFAULT)), Op.DIV, Type.SIGNED, x, y);
+ protected SignedDivNode(NodeClass<? extends SignedDivNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ super(c, IntegerStamp.OPS.getDiv().foldStamp(x.stamp(NodeView.DEFAULT), y.stamp(NodeView.DEFAULT)), Op.DIV, Type.SIGNED, x, y, zeroCheck);
}
- public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
- return canonical(null, x, y, view);
+ public static ValueNode create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view) {
+ return canonical(null, x, y, zeroCheck, view);
}
@Override
@@ -61,17 +62,17 @@
@Override
public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
NodeView view = NodeView.from(tool);
- return canonical(this, forX, forY, view);
+ return canonical(this, forX, forY, getZeroCheck(), view);
}
- public static ValueNode canonical(SignedDivNode self, ValueNode forX, ValueNode forY, NodeView view) {
+ public static ValueNode canonical(SignedDivNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, NodeView view) {
Stamp predictedStamp = IntegerStamp.OPS.getDiv().foldStamp(forX.stamp(NodeView.DEFAULT), forY.stamp(NodeView.DEFAULT));
Stamp stamp = self != null ? self.stamp(view) : predictedStamp;
if (forX.isConstant() && forY.isConstant()) {
long y = forY.asJavaConstant().asLong();
if (y == 0) {
- return self != null ? self : new SignedDivNode(forX, forY); // this will trap, can
- // not canonicalize
+ /* This will trap, cannot canonicalize. */
+ return self != null ? self : new SignedDivNode(forX, forY, zeroCheck);
}
return ConstantNode.forIntegerStamp(stamp, forX.asJavaConstant().asLong() / y);
} else if (forY.isConstant()) {
@@ -89,7 +90,7 @@
SignedRemNode integerRemNode = (SignedRemNode) integerSubNode.getY();
if (integerSubNode.stamp(view).isCompatible(stamp) && integerRemNode.stamp(view).isCompatible(stamp) && integerSubNode.getX() == integerRemNode.getX() &&
forY == integerRemNode.getY()) {
- SignedDivNode sd = new SignedDivNode(integerSubNode.getX(), forY);
+ SignedDivNode sd = new SignedDivNode(integerSubNode.getX(), forY, zeroCheck);
sd.stateBefore = self != null ? self.stateBefore : null;
return sd;
}
@@ -103,7 +104,7 @@
}
}
- return self != null ? self : new SignedDivNode(forX, forY);
+ return self != null ? self : new SignedDivNode(forX, forY, zeroCheck);
}
public static ValueNode canonical(ValueNode forX, long c, NodeView view) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignedRemNode.java Thu May 31 10:38:05 2018 -0700
@@ -30,6 +30,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -40,17 +41,17 @@
public static final NodeClass<SignedRemNode> TYPE = NodeClass.create(SignedRemNode.class);
- protected SignedRemNode(ValueNode x, ValueNode y) {
- this(TYPE, x, y);
+ protected SignedRemNode(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ this(TYPE, x, y, zeroCheck);
}
- protected SignedRemNode(NodeClass<? extends SignedRemNode> c, ValueNode x, ValueNode y) {
- super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(NodeView.DEFAULT), y.stamp(NodeView.DEFAULT)), Op.REM, Type.SIGNED, x, y);
+ protected SignedRemNode(NodeClass<? extends SignedRemNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ super(c, IntegerStamp.OPS.getRem().foldStamp(x.stamp(NodeView.DEFAULT), y.stamp(NodeView.DEFAULT)), Op.REM, Type.SIGNED, x, y, zeroCheck);
}
- public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
+ public static ValueNode create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view) {
Stamp stamp = IntegerStamp.OPS.getRem().foldStamp(x.stamp(view), y.stamp(view));
- return canonical(null, x, y, stamp, view);
+ return canonical(null, x, y, zeroCheck, stamp, view);
}
@Override
@@ -61,15 +62,15 @@
@Override
public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
NodeView view = NodeView.from(tool);
- return canonical(this, forX, forY, stamp(view), view);
+ return canonical(this, forX, forY, getZeroCheck(), stamp(view), view);
}
- private static ValueNode canonical(SignedRemNode self, ValueNode forX, ValueNode forY, Stamp stamp, NodeView view) {
+ private static ValueNode canonical(SignedRemNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view) {
if (forX.isConstant() && forY.isConstant()) {
long y = forY.asJavaConstant().asLong();
if (y == 0) {
- return self != null ? self : new SignedRemNode(forX, forY); // this will trap, can
- // not canonicalize
+ /* This will trap, cannot canonicalize. */
+ return self != null ? self : new SignedRemNode(forX, forY, zeroCheck);
}
return ConstantNode.forIntegerStamp(stamp, forX.asJavaConstant().asLong() % y);
} else if (forY.isConstant() && forX.stamp(view) instanceof IntegerStamp && forY.stamp(view) instanceof IntegerStamp) {
@@ -78,7 +79,7 @@
IntegerStamp yStamp = (IntegerStamp) forY.stamp(view);
if (constY < 0 && constY != CodeUtil.minValue(yStamp.getBits())) {
Stamp newStamp = IntegerStamp.OPS.getRem().foldStamp(forX.stamp(view), forY.stamp(view));
- return canonical(null, forX, ConstantNode.forIntegerStamp(yStamp, -constY), newStamp, view);
+ return canonical(null, forX, ConstantNode.forIntegerStamp(yStamp, -constY), zeroCheck, newStamp, view);
}
if (constY == 1) {
@@ -96,7 +97,7 @@
}
}
}
- return self != null ? self : new SignedRemNode(forX, forY);
+ return self != null ? self : new SignedRemNode(forX, forY, zeroCheck);
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedDivNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedDivNode.java Thu May 31 10:38:05 2018 -0700
@@ -30,6 +30,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -40,33 +41,33 @@
public static final NodeClass<UnsignedDivNode> TYPE = NodeClass.create(UnsignedDivNode.class);
- public UnsignedDivNode(ValueNode x, ValueNode y) {
- this(TYPE, x, y);
+ public UnsignedDivNode(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ this(TYPE, x, y, zeroCheck);
}
- protected UnsignedDivNode(NodeClass<? extends UnsignedDivNode> c, ValueNode x, ValueNode y) {
- super(c, x.stamp(NodeView.DEFAULT).unrestricted(), Op.DIV, Type.UNSIGNED, x, y);
+ protected UnsignedDivNode(NodeClass<? extends UnsignedDivNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ super(c, x.stamp(NodeView.DEFAULT).unrestricted(), Op.DIV, Type.UNSIGNED, x, y, zeroCheck);
}
- public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
+ public static ValueNode create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view) {
Stamp stamp = x.stamp(view).unrestricted();
- return canonical(null, x, y, stamp, view);
+ return canonical(null, x, y, zeroCheck, stamp, view);
}
@Override
public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
NodeView view = NodeView.from(tool);
- return canonical(this, forX, forY, stamp(view), view);
+ return canonical(this, forX, forY, getZeroCheck(), stamp(view), view);
}
@SuppressWarnings("unused")
- private static ValueNode canonical(UnsignedDivNode self, ValueNode forX, ValueNode forY, Stamp stamp, NodeView view) {
+ private static ValueNode canonical(UnsignedDivNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view) {
int bits = ((IntegerStamp) stamp).getBits();
if (forX.isConstant() && forY.isConstant()) {
long yConst = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
if (yConst == 0) {
- return self != null ? self : new UnsignedDivNode(forX, forY); // this will trap,
- // cannot canonicalize
+ /* This will trap, cannot canonicalize. */
+ return self != null ? self : new UnsignedDivNode(forX, forY, zeroCheck);
}
return ConstantNode.forIntegerStamp(stamp, Long.divideUnsigned(CodeUtil.zeroExtend(forX.asJavaConstant().asLong(), bits), yConst));
} else if (forY.isConstant()) {
@@ -78,7 +79,7 @@
return new UnsignedRightShiftNode(forX, ConstantNode.forInt(CodeUtil.log2(c)));
}
}
- return self != null ? self : new UnsignedDivNode(forX, forY);
+ return self != null ? self : new UnsignedDivNode(forX, forY, zeroCheck);
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRemNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/UnsignedRemNode.java Thu May 31 10:38:05 2018 -0700
@@ -30,6 +30,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.LIRLowerable;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
@@ -40,33 +41,33 @@
public static final NodeClass<UnsignedRemNode> TYPE = NodeClass.create(UnsignedRemNode.class);
- public UnsignedRemNode(ValueNode x, ValueNode y) {
- this(TYPE, x, y);
+ public UnsignedRemNode(ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ this(TYPE, x, y, zeroCheck);
}
- protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y) {
- super(c, x.stamp(NodeView.DEFAULT).unrestricted(), Op.REM, Type.UNSIGNED, x, y);
+ protected UnsignedRemNode(NodeClass<? extends UnsignedRemNode> c, ValueNode x, ValueNode y, GuardingNode zeroCheck) {
+ super(c, x.stamp(NodeView.DEFAULT).unrestricted(), Op.REM, Type.UNSIGNED, x, y, zeroCheck);
}
- public static ValueNode create(ValueNode x, ValueNode y, NodeView view) {
+ public static ValueNode create(ValueNode x, ValueNode y, GuardingNode zeroCheck, NodeView view) {
Stamp stamp = x.stamp(view).unrestricted();
- return canonical(null, x, y, stamp, view);
+ return canonical(null, x, y, zeroCheck, stamp, view);
}
@Override
public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
NodeView view = NodeView.from(tool);
- return canonical(this, forX, forY, stamp(view), view);
+ return canonical(this, forX, forY, getZeroCheck(), stamp(view), view);
}
@SuppressWarnings("unused")
- public static ValueNode canonical(UnsignedRemNode self, ValueNode forX, ValueNode forY, Stamp stamp, NodeView view) {
+ public static ValueNode canonical(UnsignedRemNode self, ValueNode forX, ValueNode forY, GuardingNode zeroCheck, Stamp stamp, NodeView view) {
int bits = ((IntegerStamp) stamp).getBits();
if (forX.isConstant() && forY.isConstant()) {
long yConst = CodeUtil.zeroExtend(forY.asJavaConstant().asLong(), bits);
if (yConst == 0) {
- return self != null ? self : new UnsignedRemNode(forX, forY); // this will trap,
- // cannot canonicalize
+ /* This will trap, cannot canonicalize. */
+ return self != null ? self : new UnsignedRemNode(forX, forY, zeroCheck);
}
return ConstantNode.forIntegerStamp(stamp, Long.remainderUnsigned(CodeUtil.zeroExtend(forX.asJavaConstant().asLong(), bits), yConst));
} else if (forY.isConstant()) {
@@ -77,7 +78,7 @@
return new AndNode(forX, ConstantNode.forIntegerStamp(stamp, c - 1));
}
}
- return self != null ? self : new UnsignedRemNode(forX, forY);
+ return self != null ? self : new UnsignedRemNode(forX, forY, zeroCheck);
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BoxNode.java Thu May 31 10:38:05 2018 -0700
@@ -91,7 +91,9 @@
}
protected VirtualBoxingNode createVirtualBoxingNode() {
- return new VirtualBoxingNode(StampTool.typeOrNull(stamp(NodeView.DEFAULT)), boxingKind);
+ VirtualBoxingNode node = new VirtualBoxingNode(StampTool.typeOrNull(stamp(NodeView.DEFAULT)), boxingKind);
+ node.setNodeSourcePosition(getNodeSourcePosition());
+ return node;
}
@Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BytecodeExceptionNode.java Thu May 31 10:38:05 2018 -0700
@@ -28,8 +28,12 @@
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeInputList;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodeinfo.Verbosity;
import org.graalvm.compiler.nodes.ValueNode;
@@ -50,26 +54,43 @@
cyclesRationale = "Node will be lowered to a foreign call.",
size = SIZE_8)
// @formatter:on
-public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+public final class BytecodeExceptionNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single, Canonicalizable {
+
+ public enum BytecodeExceptionKind {
+ NULL_POINTER(0, NullPointerException.class),
+ OUT_OF_BOUNDS(2, ArrayIndexOutOfBoundsException.class),
+ CLASS_CAST(2, ClassCastException.class),
+ ARRAY_STORE(1, ArrayStoreException.class),
+ DIVISION_BY_ZERO(0, ArithmeticException.class);
+
+ final int numArguments;
+ final Class<? extends Throwable> exceptionClass;
+
+ BytecodeExceptionKind(int numArguments, Class<? extends Throwable> exceptionClass) {
+ this.numArguments = numArguments;
+ this.exceptionClass = exceptionClass;
+ }
+ }
public static final NodeClass<BytecodeExceptionNode> TYPE = NodeClass.create(BytecodeExceptionNode.class);
- protected final Class<? extends Throwable> exceptionClass;
+ protected final BytecodeExceptionKind exceptionKind;
@Input NodeInputList<ValueNode> arguments;
- public BytecodeExceptionNode(MetaAccessProvider metaAccess, Class<? extends Throwable> exceptionClass, ValueNode... arguments) {
- super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(exceptionClass))));
- this.exceptionClass = exceptionClass;
+ public BytecodeExceptionNode(MetaAccessProvider metaAccess, BytecodeExceptionKind exceptionKind, ValueNode... arguments) {
+ super(TYPE, StampFactory.objectNonNull(TypeReference.createExactTrusted(metaAccess.lookupJavaType(exceptionKind.exceptionClass))));
+ this.exceptionKind = exceptionKind;
this.arguments = new NodeInputList<>(this, arguments);
+ GraalError.guarantee(arguments.length == exceptionKind.numArguments, "Mismatch in argument count for BytecodeExceptionNode");
}
- public Class<? extends Throwable> getExceptionClass() {
- return exceptionClass;
+ public BytecodeExceptionKind getExceptionKind() {
+ return exceptionKind;
}
@Override
public String toString(Verbosity verbosity) {
if (verbosity == Verbosity.Name) {
- return super.toString(verbosity) + "#" + exceptionClass.getSimpleName();
+ return super.toString(verbosity) + "#" + exceptionKind;
}
return super.toString(verbosity);
}
@@ -80,6 +101,14 @@
}
@Override
+ public Node canonical(CanonicalizerTool tool) {
+ if (tool.allUsagesAvailable() && getUsageCount() == 0) {
+ return null;
+ }
+ return this;
+ }
+
+ @Override
public void lower(LoweringTool tool) {
tool.getLowerer().lower(this, tool);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/LoadArrayComponentHubNode.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,95 @@
+/*
+ * 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.nodes.extended;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
+
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.Canonicalizable;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.nodes.spi.StampProvider;
+
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+/**
+ * Loads the component hub for of the provided array hub.
+ *
+ * This is a fixed node because on certain VMs, for example the HotSpot VM, the read is only valid
+ * when the provided hub is actually an array hub (and not, e.g., a primitive hub), so this node
+ * must not float above a possible type check. Properly guarding this node would be possible too,
+ * but it is unlikely that the guard would be more flexible than just fixing the node in the control
+ * flow.
+ */
+@NodeInfo(cycles = CYCLES_2, size = SIZE_1)
+public final class LoadArrayComponentHubNode extends FixedWithNextNode implements Lowerable, Canonicalizable.Unary<ValueNode> {
+
+ public static final NodeClass<LoadArrayComponentHubNode> TYPE = NodeClass.create(LoadArrayComponentHubNode.class);
+
+ private @Input ValueNode value;
+
+ public static ValueNode create(ValueNode value, StampProvider stampProvider, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+ Stamp stamp = stampProvider.createHubStamp(null);
+ return findSynonym(null, value, stamp, metaAccess, constantReflection);
+ }
+
+ protected LoadArrayComponentHubNode(Stamp stamp, ValueNode value) {
+ super(TYPE, stamp);
+ this.value = value;
+ }
+
+ @Override
+ public ValueNode getValue() {
+ return value;
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ tool.getLowerer().lower(this, tool);
+ }
+
+ @Override
+ public Node canonical(CanonicalizerTool tool, ValueNode forValue) {
+ return findSynonym(this, forValue, stamp, tool.getMetaAccess(), tool.getConstantReflection());
+ }
+
+ private static ValueNode findSynonym(LoadArrayComponentHubNode self, ValueNode forValue, Stamp stamp, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+ if (forValue.isConstant()) {
+ ResolvedJavaType type = constantReflection.asJavaType(forValue.asConstant());
+ if (type != null) {
+ return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(type.getComponentType()), metaAccess);
+ }
+ }
+ return self != null ? self : new LoadArrayComponentHubNode(stamp, forValue);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GeneratedInvocationPlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GeneratedInvocationPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -22,17 +22,29 @@
*/
package org.graalvm.compiler.nodes.graphbuilderconf;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
+import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
import org.graalvm.compiler.nodes.ValueNode;
import jdk.vm.ci.meta.MetaAccessProvider;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
+/**
+ * Abstract class for a plugin generated for a method annotated by {@link NodeIntrinsic} or
+ * {@link Fold}.
+ */
public abstract class GeneratedInvocationPlugin implements InvocationPlugin {
+ /**
+ * Gets the class of the annotation for which this plugin was generated.
+ */
+ public abstract Class<? extends Annotation> getSource();
+
@Override
public abstract boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/GraphBuilderTool.java Thu May 31 10:38:05 2018 -0700
@@ -76,4 +76,10 @@
* by an intrinsic.
*/
boolean parsingIntrinsic();
+
+ @SuppressWarnings("unused")
+ default boolean canDeferPlugin(GeneratedInvocationPlugin plugin) {
+ // By default generated plugins must be completely processed during parsing.
+ return false;
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -84,6 +84,15 @@
}
/**
+ * Determines if this plugin only decorates the method is it associated with. That is, it
+ * inserts nodes prior to the invocation (e.g. some kind of marker nodes) but still expects the
+ * parser to process the invocation further.
+ */
+ default boolean isDecorator() {
+ return false;
+ }
+
+ /**
* Handles invocation of a signature polymorphic method.
*
* @param receiver access to the receiver, {@code null} if {@code targetMethod} is static
@@ -167,7 +176,8 @@
* @return {@code true} if this plugin handled the invocation of {@code targetMethod}
* {@code false} if the graph builder should process the invoke further (e.g., by
* inlining it or creating an {@link Invoke} node). A plugin that does not handle an
- * invocation must not modify the graph being constructed.
+ * invocation must not modify the graph being constructed unless it is a
+ * {@linkplain InvocationPlugin#isDecorator() decorator}.
*/
default boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] argsIncludingReceiver) {
if (isSignaturePolymorphic()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java Thu May 31 10:38:05 2018 -0700
@@ -679,7 +679,9 @@
}
}
if (res != null) {
- if (canBeIntrinsified(declaringClass)) {
+ // A decorator plugin is trusted since it does not replace
+ // the method it intrinsifies.
+ if (res.isDecorator() || canBeIntrinsified(declaringClass)) {
return res;
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/NodePlugin.java Thu May 31 10:38:05 2018 -0700
@@ -23,6 +23,7 @@
package org.graalvm.compiler.nodes.graphbuilderconf;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.JavaTypeProfile;
@@ -106,10 +107,12 @@
* @param b the context
* @param array the accessed array
* @param index the index for the array access
+ * @param boundsCheck the explicit bounds check already emitted, or null if no bounds check was
+ * emitted yet
* @param elementKind the element kind of the accessed array
* @return true if the plugin handles the array access, false otherwise.
*/
- default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+ default boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
return false;
}
@@ -119,11 +122,15 @@
* @param b the context
* @param array the accessed array
* @param index the index for the array access
+ * @param boundsCheck the explicit array bounds check already emitted, or null if no array
+ * bounds check was emitted yet
+ * @param storeCheck the explicit array store check already emitted, or null if no array store
+ * check was emitted yet
* @param elementKind the element kind of the accessed array
* @param value the value to be stored into the array
* @return true if the plugin handles the array access, false otherwise.
*/
- default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+ default boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) {
return false;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AbstractNewArrayNode.java Thu May 31 10:38:05 2018 -0700
@@ -38,8 +38,12 @@
public static final NodeClass<AbstractNewArrayNode> TYPE = NodeClass.create(AbstractNewArrayNode.class);
@Input protected ValueNode length;
+ public ValueNode length() {
+ return length;
+ }
+
@Override
- public ValueNode length() {
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
return length;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessIndexedNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AccessIndexedNode.java Thu May 31 10:38:05 2018 -0700
@@ -24,8 +24,10 @@
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
@@ -40,6 +42,7 @@
public static final NodeClass<AccessIndexedNode> TYPE = NodeClass.create(AccessIndexedNode.class);
@Input protected ValueNode index;
+ @OptionalInput(InputType.Guard) private GuardingNode boundsCheck;
protected final JavaKind elementKind;
public ValueNode index() {
@@ -52,14 +55,21 @@
* @param stamp the result kind of the access
* @param array the instruction producing the array
* @param index the instruction producing the index
+ * @param boundsCheck the explicit array bounds check already performed before the access, or
+ * null if no check was performed yet
* @param elementKind the kind of the elements of the array
*/
- protected AccessIndexedNode(NodeClass<? extends AccessIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, JavaKind elementKind) {
+ protected AccessIndexedNode(NodeClass<? extends AccessIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
super(c, stamp, array);
this.index = index;
+ this.boundsCheck = boundsCheck;
this.elementKind = elementKind;
}
+ public GuardingNode getBoundsCheck() {
+ return boundsCheck;
+ }
+
/**
* Gets the element type of the array.
*
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ArrayLengthNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ArrayLengthNode.java Thu May 31 10:38:05 2018 -0700
@@ -33,10 +33,9 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.LoweringTool;
-import org.graalvm.compiler.nodes.spi.ValueProxy;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
import org.graalvm.compiler.nodes.util.GraphUtil;
@@ -91,38 +90,14 @@
}
/**
- * Replicate the {@link ValueProxyNode}s from {@code originalValue} onto {@code value}.
- *
- * @param originalValue a possibly proxied value
- * @param value a value needing proxies
- * @return proxies wrapping {@code value}
- */
- private static ValueNode reproxyValue(ValueNode originalValue, ValueNode value) {
- if (value.isConstant()) {
- // No proxy needed
- return value;
- }
- if (originalValue instanceof ValueProxyNode) {
- ValueProxyNode proxy = (ValueProxyNode) originalValue;
- return new ValueProxyNode(reproxyValue(proxy.getOriginalNode(), value), proxy.proxyPoint());
- } else if (originalValue instanceof ValueProxy) {
- ValueProxy proxy = (ValueProxy) originalValue;
- return reproxyValue(proxy.getOriginalNode(), value);
- } else {
- return value;
- }
- }
-
- /**
* Gets the length of an array if possible.
*
* @return a node representing the length of {@code array} or null if it is not available
*/
public static ValueNode readArrayLength(ValueNode originalArray, ConstantReflectionProvider constantReflection) {
- ValueNode length = GraphUtil.arrayLength(originalArray);
+ ValueNode length = GraphUtil.arrayLength(originalArray, ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ);
if (length != null) {
- // Ensure that any proxies on the original value end up on the length value
- return reproxyValue(originalArray, length);
+ return length;
}
return readArrayLengthConstant(originalArray, constantReflection);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java Thu May 31 10:38:05 2018 -0700
@@ -27,6 +27,7 @@
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import jdk.vm.ci.meta.JavaKind;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -50,13 +51,19 @@
public static final NodeClass<AtomicReadAndAddNode> TYPE = NodeClass.create(AtomicReadAndAddNode.class);
@Input(Association) AddressNode address;
@Input ValueNode delta;
+ /**
+ * We explicitly track the kind of this node instead of using {#delta.getStackKind()} to be able
+ * to emit the memory access instruction with the correct number of bits.
+ */
+ private JavaKind valueKind;
protected final LocationIdentity locationIdentity;
- public AtomicReadAndAddNode(AddressNode address, ValueNode delta, LocationIdentity locationIdentity) {
- super(TYPE, StampFactory.forKind(delta.getStackKind()));
+ public AtomicReadAndAddNode(AddressNode address, ValueNode delta, JavaKind valueKind, LocationIdentity locationIdentity) {
+ super(TYPE, StampFactory.forKind(valueKind));
this.address = address;
this.delta = delta;
+ this.valueKind = valueKind;
this.locationIdentity = locationIdentity;
}
@@ -71,7 +78,7 @@
@Override
public void generate(NodeLIRBuilderTool gen) {
- Value result = gen.getLIRGeneratorTool().emitAtomicReadAndAdd(gen.operand(address), gen.operand(delta));
+ Value result = gen.getLIRGeneratorTool().emitAtomicReadAndAdd(gen.operand(address), gen.getLIRGeneratorTool().getValueKind(valueKind), gen.operand(delta));
gen.setResult(this, result);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/InstanceOfNode.java Thu May 31 10:38:05 2018 -0700
@@ -26,6 +26,8 @@
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+import java.util.Objects;
+
import org.graalvm.compiler.core.common.type.ObjectStamp;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
@@ -50,8 +52,6 @@
import jdk.vm.ci.meta.JavaTypeProfile;
import jdk.vm.ci.meta.TriState;
-import java.util.Objects;
-
/**
* The {@code InstanceOfNode} represents an instanceof test.
*/
@@ -219,4 +219,25 @@
assert this.checkedStamp.join(newCheckedStamp).equals(newCheckedStamp) : "stamp can only improve";
this.checkedStamp = newCheckedStamp;
}
+
+ @Override
+ public TriState implies(boolean thisNegated, LogicNode other) {
+ if (other instanceof InstanceOfNode) {
+ InstanceOfNode instanceOfNode = (InstanceOfNode) other;
+ if (instanceOfNode.getValue() == getValue()) {
+ if (thisNegated) {
+ // !X => Y
+ if (this.getCheckedStamp().meet(instanceOfNode.getCheckedStamp()).equals(this.getCheckedStamp())) {
+ return TriState.get(false);
+ }
+ } else {
+ // X => Y
+ if (instanceOfNode.getCheckedStamp().meet(this.getCheckedStamp()).equals(instanceOfNode.getCheckedStamp())) {
+ return TriState.get(true);
+ }
+ }
+ }
+ }
+ return super.implies(thisNegated, other);
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoadIndexedNode.java Thu May 31 10:38:05 2018 -0700
@@ -37,6 +37,7 @@
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
import org.graalvm.compiler.nodes.type.StampTool;
@@ -65,20 +66,21 @@
* @param index the instruction producing the index
* @param elementKind the element type
*/
- public LoadIndexedNode(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind) {
- this(TYPE, createStamp(assumptions, array, elementKind), array, index, elementKind);
+ public LoadIndexedNode(Assumptions assumptions, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
+ this(TYPE, createStamp(assumptions, array, elementKind), array, index, boundsCheck, elementKind);
}
- public static ValueNode create(Assumptions assumptions, ValueNode array, ValueNode index, JavaKind elementKind, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection) {
+ public static ValueNode create(Assumptions assumptions, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind, MetaAccessProvider metaAccess,
+ ConstantReflectionProvider constantReflection) {
ValueNode constant = tryConstantFold(array, index, metaAccess, constantReflection);
if (constant != null) {
return constant;
}
- return new LoadIndexedNode(assumptions, array, index, elementKind);
+ return new LoadIndexedNode(assumptions, array, index, boundsCheck, elementKind);
}
- protected LoadIndexedNode(NodeClass<? extends LoadIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, JavaKind elementKind) {
- super(c, stamp, array, index, elementKind);
+ protected LoadIndexedNode(NodeClass<? extends LoadIndexedNode> c, Stamp stamp, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
+ super(c, stamp, array, index, boundsCheck, elementKind);
}
private static Stamp createStamp(Assumptions assumptions, ValueNode array, JavaKind kind) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LogicCompareAndSwapNode.java Thu May 31 10:38:05 2018 -0700
@@ -66,7 +66,7 @@
LIRKind resultKind = tool.getLIRKind(stamp(NodeView.DEFAULT));
Value trueResult = tool.emitConstant(resultKind, JavaConstant.TRUE);
Value falseResult = tool.emitConstant(resultKind, JavaConstant.FALSE);
- Value result = tool.emitLogicCompareAndSwap(gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue()), trueResult, falseResult);
+ Value result = tool.emitLogicCompareAndSwap(tool.getLIRKind(getAccessStamp()), gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue()), trueResult, falseResult);
gen.setResult(this, result);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java Thu May 31 10:38:05 2018 -0700
@@ -27,6 +27,7 @@
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
+import jdk.vm.ci.meta.ValueKind;
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -53,10 +54,12 @@
public static final NodeClass<LoweredAtomicReadAndWriteNode> TYPE = NodeClass.create(LoweredAtomicReadAndWriteNode.class);
@Input ValueNode newValue;
@OptionalInput(State) FrameState stateAfter;
+ private final ValueKind<?> valueKind;
- public LoweredAtomicReadAndWriteNode(AddressNode address, LocationIdentity location, ValueNode newValue, BarrierType barrierType) {
+ public LoweredAtomicReadAndWriteNode(AddressNode address, LocationIdentity location, ValueNode newValue, ValueKind<?> valueKind, BarrierType barrierType) {
super(TYPE, address, location, newValue.stamp(NodeView.DEFAULT).unrestricted(), barrierType);
this.newValue = newValue;
+ this.valueKind = valueKind;
}
@Override
@@ -78,7 +81,10 @@
@Override
public void generate(NodeLIRBuilderTool gen) {
- Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(gen.operand(getAddress()), gen.operand(getNewValue()));
+ Value emitted = gen.operand(getNewValue());
+ // In case this node works with compressed objects, the newValue's kind must be used.
+ ValueKind<? extends ValueKind<?>> actualKind = newValue.stamp(NodeView.DEFAULT).getStackKind().isObject() ? emitted.getValueKind() : this.valueKind;
+ Value result = gen.getLIRGeneratorTool().emitAtomicReadAndWrite(gen.operand(getAddress()), actualKind, emitted);
gen.setResult(this, result);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java Thu May 31 10:38:05 2018 -0700
@@ -29,6 +29,7 @@
import org.graalvm.compiler.core.common.type.Stamp;
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.core.common.type.TypeReference;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.spi.Simplifiable;
import org.graalvm.compiler.graph.spi.SimplifierTool;
@@ -118,6 +119,7 @@
}
@Override
+ @SuppressWarnings("try")
public void simplify(SimplifierTool tool) {
if (hasNoUsages()) {
NodeView view = NodeView.from(tool);
@@ -132,10 +134,12 @@
// Should be areFrameStatesAtSideEffects but currently SVM will complain about
// RuntimeConstraint
if (graph().getGuardsStage().allowsFloatingGuards()) {
- LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), CanonicalCondition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view);
- // we do not have a non-deopting path for that at the moment so action=None.
- FixedGuardNode guard = graph().add(new FixedGuardNode(lengthNegativeCondition, DeoptimizationReason.RuntimeConstraint, DeoptimizationAction.None, true));
- graph().replaceFixedWithFixed(this, guard);
+ try (DebugCloseable context = this.withNodeSourcePosition()) {
+ LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), CanonicalCondition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view);
+ // we do not have a non-deopting path for that at the moment so action=None.
+ FixedGuardNode guard = graph().add(new FixedGuardNode(lengthNegativeCondition, DeoptimizationReason.RuntimeConstraint, DeoptimizationAction.None, true));
+ graph().replaceFixedWithFixed(this, guard);
+ }
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewMultiArrayNode.java Thu May 31 10:38:05 2018 -0700
@@ -87,7 +87,7 @@
}
@Override
- public ValueNode length() {
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
return dimension(0);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/StoreIndexedNode.java Thu May 31 10:38:05 2018 -0700
@@ -28,10 +28,12 @@
import org.graalvm.compiler.core.common.type.StampFactory;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
import org.graalvm.compiler.nodes.FrameState;
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.spi.Lowerable;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
@@ -49,9 +51,15 @@
public final class StoreIndexedNode extends AccessIndexedNode implements StateSplit, Lowerable, Virtualizable {
public static final NodeClass<StoreIndexedNode> TYPE = NodeClass.create(StoreIndexedNode.class);
+
+ @OptionalInput(InputType.Guard) private GuardingNode storeCheck;
@Input ValueNode value;
@OptionalInput(State) FrameState stateAfter;
+ public GuardingNode getStoreCheck() {
+ return storeCheck;
+ }
+
@Override
public FrameState stateAfter() {
return stateAfter;
@@ -73,8 +81,9 @@
return value;
}
- public StoreIndexedNode(ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
- super(TYPE, StampFactory.forVoid(), array, index, elementKind);
+ public StoreIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) {
+ super(TYPE, StampFactory.forVoid(), array, index, boundsCheck, elementKind);
+ this.storeCheck = storeCheck;
this.value = value;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndExchangeNode.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.nodes.java;
+
+import jdk.vm.ci.meta.JavaKind;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
+import org.graalvm.compiler.nodes.memory.MemoryCheckpoint;
+import org.graalvm.compiler.nodes.spi.Lowerable;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import jdk.internal.vm.compiler.word.LocationIdentity;
+
+import static org.graalvm.compiler.nodeinfo.InputType.Memory;
+import static org.graalvm.compiler.nodeinfo.InputType.Value;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8;
+
+/**
+ * Represents an atomic compare-and-swap operation. The result is the current value of the memory
+ * location that was compared.
+ */
+@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8)
+public final class UnsafeCompareAndExchangeNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
+
+ public static final NodeClass<UnsafeCompareAndExchangeNode> TYPE = NodeClass.create(UnsafeCompareAndExchangeNode.class);
+ @Input ValueNode object;
+ @Input ValueNode offset;
+ @Input ValueNode expected;
+ @Input ValueNode newValue;
+
+ private final JavaKind valueKind;
+ private final LocationIdentity locationIdentity;
+
+ public UnsafeCompareAndExchangeNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind valueKind, LocationIdentity locationIdentity) {
+ super(TYPE, expected.stamp(NodeView.DEFAULT).meet(newValue.stamp(NodeView.DEFAULT)));
+ assert expected.stamp(NodeView.DEFAULT).isCompatible(newValue.stamp(NodeView.DEFAULT));
+ this.object = object;
+ this.offset = offset;
+ this.expected = expected;
+ this.newValue = newValue;
+ this.valueKind = valueKind;
+ this.locationIdentity = locationIdentity;
+ }
+
+ public ValueNode object() {
+ return object;
+ }
+
+ public ValueNode offset() {
+ return offset;
+ }
+
+ public ValueNode expected() {
+ return expected;
+ }
+
+ public ValueNode newValue() {
+ return newValue;
+ }
+
+ public JavaKind getValueKind() {
+ return valueKind;
+ }
+
+ @Override
+ public LocationIdentity getLocationIdentity() {
+ return locationIdentity;
+ }
+
+ @Override
+ public void lower(LoweringTool tool) {
+ tool.getLowerer().lower(this, tool);
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/UnsafeCompareAndSwapNode.java Thu May 31 10:38:05 2018 -0700
@@ -41,8 +41,8 @@
import jdk.vm.ci.meta.JavaKind;
/**
- * Represents an atomic compare-and-swap operation The result is a boolean that contains whether the
- * value matched the expected value.
+ * Represents an atomic compare-and-swap operation. The result is a boolean that contains whether
+ * the value matched the expected value.
*/
@NodeInfo(allowedUsageTypes = {Value, Memory}, cycles = CYCLES_8, size = SIZE_8)
public final class UnsafeCompareAndSwapNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/ValueCompareAndSwapNode.java Thu May 31 10:38:05 2018 -0700
@@ -55,6 +55,6 @@
assert getNewValue().stamp(NodeView.DEFAULT).isCompatible(getExpectedValue().stamp(NodeView.DEFAULT));
LIRGeneratorTool tool = gen.getLIRGeneratorTool();
assert !this.canDeoptimize();
- gen.setResult(this, tool.emitValueCompareAndSwap(gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue())));
+ gen.setResult(this, tool.emitValueCompareAndSwap(tool.getLIRKind(getAccessStamp()), gen.operand(getAddress()), gen.operand(getExpectedValue()), gen.operand(getNewValue())));
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/ReadNode.java Thu May 31 10:38:05 2018 -0700
@@ -44,6 +44,7 @@
import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.memory.address.AddressNode;
import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
@@ -122,7 +123,7 @@
}
}
if (locationIdentity.equals(ARRAY_LENGTH_LOCATION)) {
- ValueNode length = GraphUtil.arrayLength(object);
+ ValueNode length = GraphUtil.arrayLength(object, ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ);
if (length != null) {
return length;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArrayLengthProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/ArrayLengthProvider.java Thu May 31 10:38:05 2018 -0700
@@ -23,11 +23,45 @@
package org.graalvm.compiler.nodes.spi;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
+import org.graalvm.compiler.nodes.util.GraphUtil;
public interface ArrayLengthProvider {
/**
- * @return the length of the array described by this node, or null if it is not available
+ * The different modes that determine what the results of {@link GraphUtil#arrayLength} and
+ * {@link ArrayLengthProvider#findLength} can be used for.
*/
- ValueNode length();
+ enum FindLengthMode {
+ /**
+ * Use the result of {@link GraphUtil#arrayLength} and
+ * {@link ArrayLengthProvider#findLength} to replace the explicit load of the array length
+ * with a node that does not involve a memory access of the array length.
+ *
+ * Values that are defined inside a loop and flow out the loop need to be proxied by
+ * {@link ValueProxyNode}. When this mode is used, new necessary proxy nodes are created
+ * base on the proxies that were found while traversing the path to the length node. In
+ * addition, new {@link ValuePhiNode phi nodes} can be created. The caller is responsible
+ * for adding these nodes to the graph, i.e., the return value can be a node that is not yet
+ * added to the graph.
+ */
+ CANONICALIZE_READ,
+
+ /**
+ * Use the result of {@link GraphUtil#arrayLength} and
+ * {@link ArrayLengthProvider#findLength} only for decisions whether a certain optimization
+ * is possible. No new nodes are created during the search, i.e., the result is either a
+ * node that is already in the graph, or null.
+ */
+ SEARCH_ONLY
+ }
+
+ /**
+ * Returns the length of the array described by this node, or null if it is not available.
+ * Details of the different modes are documented in {@link FindLengthMode}.
+ *
+ * This method should not be called directly. Use {@link GraphUtil#arrayLength} instead.
+ */
+ ValueNode findLength(FindLengthMode mode);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringTool.java Thu May 31 10:38:05 2018 -0700
@@ -23,6 +23,7 @@
package org.graalvm.compiler.nodes.spi;
import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.LogicNode;
@@ -51,7 +52,8 @@
GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action);
- GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated);
+ GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated,
+ NodeSourcePosition noDeoptSuccessorPosition);
/**
* Gets the closest fixed node preceding the node currently being lowered.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java Thu May 31 10:38:05 2018 -0700
@@ -28,6 +28,7 @@
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.function.BiFunction;
import jdk.internal.vm.compiler.collections.EconomicMap;
@@ -66,10 +67,13 @@
import org.graalvm.compiler.nodes.StateSplit;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.ValuePhiNode;
+import org.graalvm.compiler.nodes.ValueProxyNode;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
import org.graalvm.compiler.nodes.java.MonitorIdNode;
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
+import org.graalvm.compiler.nodes.spi.ArrayLengthProvider.FindLengthMode;
import org.graalvm.compiler.nodes.spi.LimitedValueProxy;
import org.graalvm.compiler.nodes.spi.LoweringProvider;
import org.graalvm.compiler.nodes.spi.ValueProxy;
@@ -664,28 +668,71 @@
}
/**
- * Looks for an {@link ArrayLengthProvider} while iterating through all {@link ValueProxy
- * ValueProxies}.
+ * Returns the length of the array described by the value parameter, or null if it is not
+ * available. Details of the different modes are documented in {@link FindLengthMode}.
*
* @param value The start value.
+ * @param mode The mode as documented in {@link FindLengthMode}.
* @return The array length if one was found, or null otherwise.
*/
- public static ValueNode arrayLength(ValueNode value) {
+ public static ValueNode arrayLength(ValueNode value, ArrayLengthProvider.FindLengthMode mode) {
+ Objects.requireNonNull(mode);
+
ValueNode current = value;
do {
+ /*
+ * PiArrayNode implements ArrayLengthProvider and ValueProxy. We want to treat it as an
+ * ArrayLengthProvider, therefore we check this case first.
+ */
if (current instanceof ArrayLengthProvider) {
- ValueNode length = ((ArrayLengthProvider) current).length();
- if (length != null) {
- return length;
+ return ((ArrayLengthProvider) current).findLength(mode);
+
+ } else if (current instanceof ValuePhiNode) {
+ return phiArrayLength((ValuePhiNode) current, mode);
+
+ } else if (current instanceof ValueProxyNode) {
+ ValueProxyNode proxy = (ValueProxyNode) current;
+ ValueNode length = arrayLength(proxy.getOriginalNode(), mode);
+ if (mode == ArrayLengthProvider.FindLengthMode.CANONICALIZE_READ && length != null && !length.isConstant()) {
+ length = new ValueProxyNode(length, proxy.proxyPoint());
}
- }
- if (current instanceof ValueProxy) {
+ return length;
+
+ } else if (current instanceof ValueProxy) {
+ /* Written as a loop instead of a recursive call to reduce recursion depth. */
current = ((ValueProxy) current).getOriginalNode();
+
} else {
- break;
+ return null;
}
} while (true);
- return null;
+ }
+
+ private static ValueNode phiArrayLength(ValuePhiNode phi, ArrayLengthProvider.FindLengthMode mode) {
+ if (phi.merge() instanceof LoopBeginNode) {
+ /* Avoid cycle detection by not processing phi functions that could introduce cycles. */
+ return null;
+ }
+
+ ValueNode singleLength = null;
+ for (int i = 0; i < phi.values().count(); i++) {
+ ValueNode input = phi.values().get(i);
+ ValueNode length = arrayLength(input, mode);
+ if (length == null) {
+ return null;
+ }
+ assert length.stamp(NodeView.DEFAULT).getStackKind() == JavaKind.Int;
+
+ if (i == 0) {
+ assert singleLength == null;
+ singleLength = length;
+ } else if (singleLength == length) {
+ /* Nothing to do, still having a single length. */
+ } else {
+ return null;
+ }
+ }
+ return singleLength;
}
/**
@@ -1006,7 +1053,7 @@
} else {
/* The source array is not virtualized, emit index loads. */
for (int i = 0; i < readLength; i++) {
- LoadIndexedNode load = new LoadIndexedNode(null, sourceAlias, ConstantNode.forInt(i + fromInt, graph), elementKind);
+ LoadIndexedNode load = new LoadIndexedNode(null, sourceAlias, ConstantNode.forInt(i + fromInt, graph), null, elementKind);
tool.addNode(load);
newEntryState[i] = load;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/AllocatedObjectNode.java Thu May 31 10:38:05 2018 -0700
@@ -35,6 +35,7 @@
import org.graalvm.compiler.nodes.spi.ArrayLengthProvider;
import org.graalvm.compiler.nodes.spi.Virtualizable;
import org.graalvm.compiler.nodes.spi.VirtualizerTool;
+import org.graalvm.compiler.nodes.util.GraphUtil;
/**
* Selects one object from a {@link CommitAllocationNode}. The object is identified by its
@@ -71,10 +72,7 @@
}
@Override
- public ValueNode length() {
- if (virtualObject instanceof ArrayLengthProvider) {
- return ((ArrayLengthProvider) virtualObject).length();
- }
- return null;
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
+ return GraphUtil.arrayLength(virtualObject, mode);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java Thu May 31 10:38:05 2018 -0700
@@ -123,16 +123,20 @@
@Override
public VirtualArrayNode duplicate() {
- return new VirtualArrayNode(componentType, length);
+ VirtualArrayNode node = new VirtualArrayNode(componentType, length);
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
@Override
public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
- return new AllocatedObjectNode(this);
+ AllocatedObjectNode node = new AllocatedObjectNode(this);
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
@Override
- public ValueNode length() {
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
return ConstantNode.forInt(length);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualBoxingNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualBoxingNode.java Thu May 31 10:38:05 2018 -0700
@@ -53,14 +53,19 @@
@Override
public VirtualBoxingNode duplicate() {
- return new VirtualBoxingNode(type(), boxingKind);
+ VirtualBoxingNode node = new VirtualBoxingNode(type(), boxingKind);
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
@Override
public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
assert entries.length == 1;
assert locks == null;
- return new BoxNode(entries[0], type(), boxingKind);
+
+ BoxNode node = new BoxNode(entries[0], type(), boxingKind);
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
public ValueNode getBoxedValue(VirtualizerTool tool) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java Thu May 31 10:38:05 2018 -0700
@@ -113,11 +113,15 @@
@Override
public VirtualInstanceNode duplicate() {
- return new VirtualInstanceNode(type, fields, super.hasIdentity());
+ VirtualInstanceNode node = new VirtualInstanceNode(type, fields, super.hasIdentity());
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
@Override
public ValueNode getMaterializedRepresentation(FixedNode fixed, ValueNode[] entries, LockState locks) {
- return new AllocatedObjectNode(this);
+ AllocatedObjectNode node = new AllocatedObjectNode(this);
+ node.setNodeSourcePosition(this.getNodeSourcePosition());
+ return node;
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options.processor/src/org/graalvm/compiler/options/processor/OptionProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,6 @@
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -35,11 +34,11 @@
import java.util.Map;
import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
@@ -50,21 +49,16 @@
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic.Kind;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
-import org.graalvm.compiler.options.Option;
-import org.graalvm.compiler.options.OptionDescriptor;
-import org.graalvm.compiler.options.OptionDescriptors;
-import org.graalvm.compiler.options.OptionKey;
-import org.graalvm.compiler.options.OptionType;
+import org.graalvm.compiler.processor.AbstractProcessor;
/**
- * Processes static fields annotated with {@link Option}. An {@link OptionDescriptors}
+ * Processes static fields annotated with {@code Option}. An {@code OptionDescriptors}
* implementation is generated for each top level class containing at least one such field. The name
* of the generated class for top level class {@code com.foo.Bar} is
* {@code com.foo.Bar_OptionDescriptors}.
@@ -72,6 +66,12 @@
@SupportedAnnotationTypes({"org.graalvm.compiler.options.Option"})
public class OptionProcessor extends AbstractProcessor {
+ private static final String OPTION_CLASS_NAME = "org.graalvm.compiler.options.Option";
+ private static final String OPTION_KEY_CLASS_NAME = "org.graalvm.compiler.options.OptionKey";
+ private static final String OPTION_TYPE_CLASS_NAME = "org.graalvm.compiler.options.OptionType";
+ private static final String OPTION_DESCRIPTOR_CLASS_NAME = "org.graalvm.compiler.options.OptionDescriptor";
+ private static final String OPTION_DESCRIPTORS_CLASS_NAME = "org.graalvm.compiler.options.OptionDescriptors";
+
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
@@ -79,6 +79,9 @@
private final Set<Element> processed = new HashSet<>();
+ private TypeMirror optionTypeMirror;
+ private TypeMirror optionKeyTypeMirror;
+
private void processElement(Element element, OptionsInfo info) {
if (!element.getModifiers().contains(Modifier.STATIC)) {
@@ -90,26 +93,24 @@
return;
}
- Option annotation = element.getAnnotation(Option.class);
+ AnnotationMirror annotation = getAnnotation(element, optionTypeMirror);
assert annotation != null;
assert element instanceof VariableElement;
assert element.getKind() == ElementKind.FIELD;
VariableElement field = (VariableElement) element;
String fieldName = field.getSimpleName().toString();
- Elements elements = processingEnv.getElementUtils();
Types types = processingEnv.getTypeUtils();
TypeMirror fieldType = field.asType();
if (fieldType.getKind() != TypeKind.DECLARED) {
- processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OptionKey.class.getName(), element);
+ processingEnv.getMessager().printMessage(Kind.ERROR, "Option field must be of type " + OPTION_KEY_CLASS_NAME, element);
return;
}
DeclaredType declaredFieldType = (DeclaredType) fieldType;
- TypeMirror optionKeyType = elements.getTypeElement(OptionKey.class.getName()).asType();
- if (!types.isSubtype(fieldType, types.erasure(optionKeyType))) {
- String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionKeyType);
+ if (!types.isSubtype(fieldType, types.erasure(optionKeyTypeMirror))) {
+ String msg = String.format("Option field type %s is not a subclass of %s", fieldType, optionKeyTypeMirror);
processingEnv.getMessager().printMessage(Kind.ERROR, msg, element);
return;
}
@@ -123,7 +124,7 @@
return;
}
- String optionName = annotation.name();
+ String optionName = getAnnotationValue(annotation, "name", String.class);
if (optionName.equals("")) {
optionName = fieldName;
}
@@ -134,7 +135,7 @@
}
DeclaredType declaredOptionKeyType = declaredFieldType;
- while (!types.isSameType(types.erasure(declaredOptionKeyType), types.erasure(optionKeyType))) {
+ while (!types.isSameType(types.erasure(declaredOptionKeyType), types.erasure(optionKeyTypeMirror))) {
List<? extends TypeMirror> directSupertypes = types.directSupertypes(declaredFieldType);
assert !directSupertypes.isEmpty();
declaredOptionKeyType = (DeclaredType) directSupertypes.get(0);
@@ -171,12 +172,12 @@
processingEnv.getMessager().printMessage(Kind.ERROR, "Option field cannot be declared in the unnamed package", element);
return;
}
- String[] helpValue = annotation.help();
+ List<String> helpValue = getAnnotationValueList(annotation, "help", String.class);
String help = "";
- String[] extraHelp = {};
+ List<String> extraHelp = new ArrayList<>();
- if (helpValue.length == 1) {
- help = helpValue[0];
+ if (helpValue.size() == 1) {
+ help = helpValue.get(0);
if (help.startsWith("file:")) {
String path = help.substring("file:".length());
Filer filer = processingEnv.getFiler();
@@ -194,12 +195,10 @@
help = "";
}
String line = br.readLine();
- List<String> lines = new ArrayList<>();
while (line != null) {
- lines.add(line);
+ extraHelp.add(line);
line = br.readLine();
}
- extraHelp = lines.toArray(new String[lines.size()]);
}
} catch (IOException e) {
String msg = String.format("Error reading %s containing the help text for option field: %s", path, e);
@@ -207,9 +206,9 @@
return;
}
}
- } else if (helpValue.length > 1) {
- help = helpValue[0];
- extraHelp = Arrays.copyOfRange(helpValue, 1, helpValue.length);
+ } else if (helpValue.size() > 1) {
+ help = helpValue.get(0);
+ extraHelp = helpValue.subList(1, helpValue.size());
}
if (help.length() != 0) {
char firstChar = help.charAt(0);
@@ -219,7 +218,8 @@
}
}
- info.options.add(new OptionInfo(optionName, annotation.type(), help, extraHelp, optionType, declaringClass, field));
+ String optionTypeName = getAnnotationValue(annotation, "type", VariableElement.class).getSimpleName().toString();
+ info.options.add(new OptionInfo(optionName, optionTypeName, help, extraHelp, optionType, declaringClass, field));
}
private void createFiles(OptionsInfo info) {
@@ -231,7 +231,7 @@
}
private void createOptionsDescriptorsFile(OptionsInfo info, String pkg, Name topDeclaringClass, Element[] originatingElements) {
- String optionsClassName = topDeclaringClass + "_" + OptionDescriptors.class.getSimpleName();
+ String optionsClassName = topDeclaringClass + "_" + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME);
Filer filer = processingEnv.getFiler();
try (PrintWriter out = createSourceFile(pkg, optionsClassName, filer, originatingElements)) {
@@ -243,12 +243,12 @@
out.println("package " + pkg + ";");
out.println("");
out.println("import java.util.*;");
- out.println("import " + OptionDescriptors.class.getPackage().getName() + ".*;");
- out.println("import " + OptionType.class.getName() + ";");
+ out.println("import " + getPackageName(OPTION_DESCRIPTORS_CLASS_NAME) + ".*;");
+ out.println("import " + OPTION_TYPE_CLASS_NAME + ";");
out.println("");
- out.println("public class " + optionsClassName + " implements " + OptionDescriptors.class.getSimpleName() + " {");
+ out.println("public class " + optionsClassName + " implements " + getSimpleName(OPTION_DESCRIPTORS_CLASS_NAME) + " {");
- String desc = OptionDescriptor.class.getSimpleName();
+ String desc = getSimpleName(OPTION_DESCRIPTOR_CLASS_NAME);
Collections.sort(info.options);
@@ -265,18 +265,18 @@
optionField = option.declaringClass + "." + option.field.getSimpleName();
}
out.println(" case \"" + name + "\": {");
- OptionType optionType = option.optionType;
+ String optionType = option.optionType;
String type = option.type;
String help = option.help;
- String[] extraHelp = option.extraHelp;
+ List<String> extraHelp = option.extraHelp;
String declaringClass = option.declaringClass;
Name fieldName = option.field.getSimpleName();
out.printf(" return " + desc + ".create(\n");
out.printf(" /*name*/ \"%s\",\n", name);
- out.printf(" /*optionType*/ %s.%s,\n", optionType.getDeclaringClass().getSimpleName(), optionType.name());
+ out.printf(" /*optionType*/ %s.%s,\n", getSimpleName(OPTION_TYPE_CLASS_NAME), optionType);
out.printf(" /*optionValueType*/ %s.class,\n", type);
out.printf(" /*help*/ \"%s\",\n", help);
- if (extraHelp.length != 0) {
+ if (extraHelp.size() != 0) {
out.printf(" /*extraHelp*/ new String[] {\n");
for (String line : extraHelp) {
out.printf(" \"%s\",\n", line.replace("\\", "\\\\").replace("\"", "\\\""));
@@ -336,14 +336,14 @@
static class OptionInfo implements Comparable<OptionInfo> {
final String name;
- final OptionType optionType;
+ final String optionType;
final String help;
- final String[] extraHelp;
+ final List<String> extraHelp;
final String type;
final String declaringClass;
final VariableElement field;
- OptionInfo(String name, OptionType optionType, String help, String[] extraHelp, String type, String declaringClass, VariableElement field) {
+ OptionInfo(String name, String optionType, String help, List<String> extraHelp, String type, String declaringClass, VariableElement field) {
this.name = name;
this.optionType = optionType;
this.help = help;
@@ -390,8 +390,13 @@
return true;
}
+ TypeElement optionTypeElement = getTypeElement(OPTION_CLASS_NAME);
+
+ optionTypeMirror = optionTypeElement.asType();
+ optionKeyTypeMirror = getTypeElement(OPTION_KEY_CLASS_NAME).asType();
+
Map<Element, OptionsInfo> map = new HashMap<>();
- for (Element element : roundEnv.getElementsAnnotatedWith(Option.class)) {
+ for (Element element : roundEnv.getElementsAnnotatedWith(optionTypeElement)) {
if (!processed.contains(element)) {
processed.add(element);
Element topDeclaringType = topDeclaringType(element);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/CanonicalizerPhase.java Thu May 31 10:38:05 2018 -0700
@@ -314,7 +314,7 @@
@SuppressWarnings("try")
public boolean tryCanonicalize(final Node node, NodeClass<?> nodeClass) {
- try (DebugCloseable position = node.withNodeSourcePosition(); DebugContext.Scope scope = debug.scope("tryCanonicalize", node)) {
+ try (DebugCloseable position = node.withNodeSourcePosition(); DebugContext.Scope scope = debug.withContext(node)) {
if (customCanonicalizer != null) {
Node canonical = customCanonicalizer.canonicalize(node);
if (performReplacement(node, canonical)) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java Thu May 31 10:38:05 2018 -0700
@@ -172,7 +172,8 @@
AbstractMergeNode mergeNode = (AbstractMergeNode) beginNode;
for (GuardNode guard : mergeNode.guards().snapshot()) {
try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
- GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation());
+ GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), guard.getSpeculation(),
+ guard.getNoDeoptSuccessorPosition());
GuardNode newGuard = mergeNode.graph().unique(newlyCreatedGuard);
guard.replaceAndDelete(newGuard);
}
@@ -205,7 +206,8 @@
continue;
}
try (DebugCloseable closeable = guard.withNodeSourcePosition()) {
- GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), speculation);
+ GuardNode newlyCreatedGuard = new GuardNode(guard.getCondition(), anchorBlock.getBeginNode(), guard.getReason(), guard.getAction(), guard.isNegated(), speculation,
+ guard.getNoDeoptSuccessorPosition());
GuardNode newGuard = node.graph().unique(newlyCreatedGuard);
if (otherGuard.isAlive()) {
otherGuard.replaceAndDelete(newGuard);
@@ -245,7 +247,41 @@
}
}
- public static class Instance implements ControlFlowGraph.RecursiveVisitor<Integer> {
+ public static final class Marks {
+ final int infoElementOperations;
+ final int conditions;
+
+ public Marks(int infoElementOperations, int conditions) {
+ this.infoElementOperations = infoElementOperations;
+ this.conditions = conditions;
+ }
+ }
+
+ protected static final class GuardedCondition {
+ private final GuardingNode guard;
+ private final LogicNode condition;
+ private final boolean negated;
+
+ public GuardedCondition(GuardingNode guard, LogicNode condition, boolean negated) {
+ this.guard = guard;
+ this.condition = condition;
+ this.negated = negated;
+ }
+
+ public GuardingNode getGuard() {
+ return guard;
+ }
+
+ public LogicNode getCondition() {
+ return condition;
+ }
+
+ public boolean isNegated() {
+ return negated;
+ }
+ }
+
+ public static class Instance implements ControlFlowGraph.RecursiveVisitor<Marks> {
protected final NodeMap<InfoElement> map;
protected final BlockMap<List<Node>> blockToNodes;
protected final NodeMap<Block> nodeToBlock;
@@ -255,6 +291,8 @@
protected final DebugContext debug;
protected final EconomicMap<MergeNode, EconomicMap<ValuePhiNode, PhiInfoElement>> mergeMaps;
+ protected final ArrayDeque<GuardedCondition> conditions;
+
/**
* Tests which may be eliminated because post dominating tests to prove a broader condition.
*/
@@ -267,7 +305,8 @@
this.nodeToBlock = nodeToBlock;
this.undoOperations = new NodeStack();
this.map = graph.createNodeMap();
- pendingTests = new ArrayDeque<>();
+ this.pendingTests = new ArrayDeque<>();
+ this.conditions = new ArrayDeque<>();
tool = GraphUtil.getDefaultSimplifier(context.getMetaAccess(), context.getConstantReflection(), context.getConstantFieldProvider(), false, graph.getAssumptions(), graph.getOptions(),
context.getLowerer());
mergeMaps = EconomicMap.create();
@@ -337,13 +376,14 @@
}
@Override
- public Integer enter(Block block) {
- int mark = undoOperations.size();
+ public Marks enter(Block block) {
+ int infoElementsMark = undoOperations.size();
+ int conditionsMark = conditions.size();
debug.log("[Pre Processing block %s]", block);
// For now conservatively collect guards only within the same block.
pendingTests.clear();
processNodes(block);
- return mark;
+ return new Marks(infoElementsMark, conditionsMark);
}
protected void processNodes(Block block) {
@@ -531,8 +571,10 @@
UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) condition;
ValueNode value = unaryLogicNode.getValue();
if (maybeMultipleUsages(value)) {
+ // getSucceedingStampForValue doesn't take the (potentially a Pi Node) input
+ // stamp into account, so it can be safely propagated.
Stamp newStamp = unaryLogicNode.getSucceedingStampForValue(negated);
- registerNewStamp(value, newStamp, guard);
+ registerNewStamp(value, newStamp, guard, true);
}
} else if (condition instanceof BinaryOpLogicNode) {
BinaryOpLogicNode binaryOpLogicNode = (BinaryOpLogicNode) condition;
@@ -753,17 +795,21 @@
}
protected void registerCondition(LogicNode condition, boolean negated, GuardingNode guard) {
- if (condition.getUsageCount() > 1) {
+ if (condition.hasMoreThanOneUsage()) {
registerNewStamp(condition, negated ? StampFactory.contradiction() : StampFactory.tautology(), guard);
}
+ conditions.push(new GuardedCondition(guard, condition, negated));
}
protected InfoElement getInfoElements(ValueNode proxiedValue) {
- ValueNode value = GraphUtil.skipPi(proxiedValue);
- if (value == null) {
+ if (proxiedValue == null) {
return null;
}
- return map.getAndGrow(value);
+ InfoElement infoElement = map.getAndGrow(proxiedValue);
+ if (infoElement == null) {
+ infoElement = map.getAndGrow(GraphUtil.skipPi(proxiedValue));
+ }
+ return infoElement;
}
protected boolean rewireGuards(GuardingNode guard, boolean result, ValueNode proxifiedInput, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
@@ -801,6 +847,13 @@
infoElement = nextElement(infoElement);
}
+ for (GuardedCondition guardedCondition : this.conditions) {
+ TriState result = guardedCondition.getCondition().implies(guardedCondition.isNegated(), node);
+ if (result.isKnown()) {
+ return rewireGuards(guardedCondition.guard, result.toBoolean(), null, null, rewireGuardFunction);
+ }
+ }
+
if (node instanceof UnaryOpLogicNode) {
UnaryOpLogicNode unaryLogicNode = (UnaryOpLogicNode) node;
ValueNode value = unaryLogicNode.getValue();
@@ -943,30 +996,40 @@
}
protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard) {
+ registerNewStamp(maybeProxiedValue, newStamp, guard, false);
+ }
+
+ protected void registerNewStamp(ValueNode maybeProxiedValue, Stamp newStamp, GuardingNode guard, boolean propagateThroughPis) {
assert maybeProxiedValue != null;
assert guard != null;
- if (newStamp != null) {
- ValueNode value = maybeProxiedValue;
- Stamp stamp = newStamp;
+
+ if (newStamp == null || newStamp.isUnrestricted()) {
+ return;
+ }
+
+ ValueNode value = maybeProxiedValue;
+ Stamp stamp = newStamp;
+
+ while (stamp != null && value != null) {
ValueNode proxiedValue = null;
if (value instanceof PiNode) {
proxiedValue = value;
}
- do {
- counterStampsRegistered.increment(debug);
- debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, stamp, guard);
- assert value instanceof LogicNode || stamp.isCompatible(value.stamp(NodeView.DEFAULT)) : stamp + " vs. " + value.stamp(NodeView.DEFAULT) + " (" + value + ")";
- map.setAndGrow(value, new InfoElement(stamp, guard, proxiedValue, map.getAndGrow(value)));
- undoOperations.push(value);
- if (value instanceof StampInverter) {
- StampInverter stampInverter = (StampInverter) value;
- value = stampInverter.getValue();
- stamp = stampInverter.invertStamp(stamp);
- } else {
- value = null;
- stamp = null;
- }
- } while (value != null && stamp != null);
+ counterStampsRegistered.increment(debug);
+ debug.log("\t Saving stamp for node %s stamp %s guarded by %s", value, stamp, guard);
+ assert value instanceof LogicNode || stamp.isCompatible(value.stamp(NodeView.DEFAULT)) : stamp + " vs. " + value.stamp(NodeView.DEFAULT) + " (" + value + ")";
+ map.setAndGrow(value, new InfoElement(stamp, guard, proxiedValue, map.getAndGrow(value)));
+ undoOperations.push(value);
+ if (propagateThroughPis && value instanceof PiNode) {
+ PiNode piNode = (PiNode) value;
+ value = piNode.getOriginalNode();
+ } else if (value instanceof StampInverter) {
+ StampInverter stampInverter = (StampInverter) value;
+ value = stampInverter.getValue();
+ stamp = stampInverter.invertStamp(stamp);
+ } else {
+ break;
+ }
}
}
@@ -990,7 +1053,9 @@
if (value.hasMoreThanOneUsage()) {
return true;
} else {
- return value instanceof ProxyNode;
+ return value instanceof ProxyNode ||
+ value instanceof PiNode ||
+ value instanceof StampInverter;
}
}
@@ -1019,14 +1084,19 @@
}
@Override
- public void exit(Block b, Integer state) {
- int mark = state;
- while (undoOperations.size() > mark) {
+ public void exit(Block b, Marks marks) {
+ int infoElementsMark = marks.infoElementOperations;
+ while (undoOperations.size() > infoElementsMark) {
Node node = undoOperations.pop();
if (node.isAlive()) {
map.set(node, map.get(node).getParent());
}
}
+
+ int conditionsMark = marks.conditions;
+ while (conditions.size() > conditionsMark) {
+ conditions.pop();
+ }
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java Thu May 31 10:38:05 2018 -0700
@@ -29,6 +29,7 @@
import org.graalvm.compiler.core.common.GraalOptions;
import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.spi.SimplifierTool;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -178,8 +179,9 @@
AbstractEndNode end = mergeNode.forwardEnds().first();
propagateFixed(end, deopt, loweringProvider);
}
- assert next.isAlive();
- propagateFixed(next, deopt, loweringProvider);
+ if (next.isAlive()) {
+ propagateFixed(next, deopt, loweringProvider);
+ }
return;
} else if (current.predecessor() instanceof IfNode) {
IfNode ifNode = (IfNode) current.predecessor();
@@ -188,7 +190,9 @@
StructuredGraph graph = ifNode.graph();
LogicNode conditionNode = ifNode.condition();
boolean negateGuardCondition = current == ifNode.trueSuccessor();
- FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
+ NodeSourcePosition survivingSuccessorPosition = negateGuardCondition ? ifNode.falseSuccessor().getNodeSourcePosition() : ifNode.trueSuccessor().getNodeSourcePosition();
+ FixedGuardNode guard = graph.add(
+ new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition, survivingSuccessorPosition));
FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
AbstractBeginNode survivingSuccessor;
@@ -223,11 +227,14 @@
}
}
+ @SuppressWarnings("try")
private static void moveAsDeoptAfter(FixedWithNextNode node, StaticDeoptimizingNode deopt) {
- FixedNode next = node.next();
- if (next != deopt.asNode()) {
- node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation())));
- GraphUtil.killCFG(next);
+ try (DebugCloseable position = deopt.asNode().withNodeSourcePosition()) {
+ FixedNode next = node.next();
+ if (next != deopt.asNode()) {
+ node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation())));
+ GraphUtil.killCFG(next);
+ }
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeoptimizationGroupingPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/DeoptimizationGroupingPhase.java Thu May 31 10:38:05 2018 -0700
@@ -27,6 +27,7 @@
import org.graalvm.compiler.core.common.cfg.Loop;
import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
import org.graalvm.compiler.nodes.AbstractMergeNode;
import org.graalvm.compiler.nodes.DynamicDeoptimizeNode;
@@ -52,6 +53,7 @@
public class DeoptimizationGroupingPhase extends BasePhase<MidTierContext> {
@Override
+ @SuppressWarnings("try")
protected void run(StructuredGraph graph, MidTierContext context) {
ControlFlowGraph cfg = null;
for (FrameState fs : graph.getNodes(FrameState.TYPE)) {
@@ -80,8 +82,9 @@
target.replaceAtPredecessor(firstEnd);
exitLoops((AbstractDeoptimizeNode) target, firstEnd, cfg);
-
- merge.setNext(graph.add(new DynamicDeoptimizeNode(reasonActionPhi, speculationPhi)));
+ try (DebugCloseable position = target.withNodeSourcePosition()) {
+ merge.setNext(graph.add(new DynamicDeoptimizeNode(reasonActionPhi, speculationPhi)));
+ }
obsoletes = new LinkedList<>();
obsoletes.add((AbstractDeoptimizeNode) target);
target = merge;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ExpandLogicPhase.java Thu May 31 10:38:05 2018 -0700
@@ -107,64 +107,66 @@
binary.safeDelete();
}
- @SuppressWarnings("try")
private static void processIf(LogicNode x, boolean xNegated, LogicNode y, boolean yNegated, IfNode ifNode, double shortCircuitProbability) {
- try (DebugCloseable context = ifNode.withNodeSourcePosition()) {
- /*
- * this method splits an IfNode, which has a ShortCircuitOrNode as its condition, into
- * two separate IfNodes: if(X) and if(Y)
- *
- * for computing the probabilities P(X) and P(Y), we use two different approaches. The
- * first one assumes that the shortCircuitProbability and the probability on the IfNode
- * were created with each other in mind. If this assumption does not hold, we fall back
- * to another mechanism for computing the probabilities.
- */
- AbstractBeginNode trueTarget = ifNode.trueSuccessor();
- AbstractBeginNode falseTarget = ifNode.falseSuccessor();
+ /*
+ * this method splits an IfNode, which has a ShortCircuitOrNode as its condition, into two
+ * separate IfNodes: if(X) and if(Y)
+ *
+ * for computing the probabilities P(X) and P(Y), we use two different approaches. The first
+ * one assumes that the shortCircuitProbability and the probability on the IfNode were
+ * created with each other in mind. If this assumption does not hold, we fall back to
+ * another mechanism for computing the probabilities.
+ */
+ AbstractBeginNode trueTarget = ifNode.trueSuccessor();
+ AbstractBeginNode falseTarget = ifNode.falseSuccessor();
- // 1st approach
- // assumption: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y))
- double firstIfTrueProbability = shortCircuitProbability;
- double secondIfTrueProbability = sanitizeProbability((ifNode.getTrueSuccessorProbability() - shortCircuitProbability) / (1 - shortCircuitProbability));
- double expectedOriginalIfTrueProbability = firstIfTrueProbability + (1 - firstIfTrueProbability) * secondIfTrueProbability;
+ // 1st approach
+ // assumption: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y))
+ double firstIfTrueProbability = shortCircuitProbability;
+ double secondIfTrueProbability = sanitizeProbability((ifNode.getTrueSuccessorProbability() - shortCircuitProbability) / (1 - shortCircuitProbability));
+ double expectedOriginalIfTrueProbability = firstIfTrueProbability + (1 - firstIfTrueProbability) * secondIfTrueProbability;
- if (!doubleEquals(ifNode.getTrueSuccessorProbability(), expectedOriginalIfTrueProbability)) {
- /*
- * 2nd approach
- *
- * the assumption above did not hold, so we either used an artificial probability as
- * shortCircuitProbability or the ShortCircuitOrNode was moved to some other IfNode.
- *
- * so, we distribute the if's trueSuccessorProbability between the newly generated
- * if nodes according to the shortCircuitProbability. the following invariant is
- * always true in this case: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) *
- * P(Y))
- */
- firstIfTrueProbability = ifNode.getTrueSuccessorProbability() * shortCircuitProbability;
- secondIfTrueProbability = sanitizeProbability(1 - (ifNode.probability(falseTarget) / (1 - firstIfTrueProbability)));
- }
+ if (!doubleEquals(ifNode.getTrueSuccessorProbability(), expectedOriginalIfTrueProbability)) {
+ /*
+ * 2nd approach
+ *
+ * the assumption above did not hold, so we either used an artificial probability as
+ * shortCircuitProbability or the ShortCircuitOrNode was moved to some other IfNode.
+ *
+ * so, we distribute the if's trueSuccessorProbability between the newly generated if
+ * nodes according to the shortCircuitProbability. the following invariant is always
+ * true in this case: P(originalIf.trueSuccessor) == P(X) + ((1 - P(X)) * P(Y))
+ */
+ firstIfTrueProbability = ifNode.getTrueSuccessorProbability() * shortCircuitProbability;
+ secondIfTrueProbability = sanitizeProbability(1 - (ifNode.probability(falseTarget) / (1 - firstIfTrueProbability)));
+ }
- ifNode.clearSuccessors();
- Graph graph = ifNode.graph();
- AbstractMergeNode trueTargetMerge = graph.add(new MergeNode());
- trueTargetMerge.setNext(trueTarget);
- EndNode firstTrueEnd = graph.add(new EndNode());
- EndNode secondTrueEnd = graph.add(new EndNode());
- trueTargetMerge.addForwardEnd(firstTrueEnd);
- trueTargetMerge.addForwardEnd(secondTrueEnd);
- AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd);
- AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd);
- if (yNegated) {
- secondIfTrueProbability = 1.0 - secondIfTrueProbability;
- }
- if (xNegated) {
- firstIfTrueProbability = 1.0 - firstIfTrueProbability;
- }
- AbstractBeginNode secondIf = BeginNode.begin(graph.add(new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfTrueProbability)));
- IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIf : firstTrueTarget, xNegated ? firstTrueTarget : secondIf, firstIfTrueProbability));
- ifNode.replaceAtPredecessor(firstIf);
- ifNode.safeDelete();
+ ifNode.clearSuccessors();
+ Graph graph = ifNode.graph();
+ AbstractMergeNode trueTargetMerge = graph.add(new MergeNode());
+ trueTargetMerge.setNext(trueTarget);
+ EndNode firstTrueEnd = graph.add(new EndNode());
+ EndNode secondTrueEnd = graph.add(new EndNode());
+ trueTargetMerge.addForwardEnd(firstTrueEnd);
+ trueTargetMerge.addForwardEnd(secondTrueEnd);
+ AbstractBeginNode firstTrueTarget = BeginNode.begin(firstTrueEnd);
+ firstTrueTarget.setNodeSourcePosition(trueTarget.getNodeSourcePosition());
+ AbstractBeginNode secondTrueTarget = BeginNode.begin(secondTrueEnd);
+ secondTrueTarget.setNodeSourcePosition(trueTarget.getNodeSourcePosition());
+ if (yNegated) {
+ secondIfTrueProbability = 1.0 - secondIfTrueProbability;
}
+ if (xNegated) {
+ firstIfTrueProbability = 1.0 - firstIfTrueProbability;
+ }
+ IfNode secondIf = new IfNode(y, yNegated ? falseTarget : secondTrueTarget, yNegated ? secondTrueTarget : falseTarget, secondIfTrueProbability);
+ secondIf.setNodeSourcePosition(ifNode.getNodeSourcePosition());
+ AbstractBeginNode secondIfBegin = BeginNode.begin(graph.add(secondIf));
+ secondIfBegin.setNodeSourcePosition(falseTarget.getNodeSourcePosition());
+ IfNode firstIf = graph.add(new IfNode(x, xNegated ? secondIfBegin : firstTrueTarget, xNegated ? firstTrueTarget : secondIfBegin, firstIfTrueProbability));
+ firstIf.setNodeSourcePosition(ifNode.getNodeSourcePosition());
+ ifNode.replaceAtPredecessor(firstIf);
+ ifNode.safeDelete();
}
private static boolean doubleEquals(double a, double b) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java Thu May 31 10:38:05 2018 -0700
@@ -86,6 +86,7 @@
try (DebugCloseable position = guard.withNodeSourcePosition()) {
StructuredGraph graph = guard.graph();
AbstractBeginNode fastPath = graph.add(new BeginNode());
+ fastPath.setNodeSourcePosition(guard.getNoDeoptSuccessorPosition());
@SuppressWarnings("deprecation")
int debugId = useGuardIdAsDebugId ? guard.getId() : DeoptimizeNode.DEFAULT_DEBUG_ID;
DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.getAction(), guard.getReason(), debugId, guard.getSpeculation(), null));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoopSafepointInsertionPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoopSafepointInsertionPhase.java Thu May 31 10:38:05 2018 -0700
@@ -24,6 +24,7 @@
import static org.graalvm.compiler.core.common.GraalOptions.GenLoopSafepoints;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.nodes.LoopBeginNode;
import org.graalvm.compiler.nodes.LoopEndNode;
import org.graalvm.compiler.nodes.SafepointNode;
@@ -43,13 +44,16 @@
}
@Override
+ @SuppressWarnings("try")
protected void run(StructuredGraph graph) {
if (GenLoopSafepoints.getValue(graph.getOptions())) {
for (LoopBeginNode loopBeginNode : graph.getNodes(LoopBeginNode.TYPE)) {
for (LoopEndNode loopEndNode : loopBeginNode.loopEnds()) {
if (loopEndNode.canSafepoint()) {
- SafepointNode safepointNode = graph.add(new SafepointNode());
- graph.addBeforeFixed(loopEndNode, safepointNode);
+ try (DebugCloseable s = loopEndNode.withNodeSourcePosition()) {
+ SafepointNode safepointNode = graph.add(new SafepointNode());
+ graph.addBeforeFixed(loopEndNode, safepointNode);
+ }
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/LoweringPhase.java Thu May 31 10:38:05 2018 -0700
@@ -43,6 +43,7 @@
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeBitMap;
import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.iterators.NodeIterable;
import org.graalvm.compiler.nodeinfo.InputType;
import org.graalvm.compiler.nodeinfo.NodeInfo;
@@ -171,7 +172,7 @@
@Override
public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
- return createGuard(before, condition, deoptReason, action, JavaConstant.NULL_POINTER, false);
+ return createGuard(before, condition, deoptReason, action, JavaConstant.NULL_POINTER, false, null);
}
@Override
@@ -180,7 +181,8 @@
}
@Override
- public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated) {
+ public GuardingNode createGuard(FixedNode before, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, JavaConstant speculation, boolean negated,
+ NodeSourcePosition noDeoptSucccessorPosition) {
StructuredGraph graph = before.graph();
if (OptEliminateGuards.getValue(graph.getOptions())) {
for (Node usage : condition.usages()) {
@@ -190,7 +192,7 @@
}
}
if (!condition.graph().getGuardsStage().allowsFloatingGuards()) {
- FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, speculation, negated));
+ FixedGuardNode fixedGuard = graph.add(new FixedGuardNode(condition, deoptReason, action, speculation, negated, noDeoptSucccessorPosition));
graph.addBeforeFixed(before, fixedGuard);
DummyGuardHandle handle = graph.add(new DummyGuardHandle(fixedGuard));
fixedGuard.lower(this);
@@ -198,7 +200,7 @@
handle.safeDelete();
return result;
} else {
- GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, speculation));
+ GuardNode newGuard = graph.unique(new GuardNode(condition, guardAnchor, deoptReason, action, negated, speculation, noDeoptSucccessorPosition));
if (OptEliminateGuards.getValue(graph.getOptions())) {
activeGuards.markAndGrow(newGuard);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java Thu May 31 10:38:05 2018 -0700
@@ -65,6 +65,7 @@
import org.graalvm.compiler.nodes.CallTargetNode;
import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
import org.graalvm.compiler.nodes.DeoptimizeNode;
+import org.graalvm.compiler.nodes.DeoptimizingGuard;
import org.graalvm.compiler.nodes.EndNode;
import org.graalvm.compiler.nodes.FixedGuardNode;
import org.graalvm.compiler.nodes.FixedNode;
@@ -520,6 +521,7 @@
return listener.getNodes();
}
+ @SuppressWarnings("try")
private static ValueNode finishInlining(Invoke invoke, StructuredGraph graph, FixedNode firstNode, List<ReturnNode> returnNodes, UnwindNode unwindNode, Assumptions inlinedAssumptions,
StructuredGraph inlineGraph) {
FixedNode invokeNode = invoke.asNode();
@@ -548,15 +550,19 @@
// get rid of memory kill
AbstractBeginNode begin = invokeWithException.next();
if (begin instanceof KillingBeginNode) {
- AbstractBeginNode newBegin = new BeginNode();
- graph.addAfterFixed(begin, graph.add(newBegin));
- begin.replaceAtUsages(newBegin);
- graph.removeFixed(begin);
+ try (DebugCloseable position = begin.withNodeSourcePosition()) {
+ AbstractBeginNode newBegin = new BeginNode();
+ graph.addAfterFixed(begin, graph.add(newBegin));
+ begin.replaceAtUsages(newBegin);
+ graph.removeFixed(begin);
+ }
}
} else {
if (unwindNode != null && unwindNode.isAlive()) {
- DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
- unwindNode.replaceAndDelete(deoptimizeNode);
+ try (DebugCloseable position = unwindNode.withNodeSourcePosition()) {
+ DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
+ unwindNode.replaceAndDelete(deoptimizeNode);
+ }
}
}
@@ -710,6 +716,10 @@
posMap.put(pos, callerPos);
}
value.setNodeSourcePosition(callerPos);
+
+ if (value instanceof DeoptimizingGuard) {
+ ((DeoptimizingGuard) value).addCallerToNoDeoptSuccessorPosition(callerPos.getCaller());
+ }
} else {
if (isSubstitution) {
/*
@@ -721,7 +731,7 @@
}
}
}
- assert invokeGraph.verifySourcePositions();
+ assert invokeGraph.verifySourcePositions(false);
}
public static void processMonitorId(FrameState stateAfter, MonitorIdNode monitorIdNode) {
@@ -871,6 +881,7 @@
return frameState.bci == BytecodeFrame.AFTER_EXCEPTION_BCI || (frameState.bci == BytecodeFrame.UNWIND_BCI && !frameState.getMethod().isSynchronized());
}
+ @SuppressWarnings("try")
public static FrameState handleMissingAfterExceptionFrameState(FrameState nonReplaceableFrameState, Invoke invoke, EconomicMap<Node, Node> replacements, boolean alwaysDuplicateStateAfter) {
StructuredGraph graph = nonReplaceableFrameState.graph();
NodeWorkList workList = graph.createNodeWorkList();
@@ -890,9 +901,11 @@
AbstractMergeNode merge = (AbstractMergeNode) fixedStateSplit;
while (merge.isAlive()) {
AbstractEndNode end = merge.forwardEnds().first();
- DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
- end.replaceAtPredecessor(deoptimizeNode);
- GraphUtil.killCFG(end);
+ try (DebugCloseable position = end.withNodeSourcePosition()) {
+ DeoptimizeNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
+ end.replaceAtPredecessor(deoptimizeNode);
+ GraphUtil.killCFG(end);
+ }
}
} else if (fixedStateSplit instanceof ExceptionObjectNode) {
// The target invoke does not have an exception edge. This means that the
@@ -909,12 +922,14 @@
}
handleAfterBciFrameState(newInvoke.stateAfter(), invoke, alwaysDuplicateStateAfter);
} else {
- FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
- if (fixedStateSplit instanceof AbstractBeginNode) {
- deoptimizeNode = BeginNode.begin(deoptimizeNode);
+ try (DebugCloseable position = fixedStateSplit.withNodeSourcePosition()) {
+ FixedNode deoptimizeNode = addDeoptimizeNode(graph, DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler);
+ if (fixedStateSplit instanceof AbstractBeginNode) {
+ deoptimizeNode = BeginNode.begin(deoptimizeNode);
+ }
+ fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
+ GraphUtil.killCFG(fixedStateSplit);
}
- fixedStateSplit.replaceAtPredecessor(deoptimizeNode);
- GraphUtil.killCFG(fixedStateSplit);
}
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/GraphPrinter.java Thu May 31 10:38:05 2018 -0700
@@ -111,7 +111,14 @@
SnippetReflectionProvider snippetReflection = getSnippetReflectionProvider();
if (snippetReflection != null) {
if (constant.getJavaKind() == JavaKind.Object) {
- Object obj = snippetReflection.asObject(Object.class, constant);
+ Object obj = null;
+ /*
+ * Ignore any exceptions on unknown JavaConstant implementations in debugging code.
+ */
+ try {
+ obj = snippetReflection.asObject(Object.class, constant);
+ } catch (Throwable ex) {
+ }
if (obj != null) {
return GraphPrinter.constantToString(obj);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/AbstractProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,271 @@
+/*
+ * 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.processor;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.processing.FilerException;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic.Kind;
+import javax.tools.FileObject;
+import javax.tools.StandardLocation;
+
+/**
+ * {@link javax.annotation.processing.AbstractProcessor} subclass that provides extra functionality.
+ */
+@SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_SUPERCLASS", //
+ reason = "We want this type to be found when someone is writing a new Graal annotation processor")
+public abstract class AbstractProcessor extends javax.annotation.processing.AbstractProcessor {
+
+ /**
+ * Gets the processing environment available to this processor.
+ */
+ public ProcessingEnvironment env() {
+ return processingEnv;
+ }
+
+ private final Map<String, TypeElement> types = new HashMap<>();
+
+ /**
+ * Gets the {@link TypeMirror} for a given class name.
+ *
+ * @throws NoClassDefFoundError if the class cannot be resolved
+ */
+ public TypeMirror getType(String className) {
+ return getTypeElement(className).asType();
+ }
+
+ /**
+ * Gets the {@link TypeMirror} for a given class name.
+ *
+ * @rturn {@code null} if the class cannot be resolved
+ */
+ public TypeMirror getTypeOrNull(String className) {
+ TypeElement element = getTypeElementOrNull(className);
+ if (element == null) {
+ return null;
+ }
+ return element.asType();
+ }
+
+ /**
+ * Gets the {@link TypeElement} for a given class name.
+ *
+ * @throws NoClassDefFoundError if the class cannot be resolved
+ */
+ public TypeElement getTypeElement(String className) {
+ TypeElement type = getTypeElementOrNull(className);
+ if (type == null) {
+ throw new NoClassDefFoundError(className);
+ }
+ return type;
+ }
+
+ /**
+ * Gets the {@link TypeElement} for a given class name.
+ *
+ * @returns {@code null} if the class cannot be resolved
+ */
+ public TypeElement getTypeElementOrNull(String className) {
+ TypeElement type = types.get(className);
+ if (type == null) {
+ type = processingEnv.getElementUtils().getTypeElement(className);
+ if (type == null) {
+ return null;
+ }
+ types.put(className, type);
+ }
+ return type;
+ }
+
+ /**
+ * Converts a given {@link TypeMirror} to a {@link TypeElement}.
+ *
+ * @throws ClassCastException if type cannot be converted to a {@link TypeElement}
+ */
+ public TypeElement asTypeElement(TypeMirror type) {
+ Element element = processingEnv.getTypeUtils().asElement(type);
+ if (element == null) {
+ throw new ClassCastException(type + " cannot be converted to a " + TypeElement.class.getName());
+ }
+ return (TypeElement) element;
+ }
+
+ /**
+ * Regular expression for a qualified class name that assumes package names start with lowercase
+ * and non-package components start with uppercase.
+ */
+ private static final Pattern QUALIFIED_CLASS_NAME_RE = Pattern.compile("(?:[a-z]\\w*\\.)+([A-Z].*)");
+
+ /**
+ * Gets the non-package component of a qualified class name.
+ *
+ * @throws IllegalArgumentException if {@code className} does not match
+ * {@link #QUALIFIED_CLASS_NAME_RE}
+ */
+ public static String getSimpleName(String className) {
+ Matcher m = QUALIFIED_CLASS_NAME_RE.matcher(className);
+ if (m.matches()) {
+ return m.group(1);
+ }
+ throw new IllegalArgumentException("Class name \"" + className + "\" does not match pattern " + QUALIFIED_CLASS_NAME_RE);
+ }
+
+ /**
+ * Gets the package component of a qualified class name.
+ *
+ * @throws IllegalArgumentException if {@code className} does not match
+ * {@link #QUALIFIED_CLASS_NAME_RE}
+ */
+ public static String getPackageName(String className) {
+ String simpleName = getSimpleName(className);
+ return className.substring(0, className.length() - simpleName.length() - 1);
+ }
+
+ /**
+ * Gets the annotation of type {@code annotationType} directly present on {@code element}.
+ *
+ * @return {@code null} if an annotation of type {@code annotationType} is not on
+ * {@code element}
+ */
+ public AnnotationMirror getAnnotation(Element element, TypeMirror annotationType) {
+ List<AnnotationMirror> mirrors = getAnnotations(element, annotationType);
+ return mirrors.isEmpty() ? null : mirrors.get(0);
+ }
+
+ /**
+ * Gets all annotations directly present on {@code element}.
+ */
+ public List<AnnotationMirror> getAnnotations(Element element, TypeMirror typeMirror) {
+ List<AnnotationMirror> result = new ArrayList<>();
+ for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
+ if (processingEnv.getTypeUtils().isSameType(mirror.getAnnotationType(), typeMirror)) {
+ result.add(mirror);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the value of the {@code name} element of {@code annotation} and converts it to a value
+ * of type {@code type}.
+ *
+ * @param type the expected type of the element value. This must be a subclass of one of the
+ * types described by {@link AnnotationValue}.
+ * @throws NoSuchElementException if {@code annotation} has no element named {@code name}
+ * @throws ClassCastException if the value of the specified element cannot be converted to
+ * {@code type}
+ */
+ public static <T> T getAnnotationValue(AnnotationMirror annotation, String name, Class<T> type) {
+ ExecutableElement valueMethod = null;
+ for (ExecutableElement method : ElementFilter.methodsIn(annotation.getAnnotationType().asElement().getEnclosedElements())) {
+ if (method.getSimpleName().toString().equals(name)) {
+ valueMethod = method;
+ break;
+ }
+ }
+
+ if (valueMethod == null) {
+ return null;
+ }
+
+ AnnotationValue value = annotation.getElementValues().get(valueMethod);
+ if (value == null) {
+ value = valueMethod.getDefaultValue();
+ }
+
+ return type.cast(value.getValue());
+ }
+
+ /**
+ * Gets the value of the {@code name} array-typed element of {@code annotation} and converts it
+ * to list of values of type {@code type}.
+ *
+ * @param componentType the expected component type of the element value. This must be a
+ * subclass of one of the types described by {@link AnnotationValue}.
+ * @throws NoSuchElementException if {@code annotation} has no element named {@code name}
+ * @throws ClassCastException if the value of the specified element is not an array whose
+ * components cannot be converted to {@code componentType}
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> List<T> getAnnotationValueList(AnnotationMirror annotation, String name, Class<T> componentType) {
+ List<? extends AnnotationValue> values = getAnnotationValue(annotation, name, List.class);
+ List<T> result = new ArrayList<>();
+
+ if (values != null) {
+ for (AnnotationValue value : values) {
+ result.add(componentType.cast(value.getValue()));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Creates a {@code META-INF/providers/<providerClassName>} file whose contents are a single
+ * line containing {@code serviceClassName}.
+ */
+ public void createProviderFile(String providerClassName, String serviceClassName, Element... originatingElements) {
+ assert originatingElements.length > 0;
+ String filename = "META-INF/providers/" + providerClassName;
+ try {
+ FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, originatingElements);
+ PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
+ writer.println(serviceClassName);
+ writer.close();
+ } catch (IOException e) {
+ processingEnv.getMessager().printMessage(isBug367599(e) ? Kind.NOTE : Kind.ERROR, e.getMessage(), originatingElements[0]);
+ }
+ }
+
+ /**
+ * Determines if a given exception is (most likely) caused by
+ * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
+ */
+ private static boolean isBug367599(Throwable t) {
+ if (t instanceof FilerException) {
+ for (StackTraceElement ste : t.getStackTrace()) {
+ if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
+ // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
+ return true;
+ }
+ }
+ }
+ return t.getCause() != null && isBug367599(t.getCause());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.processor/src/org/graalvm/compiler/processor/SuppressFBWarnings.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,41 @@
+/*
+ * 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.processor;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Used to suppress <a href="http://findbugs.sourceforge.net">FindBugs</a> warnings.
+ */
+@Retention(RetentionPolicy.CLASS)
+@interface SuppressFBWarnings {
+ /**
+ * The set of FindBugs
+ * <a href="http://findbugs.sourceforge.net/bugDescriptions.html">warnings</a> that are to be
+ * suppressed in annotated element. The value can be a bug category, kind or pattern.
+ */
+ java.lang.String[] value();
+
+ String reason();
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64GraphBuilderPlugins.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,20 +29,29 @@
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.SIN;
import static org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation.TAN;
import static org.graalvm.compiler.serviceprovider.GraalServices.JAVA_SPECIFICATION_VERSION;
+import static org.graalvm.compiler.serviceprovider.GraalServices.Java8OrEarlier;
import org.graalvm.compiler.bytecode.BytecodeProvider;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool.RoundingMode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
+import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
+import org.graalvm.compiler.nodes.java.AtomicReadAndAddNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.UnaryOperation;
+import jdk.internal.vm.compiler.word.LocationIdentity;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.ResolvedJavaMethod;
+import sun.misc.Unsafe;
public class AArch64GraphBuilderPlugins {
@@ -56,7 +65,11 @@
registerMathPlugins(invocationPlugins);
registerStringLatin1Plugins(invocationPlugins, bytecodeProvider);
registerStringUTF16Plugins(invocationPlugins, bytecodeProvider);
-
+ registerUnsafeReadAndAddPlugins(invocationPlugins, bytecodeProvider);
+ // This is temporarily disabled until we implement correct emitting of the CAS
+ // instructions of the proper width.
+ StandardGraphBuilderPlugins.registerPlatformSpecificUnsafePlugins(invocationPlugins, bytecodeProvider,
+ new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object});
}
});
}
@@ -107,6 +120,9 @@
return true;
}
});
+ registerRound(r, "rint", RoundingMode.NEAREST);
+ registerRound(r, "ceil", RoundingMode.UP);
+ registerRound(r, "floor", RoundingMode.DOWN);
}
private static void registerUnaryMath(Registration r, String name, UnaryOperation operation) {
@@ -119,6 +135,16 @@
});
}
+ private static void registerRound(Registration r, String name, RoundingMode mode) {
+ r.register1(name, Double.TYPE, new InvocationPlugin() {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) {
+ b.push(JavaKind.Double, b.append(new AArch64RoundNode(arg, mode)));
+ return true;
+ }
+ });
+ }
+
private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
if (JAVA_SPECIFICATION_VERSION >= 9) {
Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider);
@@ -137,4 +163,30 @@
}
}
+ private static void registerUnsafeReadAndAddPlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
+ Registration r;
+ if (Java8OrEarlier) {
+ r = new Registration(plugins, Unsafe.class);
+ } else {
+ r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider);
+ }
+
+ for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
+ Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+
+ if (kind != JavaKind.Object) {
+ r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
+ // Emits a null-check for the otherwise unused receiver
+ unsafe.get();
+ AddressNode address = b.add(new OffsetAddressNode(object, offset));
+ b.addPush(kind, new AtomicReadAndAddNode(address, delta, kind, LocationIdentity.any()));
+ b.getGraph().markUnsafeAccess();
+ return true;
+ }
+ });
+ }
+ }
+ }
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64IntegerArithmeticSnippets.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,7 +25,9 @@
package org.graalvm.compiler.replacements.aarch64;
import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
import org.graalvm.compiler.debug.DebugHandlersFactory;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node.NodeIntrinsic;
@@ -34,7 +37,7 @@
import org.graalvm.compiler.nodes.NodeView;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.FixedBinaryNode;
+import org.graalvm.compiler.nodes.calc.IntegerDivRemNode;
import org.graalvm.compiler.nodes.calc.SignedDivNode;
import org.graalvm.compiler.nodes.calc.SignedRemNode;
import org.graalvm.compiler.nodes.calc.UnsignedDivNode;
@@ -84,7 +87,7 @@
ulrem = snippet(AArch64IntegerArithmeticSnippets.class, "ulremSnippet");
}
- public void lower(FixedBinaryNode node, LoweringTool tool) {
+ public void lower(IntegerDivRemNode node, LoweringTool tool) {
JavaKind kind = node.stamp(NodeView.DEFAULT).getStackKind();
assert kind == JavaKind.Int || kind == JavaKind.Long;
SnippetTemplate.SnippetInfo snippet;
@@ -106,68 +109,88 @@
Arguments args = new Arguments(snippet, graph.getGuardsStage(), tool.getLoweringStage());
args.add("x", node.getX());
args.add("y", node.getY());
+
+ IntegerStamp yStamp = (IntegerStamp) node.getY().stamp(NodeView.DEFAULT);
+ args.addConst("needsZeroCheck", node.getZeroCheck() == null && yStamp.contains(0));
+
template(node, args).instantiate(providers.getMetaAccess(), node, SnippetTemplate.DEFAULT_REPLACER, args);
}
@Snippet
- public static int idivSnippet(int x, int y) {
- checkForZero(y);
+ public static int idivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeDiv(x, y);
}
@Snippet
- public static long ldivSnippet(long x, long y) {
- checkForZero(y);
+ public static long ldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeDiv(x, y);
}
@Snippet
- public static int iremSnippet(int x, int y) {
- checkForZero(y);
+ public static int iremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeRem(x, y);
}
@Snippet
- public static long lremSnippet(long x, long y) {
- checkForZero(y);
+ public static long lremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeRem(x, y);
}
@Snippet
- public static int uidivSnippet(int x, int y) {
- checkForZero(y);
+ public static int uidivSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeUDiv(x, y);
}
@Snippet
- public static long uldivSnippet(long x, long y) {
- checkForZero(y);
+ public static long uldivSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeUDiv(x, y);
}
@Snippet
- public static int uiremSnippet(int x, int y) {
- checkForZero(y);
+ public static int uiremSnippet(int x, int y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeURem(x, y);
}
@Snippet
- public static long ulremSnippet(long x, long y) {
- checkForZero(y);
+ public static long ulremSnippet(long x, long y, @ConstantParameter boolean needsZeroCheck) {
+ if (needsZeroCheck) {
+ checkForZero(y);
+ }
return safeURem(x, y);
}
private static void checkForZero(int y) {
if (y == 0) {
// "/ by zero"
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
+ DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
}
}
private static void checkForZero(long y) {
if (y == 0) {
// "/ by zero"
- DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.ArithmeticException);
+ DeoptimizeNode.deopt(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.ArithmeticException);
}
}
@@ -207,7 +230,7 @@
public static final NodeClass<SafeSignedDivNode> TYPE = NodeClass.create(SafeSignedDivNode.class);
protected SafeSignedDivNode(ValueNode x, ValueNode y) {
- super(TYPE, x, y);
+ super(TYPE, x, y, null);
}
@Override
@@ -223,7 +246,7 @@
public static final NodeClass<SafeSignedRemNode> TYPE = NodeClass.create(SafeSignedRemNode.class);
protected SafeSignedRemNode(ValueNode x, ValueNode y) {
- super(TYPE, x, y);
+ super(TYPE, x, y, null);
}
@Override
@@ -239,7 +262,7 @@
public static final NodeClass<SafeUnsignedDivNode> TYPE = NodeClass.create(SafeUnsignedDivNode.class);
protected SafeUnsignedDivNode(ValueNode x, ValueNode y) {
- super(TYPE, x, y);
+ super(TYPE, x, y, null);
}
@Override
@@ -255,7 +278,7 @@
public static final NodeClass<SafeUnsignedRemNode> TYPE = NodeClass.create(SafeUnsignedRemNode.class);
protected SafeUnsignedRemNode(ValueNode x, ValueNode y) {
- super(TYPE, x, y);
+ super(TYPE, x, y, null);
}
@Override
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.aarch64/src/org/graalvm/compiler/replacements/aarch64/AArch64RoundNode.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,113 @@
+/*
+ * 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.replacements.aarch64;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import org.graalvm.compiler.core.common.type.FloatStamp;
+import org.graalvm.compiler.core.common.type.Stamp;
+import org.graalvm.compiler.debug.GraalError;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.spi.CanonicalizerTool;
+import org.graalvm.compiler.lir.gen.ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool;
+import org.graalvm.compiler.lir.aarch64.AArch64ArithmeticLIRGeneratorTool.RoundingMode;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.ConstantNode;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.UnaryNode;
+import org.graalvm.compiler.nodes.spi.ArithmeticLIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8;
+
+/**
+ * Round floating-point value.
+ */
+@NodeInfo(cycles = CYCLES_8)
+public final class AArch64RoundNode extends UnaryNode implements ArithmeticLIRLowerable {
+ public static final NodeClass<AArch64RoundNode> TYPE = NodeClass.create(AArch64RoundNode.class);
+
+ private final RoundingMode mode;
+
+ public AArch64RoundNode(ValueNode value, RoundingMode mode) {
+ super(TYPE, roundStamp((FloatStamp) value.stamp(NodeView.DEFAULT), mode), value);
+ this.mode = mode;
+ }
+
+ private static double round(RoundingMode mode, double input) {
+ switch (mode) {
+ case DOWN:
+ return Math.floor(input);
+ case NEAREST:
+ return Math.rint(input);
+ case UP:
+ return Math.ceil(input);
+ case TRUNCATE:
+ return (long) input;
+ default:
+ throw GraalError.unimplemented("unimplemented RoundingMode " + mode);
+ }
+ }
+
+ private static FloatStamp roundStamp(FloatStamp stamp, RoundingMode mode) {
+ double min = stamp.lowerBound();
+ min = Math.min(min, round(mode, min));
+
+ double max = stamp.upperBound();
+ max = Math.max(max, round(mode, max));
+
+ return new FloatStamp(stamp.getBits(), min, max, stamp.isNonNaN());
+ }
+
+ @Override
+ public Stamp foldStamp(Stamp newStamp) {
+ assert newStamp.isCompatible(getValue().stamp(NodeView.DEFAULT));
+ return roundStamp((FloatStamp) newStamp, mode);
+ }
+
+ private ValueNode tryFold(ValueNode input) {
+ if (input.isConstant()) {
+ JavaConstant c = input.asJavaConstant();
+ if (c.getJavaKind() == JavaKind.Double) {
+ return ConstantNode.forDouble(round(mode, c.asDouble()));
+ } else if (c.getJavaKind() == JavaKind.Float) {
+ return ConstantNode.forFloat((float) round(mode, c.asFloat()));
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) {
+ ValueNode folded = tryFold(forValue);
+ return folded != null ? folded : this;
+ }
+
+ @Override
+ public void generate(NodeLIRBuilderTool builder, ArithmeticLIRGeneratorTool gen) {
+ builder.setResult(this, ((AArch64ArithmeticLIRGeneratorTool) gen).emitRound(builder.operand(getValue()), mode));
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64GraphBuilderPlugins.java Thu May 31 10:38:05 2018 -0700
@@ -50,6 +50,7 @@
import org.graalvm.compiler.replacements.ArraysSubstitutions;
import org.graalvm.compiler.replacements.IntegerSubstitutions;
import org.graalvm.compiler.replacements.LongSubstitutions;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafeGetPlugin;
import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins.UnsafePutPlugin;
import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
@@ -74,6 +75,8 @@
public void run() {
registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch, replacementsBytecodeProvider);
registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider);
+ StandardGraphBuilderPlugins.registerPlatformSpecificUnsafePlugins(invocationPlugins, replacementsBytecodeProvider,
+ new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object, JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Float, JavaKind.Double});
registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider);
registerStringPlugins(invocationPlugins, arch, replacementsBytecodeProvider);
registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider);
@@ -218,12 +221,16 @@
private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) {
Registration r;
+ JavaKind[] unsafeJavaKinds;
if (Java8OrEarlier) {
r = new Registration(plugins, Unsafe.class);
+ unsafeJavaKinds = new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object};
} else {
r = new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider);
+ unsafeJavaKinds = new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object};
}
- for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
+
+ for (JavaKind kind : unsafeJavaKinds) {
Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
r.register4("getAndSet" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
@@ -236,14 +243,14 @@
return true;
}
});
- if (kind != JavaKind.Object) {
+ if (kind != JavaKind.Boolean && kind.isNumericInteger()) {
r.register4("getAndAdd" + kind.name(), Receiver.class, Object.class, long.class, javaClass, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode delta) {
// Emits a null-check for the otherwise unused receiver
unsafe.get();
AddressNode address = b.add(new OffsetAddressNode(object, offset));
- b.addPush(kind, new AtomicReadAndAddNode(address, delta, LocationIdentity.any()));
+ b.addPush(kind, new AtomicReadAndAddNode(address, delta, kind, LocationIdentity.any()));
b.getGraph().markUnsafeAccess();
return true;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.jdk9.test/src/org/graalvm/compiler/replacements/jdk9/UnsafeReplacementsTest.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,313 @@
+/*
+ * 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.replacements.jdk9;
+
+import jdk.vm.ci.amd64.AMD64;
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import org.graalvm.compiler.api.test.Graal;
+import org.graalvm.compiler.replacements.test.MethodSubstitutionTest;
+import org.graalvm.compiler.runtime.RuntimeProvider;
+import org.graalvm.compiler.test.AddExports;
+import org.junit.Test;
+
+@AddExports("java.base/jdk.internal.misc")
+public class UnsafeReplacementsTest extends MethodSubstitutionTest {
+
+ // See GR-9819.
+ @SuppressWarnings("unused") ResolvedJavaMethod method = null;
+
+ static class Container {
+ public volatile boolean booleanField;
+ public volatile byte byteField = 17;
+ public volatile char charField = 1025;
+ public volatile short shortField = 2232;
+ public volatile int intField = 0xcafebabe;
+ public volatile long longField = 0xdedababafafaL;
+ public volatile float floatField = 0.125f;
+ public volatile double doubleField = 0.125;
+ public volatile Object objectField = dummyValue;
+ }
+
+ static jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
+ static Container dummyValue = new Container();
+ static Container newDummyValue = new Container();
+ static long booleanOffset;
+ static long byteOffset;
+ static long charOffset;
+ static long shortOffset;
+ static long intOffset;
+ static long longOffset;
+ static long floatOffset;
+ static long doubleOffset;
+ static long objectOffset;
+
+ static {
+ try {
+ booleanOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("booleanField"));
+ byteOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("byteField"));
+ charOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("charField"));
+ shortOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("shortField"));
+ intOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("intField"));
+ longOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("longField"));
+ floatOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("floatField"));
+ doubleOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("doubleField"));
+ objectOffset = unsafe.objectFieldOffset(Container.class.getDeclaredField("objectField"));
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static boolean unsafeCompareAndSetBoolean() {
+ Container container = new Container();
+ return unsafe.compareAndSetBoolean(container, booleanOffset, false, true);
+ }
+
+ public static boolean unsafeCompareAndSetByte() {
+ Container container = new Container();
+ return unsafe.compareAndSetByte(container, byteOffset, (byte) 17, (byte) 121);
+ }
+
+ public static boolean unsafeCompareAndSetChar() {
+ Container container = new Container();
+ return unsafe.compareAndSetChar(container, charOffset, (char) 1025, (char) 1777);
+ }
+
+ public static boolean unsafeCompareAndSetShort() {
+ Container container = new Container();
+ return unsafe.compareAndSetShort(container, shortOffset, (short) 2232, (short) 12111);
+ }
+
+ public static boolean unsafeCompareAndSetInt() {
+ Container container = new Container();
+ return unsafe.compareAndSetInt(container, intOffset, 0xcafebabe, 0xbabefafa);
+ }
+
+ public static boolean unsafeCompareAndSetLong() {
+ Container container = new Container();
+ return unsafe.compareAndSetLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL);
+ }
+
+ public static boolean unsafeCompareAndSetFloat() {
+ Container container = new Container();
+ return unsafe.compareAndSetFloat(container, floatOffset, 0.125f, 0.25f);
+ }
+
+ public static boolean unsafeCompareAndSetDouble() {
+ Container container = new Container();
+ return unsafe.compareAndSetDouble(container, doubleOffset, 0.125, 0.25);
+ }
+
+ public static boolean unsafeCompareAndSetObject() {
+ Container container = new Container();
+ return unsafe.compareAndSetObject(container, objectOffset, dummyValue, newDummyValue);
+ }
+
+ public static boolean unsafeCompareAndExchangeBoolean() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeBoolean(container, booleanOffset, false, true);
+ }
+
+ public static byte unsafeCompareAndExchangeByte() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeByte(container, byteOffset, (byte) 17, (byte) 31);
+ }
+
+ public static char unsafeCompareAndExchangeChar() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeChar(container, charOffset, (char) 1025, (char) 4502);
+ }
+
+ public static short unsafeCompareAndExchangeShort() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeShort(container, shortOffset, (short) 2232, (short) 8121);
+ }
+
+ public static int unsafeCompareAndExchangeInt() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeInt(container, intOffset, 0xcafebabe, 0xbabefafa);
+ }
+
+ public static long unsafeCompareAndExchangeLong() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeLong(container, longOffset, 0xdedababafafaL, 0xfafacecafafadedaL);
+ }
+
+ public static float unsafeCompareAndExchangeFloat() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeFloat(container, floatOffset, 0.125f, 0.25f);
+ }
+
+ public static double unsafeCompareAndExchangeDouble() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeDouble(container, doubleOffset, 0.125, 0.25);
+ }
+
+ public static Object unsafeCompareAndExchangeObject() {
+ Container container = new Container();
+ return unsafe.compareAndExchangeObject(container, objectOffset, dummyValue, newDummyValue);
+ }
+
+ @Test
+ public void testCompareAndSet() {
+ TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
+ if (target.arch instanceof AMD64) {
+ testGraph("unsafeCompareAndSetBoolean");
+ testGraph("unsafeCompareAndSetByte");
+ testGraph("unsafeCompareAndSetChar");
+ testGraph("unsafeCompareAndSetShort");
+ testGraph("unsafeCompareAndSetInt");
+ testGraph("unsafeCompareAndSetLong");
+ testGraph("unsafeCompareAndSetFloat");
+ testGraph("unsafeCompareAndSetDouble");
+ testGraph("unsafeCompareAndSetObject");
+ testGraph("unsafeCompareAndExchangeBoolean");
+ testGraph("unsafeCompareAndExchangeByte");
+ testGraph("unsafeCompareAndExchangeChar");
+ testGraph("unsafeCompareAndExchangeShort");
+ testGraph("unsafeCompareAndExchangeInt");
+ testGraph("unsafeCompareAndExchangeLong");
+ testGraph("unsafeCompareAndExchangeFloat");
+ testGraph("unsafeCompareAndExchangeDouble");
+ testGraph("unsafeCompareAndExchangeObject");
+ }
+ test("unsafeCompareAndSetBoolean");
+ test("unsafeCompareAndSetByte");
+ test("unsafeCompareAndSetChar");
+ test("unsafeCompareAndSetShort");
+ test("unsafeCompareAndSetInt");
+ test("unsafeCompareAndSetLong");
+ test("unsafeCompareAndSetFloat");
+ test("unsafeCompareAndSetDouble");
+ test("unsafeCompareAndSetObject");
+ test("unsafeCompareAndExchangeBoolean");
+ test("unsafeCompareAndExchangeByte");
+ test("unsafeCompareAndExchangeChar");
+ test("unsafeCompareAndExchangeShort");
+ test("unsafeCompareAndExchangeInt");
+ test("unsafeCompareAndExchangeLong");
+ test("unsafeCompareAndExchangeFloat");
+ test("unsafeCompareAndExchangeDouble");
+ test("unsafeCompareAndExchangeObject");
+ }
+
+ public static int unsafeGetAndAddByte() {
+ Container container = new Container();
+ return unsafe.getAndAddByte(container, byteOffset, (byte) 2);
+ }
+
+ public static int unsafeGetAndAddChar() {
+ Container container = new Container();
+ return unsafe.getAndAddChar(container, charOffset, (char) 250);
+ }
+
+ public static int unsafeGetAndAddShort() {
+ Container container = new Container();
+ return unsafe.getAndAddShort(container, shortOffset, (short) 1250);
+ }
+
+ public static int unsafeGetAndAddInt() {
+ Container container = new Container();
+ return unsafe.getAndAddInt(container, intOffset, 104501);
+ }
+
+ public static long unsafeGetAndAddLong() {
+ Container container = new Container();
+ return unsafe.getAndAddLong(container, longOffset, 0x123456abcdL);
+ }
+
+ @Test
+ public void testGetAndAdd() {
+ TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
+ if (target.arch instanceof AMD64) {
+ testGraph("unsafeGetAndAddByte");
+ testGraph("unsafeGetAndAddChar");
+ testGraph("unsafeGetAndAddShort");
+ testGraph("unsafeGetAndAddInt");
+ testGraph("unsafeGetAndAddLong");
+ }
+ test("unsafeGetAndAddByte");
+ test("unsafeGetAndAddChar");
+ test("unsafeGetAndAddShort");
+ test("unsafeGetAndAddInt");
+ test("unsafeGetAndAddLong");
+ }
+
+ public static boolean unsafeGetAndSetBoolean() {
+ Container container = new Container();
+ return unsafe.getAndSetBoolean(container, booleanOffset, true);
+ }
+
+ public static byte unsafeGetAndSetByte() {
+ Container container = new Container();
+ return unsafe.getAndSetByte(container, byteOffset, (byte) 129);
+ }
+
+ public static char unsafeGetAndSetChar() {
+ Container container = new Container();
+ return unsafe.getAndSetChar(container, charOffset, (char) 21111);
+ }
+
+ public static short unsafeGetAndSetShort() {
+ Container container = new Container();
+ return unsafe.getAndSetShort(container, shortOffset, (short) 21111);
+ }
+
+ public static int unsafeGetAndSetInt() {
+ Container container = new Container();
+ return unsafe.getAndSetInt(container, intOffset, 0x1234af);
+ }
+
+ public static long unsafeGetAndSetLong() {
+ Container container = new Container();
+ return unsafe.getAndSetLong(container, longOffset, 0x12345678abL);
+ }
+
+ public static Object unsafeGetAndSetObject() {
+ Container container = new Container();
+ container.objectField = null;
+ Container other = new Container();
+ return unsafe.getAndSetObject(container, objectOffset, other);
+ }
+
+ @Test
+ public void testGetAndSet() {
+ TargetDescription target = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend().getTarget();
+ if (target.arch instanceof AMD64) {
+ testGraph("unsafeGetAndSetBoolean");
+ testGraph("unsafeGetAndSetByte");
+ testGraph("unsafeGetAndSetChar");
+ testGraph("unsafeGetAndSetShort");
+ testGraph("unsafeGetAndSetInt");
+ testGraph("unsafeGetAndSetLong");
+ testGraph("unsafeGetAndSetObject");
+ }
+ test("unsafeGetAndSetBoolean");
+ test("unsafeGetAndSetByte");
+ test("unsafeGetAndSetChar");
+ test("unsafeGetAndSetShort");
+ test("unsafeGetAndSetInt");
+ test("unsafeGetAndSetLong");
+ test("unsafeGetAndSetObject");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/META-INF/services/javax.annotation.processing.Processor Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,1 @@
+org.graalvm.compiler.replacements.processor.ReplacementsAnnotationProcessor
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/APHotSpotSignature.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+/**
+ * Pretty much copied from HotSpotSignature but using a different method for resolving types. This
+ * class should be rewritten, its just a quick hack to get signatures working.
+ */
+final class APHotSpotSignature {
+
+ private final List<String> arguments = new ArrayList<>();
+ private final String returnType;
+ private final String originalString;
+ private TypeMirror[] argumentTypes;
+ private TypeMirror returnTypeCache;
+
+ APHotSpotSignature(String signature) {
+ assert signature.length() > 0;
+ this.originalString = signature;
+
+ if (signature.charAt(0) == '(') {
+ int cur = 1;
+ while (cur < signature.length() && signature.charAt(cur) != ')') {
+ int nextCur = parseSignature(signature, cur);
+ arguments.add(signature.substring(cur, nextCur));
+ cur = nextCur;
+ }
+
+ cur++;
+ int nextCur = parseSignature(signature, cur);
+ returnType = signature.substring(cur, nextCur);
+ if (nextCur != signature.length()) {
+ throw new RuntimeException("Invalid trailing characters.");
+ }
+ } else {
+ returnType = null;
+ }
+ }
+
+ private static int parseSignature(String signature, int start) {
+ int cur = start;
+ char first;
+ do {
+ first = signature.charAt(cur++);
+ } while (first == '[');
+
+ switch (first) {
+ case 'L':
+ while (signature.charAt(cur) != ';') {
+ cur++;
+ }
+ cur++;
+ break;
+ case 'V':
+ case 'I':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'F':
+ case 'J':
+ case 'S':
+ case 'Z':
+ break;
+ default:
+ throw new RuntimeException("Invalid character at index " + cur + " in signature: " + signature);
+ }
+ return cur;
+ }
+
+ public int getParameterCount(boolean withReceiver) {
+ return arguments.size() + (withReceiver ? 1 : 0);
+ }
+
+ public TypeMirror getParameterType(ProcessingEnvironment env, int index) {
+ if (argumentTypes == null) {
+ argumentTypes = new TypeMirror[arguments.size()];
+ }
+ TypeMirror type = argumentTypes[index];
+ if (arguments.get(index) == null) {
+ throw new RuntimeException(String.format("Invalid argument at index %s.", index));
+ }
+
+ if (type == null) {
+ argumentTypes[index] = lookupType(env, arguments.get(index));
+ }
+ return argumentTypes[index];
+ }
+
+ private static TypeMirror lookupType(ProcessingEnvironment env, String binaryName) {
+ if (binaryName.length() == 1) {
+ TypeKind kind = fromPrimitiveOrVoidTypeChar(binaryName.charAt(0));
+ if (kind.isPrimitive()) {
+ return env.getTypeUtils().getPrimitiveType(kind);
+ } else if (kind == TypeKind.VOID) {
+ return env.getTypeUtils().getNoType(kind);
+ }
+ }
+
+ String canonicalName = binaryName;
+ if (canonicalName.startsWith("L") && canonicalName.endsWith(";")) {
+ canonicalName = canonicalName.substring(1, canonicalName.length() - 1);
+ }
+ env.getMessager().printMessage(Kind.ERROR, canonicalName);
+
+ int arrayDims = 0;
+ while (canonicalName.startsWith("[")) {
+ canonicalName = canonicalName.substring(1, canonicalName.length());
+ arrayDims++;
+ }
+
+ canonicalName = canonicalName.replaceAll("/", ".");
+ TypeElement typeElement = env.getElementUtils().getTypeElement(canonicalName);
+ if (typeElement == null) {
+ throw new RuntimeException(String.format("Type with name %s not found.", canonicalName));
+ }
+ TypeMirror mirror = typeElement.asType();
+ for (int i = 0; i < arrayDims; i++) {
+ mirror = env.getTypeUtils().getArrayType(mirror);
+ }
+ return mirror;
+ }
+
+ /**
+ * Returns the kind from the character describing a primitive or void.
+ *
+ * @param ch the character
+ * @return the kind
+ */
+ public static TypeKind fromPrimitiveOrVoidTypeChar(char ch) {
+ switch (ch) {
+ case 'Z':
+ return TypeKind.BOOLEAN;
+ case 'C':
+ return TypeKind.CHAR;
+ case 'F':
+ return TypeKind.FLOAT;
+ case 'D':
+ return TypeKind.DOUBLE;
+ case 'B':
+ return TypeKind.BYTE;
+ case 'S':
+ return TypeKind.SHORT;
+ case 'I':
+ return TypeKind.INT;
+ case 'J':
+ return TypeKind.LONG;
+ case 'V':
+ return TypeKind.VOID;
+ }
+ throw new IllegalArgumentException("unknown primitive or void type character: " + ch);
+ }
+
+ public TypeMirror getReturnType(ProcessingEnvironment env) {
+ if (returnTypeCache == null) {
+ if (returnType == null) {
+ throw new RuntimeException("Invalid return type.");
+ }
+ returnTypeCache = lookupType(env, returnType);
+ }
+ return returnTypeCache;
+ }
+
+ @Override
+ public String toString() {
+ return "Signature<" + originalString + ">";
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/AnnotationHandler.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Handles processing of a single annotation type.
+ */
+public abstract class AnnotationHandler {
+
+ protected final AbstractProcessor processor;
+ protected final String annotationTypeName;
+
+ public AnnotationHandler(AbstractProcessor processor, String annotationTypeName) {
+ this.processor = processor;
+ this.annotationTypeName = annotationTypeName;
+ }
+
+ /**
+ * Processes the presence of {@code annotation} on {@code element}.
+ */
+ public abstract void process(Element element, AnnotationMirror annotation, PluginGenerator generator);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ClassSubstitutionHandler.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValue;
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValueList;
+
+import java.util.List;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Handler for the {@value #CLASS_SUBSTITUTION_CLASS_NAME} annotation.
+ */
+public final class ClassSubstitutionHandler extends AnnotationHandler {
+
+ static final String CLASS_SUBSTITUTION_CLASS_NAME = "org.graalvm.compiler.api.replacements.ClassSubstitution";
+
+ public ClassSubstitutionHandler(AbstractProcessor env) {
+ super(env, CLASS_SUBSTITUTION_CLASS_NAME);
+ }
+
+ @Override
+ public void process(Element element, AnnotationMirror classSubstitution, PluginGenerator generator) {
+ if (!element.getKind().isClass()) {
+ assert false : "Element is guaranteed to be a class.";
+ return;
+ }
+ TypeElement type = (TypeElement) element;
+
+ TypeElement substitutionType = resolveOriginalType(processor, type, classSubstitution);
+ if (substitutionType == null) {
+ return;
+ }
+ }
+
+ static TypeElement resolveOriginalType(AbstractProcessor processor, Element sourceElement, AnnotationMirror classSubstition) {
+ TypeMirror type = getAnnotationValue(classSubstition, "value", TypeMirror.class);
+ List<String> classNames = getAnnotationValueList(classSubstition, "className", String.class);
+ boolean optional = getAnnotationValue(classSubstition, "optional", Boolean.class);
+
+ Messager messager = processor.env().getMessager();
+ if (type.getKind() != TypeKind.DECLARED) {
+ messager.printMessage(Kind.ERROR, "The provided class must be a declared type.", sourceElement, classSubstition);
+ return null;
+ }
+
+ if (!classSubstition.getAnnotationType().asElement().equals(((DeclaredType) type).asElement())) {
+ if (classNames.size() != 0) {
+ String msg = "The usage of value and className is exclusive.";
+ messager.printMessage(Kind.ERROR, msg, sourceElement, classSubstition);
+ messager.printMessage(Kind.ERROR, msg, sourceElement, classSubstition);
+ }
+
+ return (TypeElement) ((DeclaredType) type).asElement();
+ }
+
+ if (classNames.size() != 0) {
+ TypeElement typeElement = null;
+ for (String className : classNames) {
+ typeElement = processor.getTypeElementOrNull(className);
+ if (typeElement != null) {
+ break;
+ }
+ }
+ if (typeElement == null && !optional) {
+ messager.printMessage(Kind.ERROR, String.format("None of the classes %s were found on the classpath.", classNames), sourceElement, classSubstition);
+ }
+
+ return typeElement;
+ }
+
+ if (!optional) {
+ messager.printMessage(Kind.ERROR, String.format("No value for 'value' or 'className' provided."), sourceElement, classSubstition);
+ }
+
+ return null;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/FoldHandler.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.processor.AbstractProcessor.getSimpleName;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.type.TypeKind;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Handler for the {@value #FOLD_CLASS_NAME} annotation.
+ */
+public final class FoldHandler extends AnnotationHandler {
+
+ static final String FOLD_CLASS_NAME = "org.graalvm.compiler.api.replacements.Fold";
+ static final String INJECTED_PARAMETER_CLASS_NAME = "org.graalvm.compiler.api.replacements.Fold.InjectedParameter";
+
+ public FoldHandler(AbstractProcessor processor) {
+ super(processor, FOLD_CLASS_NAME);
+ }
+
+ @Override
+ public void process(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+ if (element.getKind() != ElementKind.METHOD) {
+ assert false : "Element is guaranteed to be a method.";
+ return;
+ }
+
+ ExecutableElement foldMethod = (ExecutableElement) element;
+ if (foldMethod.getReturnType().getKind() == TypeKind.VOID) {
+ processor.env().getMessager().printMessage(Kind.ERROR,
+ String.format("A @%s method must not be void as it won't yield a compile-time constant (the reason for supporting folding!).", getSimpleName(FOLD_CLASS_NAME)), element,
+ annotation);
+ } else if (foldMethod.getModifiers().contains(Modifier.PRIVATE)) {
+ processor.env().getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be private.", getSimpleName(FOLD_CLASS_NAME)), element, annotation);
+ } else {
+ generator.addPlugin(new GeneratedFoldPlugin(foldMethod));
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedFoldPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.replacements.processor.FoldHandler.FOLD_CLASS_NAME;
+import static org.graalvm.compiler.replacements.processor.FoldHandler.INJECTED_PARAMETER_CLASS_NAME;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+import org.graalvm.compiler.replacements.processor.InjectedDependencies.WellKnownDependency;
+
+/**
+ * Create graph builder plugins for {@code Fold} methods.
+ */
+public class GeneratedFoldPlugin extends GeneratedPlugin {
+
+ public GeneratedFoldPlugin(ExecutableElement intrinsicMethod) {
+ super(intrinsicMethod);
+ }
+
+ @Override
+ protected TypeElement getAnnotationClass(AbstractProcessor processor) {
+ return processor.getTypeElement(FOLD_CLASS_NAME);
+ }
+
+ @Override
+ public void extraImports(Set<String> imports) {
+ imports.add("jdk.vm.ci.meta.JavaConstant");
+ imports.add("jdk.vm.ci.meta.JavaKind");
+ imports.add("org.graalvm.compiler.nodes.ConstantNode");
+ }
+
+ @Override
+ protected InjectedDependencies createExecute(AbstractProcessor processor, PrintWriter out) {
+ InjectedDependencies deps = new InjectedDependencies();
+ List<? extends VariableElement> params = intrinsicMethod.getParameters();
+
+ int argCount = 0;
+ Object receiver;
+ if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+ receiver = intrinsicMethod.getEnclosingElement();
+ } else {
+ receiver = "arg0";
+ TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
+ constantArgument(processor, out, deps, argCount, type.asType(), argCount);
+ argCount++;
+ }
+
+ int firstArg = argCount;
+ for (VariableElement param : params) {
+ if (processor.getAnnotation(param, processor.getType(INJECTED_PARAMETER_CLASS_NAME)) == null) {
+ constantArgument(processor, out, deps, argCount, param.asType(), argCount);
+ } else {
+ out.printf(" assert checkInjectedArgument(b, args[%d], targetMethod);\n", argCount);
+ out.printf(" %s arg%d = %s;\n", param.asType(), argCount, deps.use(processor, (DeclaredType) param.asType()));
+ }
+ argCount++;
+ }
+
+ Set<String> suppressWarnings = new TreeSet<>();
+ if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
+ suppressWarnings.add("deprecation");
+ }
+ if (hasRawtypeWarning(intrinsicMethod.getReturnType())) {
+ suppressWarnings.add("rawtypes");
+ }
+ for (VariableElement param : params) {
+ if (hasUncheckedWarning(param.asType())) {
+ suppressWarnings.add("unchecked");
+ }
+ }
+ if (suppressWarnings.size() > 0) {
+ out.printf(" @SuppressWarnings({");
+ String sep = "";
+ for (String suppressWarning : suppressWarnings) {
+ out.printf("%s\"%s\"", sep, suppressWarning);
+ sep = ", ";
+ }
+ out.printf("})\n");
+ }
+
+ out.printf(" %s result = %s.%s(", getErasedType(intrinsicMethod.getReturnType()), receiver, intrinsicMethod.getSimpleName());
+ if (argCount > firstArg) {
+ out.printf("arg%d", firstArg);
+ for (int i = firstArg + 1; i < argCount; i++) {
+ out.printf(", arg%d", i);
+ }
+ }
+ out.printf(");\n");
+
+ TypeMirror returnType = intrinsicMethod.getReturnType();
+ switch (returnType.getKind()) {
+ case BOOLEAN:
+ out.printf(" JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n");
+ break;
+ case BYTE:
+ case SHORT:
+ case CHAR:
+ case INT:
+ out.printf(" JavaConstant constant = JavaConstant.forInt(result);\n");
+ break;
+ case LONG:
+ out.printf(" JavaConstant constant = JavaConstant.forLong(result);\n");
+ break;
+ case FLOAT:
+ out.printf(" JavaConstant constant = JavaConstant.forFloat(result);\n");
+ break;
+ case DOUBLE:
+ out.printf(" JavaConstant constant = JavaConstant.forDouble(result);\n");
+ break;
+ case ARRAY:
+ case TYPEVAR:
+ case DECLARED:
+ if (returnType.equals(processor.getType("java.lang.String"))) {
+ out.printf(" JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION));
+ } else {
+ out.printf(" JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(returnType.toString());
+ }
+
+ out.printf(" ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH));
+ out.printf(" b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
+ out.printf(" b.notifyReplacedCall(targetMethod, node);\n");
+ out.printf(" return true;\n");
+
+ return deps;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedNodeIntrinsicPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.replacements.processor.NodeIntrinsicHandler.CONSTANT_NODE_PARAMETER_CLASS_NAME;
+import static org.graalvm.compiler.replacements.processor.NodeIntrinsicHandler.INJECTED_NODE_PARAMETER_CLASS_NAME;
+import static org.graalvm.compiler.replacements.processor.NodeIntrinsicHandler.VALUE_NODE_CLASS_NAME;
+
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Set;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Create graph builder plugins for {@code NodeIntrinsic} methods.
+ */
+public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin {
+
+ private final TypeMirror[] signature;
+
+ public GeneratedNodeIntrinsicPlugin(ExecutableElement intrinsicMethod, TypeMirror[] signature) {
+ super(intrinsicMethod);
+ this.signature = signature;
+ }
+
+ @Override
+ protected TypeElement getAnnotationClass(AbstractProcessor processor) {
+ return processor.getTypeElement(NodeIntrinsicHandler.NODE_INTRINSIC_CLASS_NAME);
+ }
+
+ protected abstract List<? extends VariableElement> getParameters();
+
+ protected abstract void factoryCall(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argCount);
+
+ @Override
+ protected InjectedDependencies createExecute(AbstractProcessor processor, PrintWriter out) {
+ InjectedDependencies deps = new InjectedDependencies();
+
+ List<? extends VariableElement> params = getParameters();
+
+ int idx = 0;
+ for (; idx < params.size(); idx++) {
+ VariableElement param = params.get(idx);
+ if (processor.getAnnotation(param, processor.getType(INJECTED_NODE_PARAMETER_CLASS_NAME)) == null) {
+ break;
+ }
+
+ out.printf(" %s arg%d = %s;\n", param.asType(), idx, deps.use(processor, (DeclaredType) param.asType()));
+ }
+
+ for (int i = 0; i < signature.length; i++, idx++) {
+ if (processor.getAnnotation(intrinsicMethod.getParameters().get(i), processor.getType(CONSTANT_NODE_PARAMETER_CLASS_NAME)) != null) {
+ constantArgument(processor, out, deps, idx, signature[i], i);
+ } else {
+ if (signature[i].equals(processor.getType(VALUE_NODE_CLASS_NAME))) {
+ out.printf(" ValueNode arg%d = args[%d];\n", idx, i);
+ } else {
+ out.printf(" %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
+ }
+ }
+ }
+
+ factoryCall(processor, out, deps, idx);
+
+ return deps;
+ }
+
+ public static class ConstructorPlugin extends GeneratedNodeIntrinsicPlugin {
+
+ private final ExecutableElement constructor;
+
+ public ConstructorPlugin(ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
+ super(intrinsicMethod, signature);
+ this.constructor = constructor;
+ }
+
+ @Override
+ public void extraImports(Set<String> imports) {
+ if (intrinsicMethod.getReturnType().getKind() != TypeKind.VOID) {
+ imports.add("jdk.vm.ci.meta.JavaKind");
+ }
+ }
+
+ @Override
+ protected List<? extends VariableElement> getParameters() {
+ return constructor.getParameters();
+ }
+
+ @Override
+ protected void factoryCall(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argCount) {
+ out.printf(" %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
+ if (argCount > 0) {
+ out.printf("arg0");
+ for (int i = 1; i < argCount; i++) {
+ out.printf(", arg%d", i);
+ }
+ }
+ out.printf(");\n");
+
+ if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) {
+ out.printf(" b.add(node);\n");
+ } else {
+ out.printf(" b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
+ }
+ out.printf(" return true;\n");
+ }
+ }
+
+ public static class CustomFactoryPlugin extends GeneratedNodeIntrinsicPlugin {
+
+ private final ExecutableElement customFactory;
+
+ public CustomFactoryPlugin(ExecutableElement intrinsicMethod, ExecutableElement customFactory, TypeMirror[] signature) {
+ super(intrinsicMethod, signature);
+ this.customFactory = customFactory;
+ }
+
+ @Override
+ public void extraImports(Set<String> imports) {
+ }
+
+ @Override
+ protected List<? extends VariableElement> getParameters() {
+ List<? extends VariableElement> ret = customFactory.getParameters();
+ // remove initial GraphBuilderContext and ResolvedJavaMethod parameters
+ return ret.subList(2, ret.size());
+ }
+
+ @Override
+ protected void factoryCall(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argCount) {
+ out.printf(" return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName());
+ for (int i = 0; i < argCount; i++) {
+ out.printf(", arg%d", i);
+ }
+ out.printf(");\n");
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/GeneratedPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,248 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import java.io.PrintWriter;
+import java.util.Set;
+
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+import org.graalvm.compiler.replacements.processor.InjectedDependencies.Dependency;
+import org.graalvm.compiler.replacements.processor.InjectedDependencies.WellKnownDependency;
+
+public abstract class GeneratedPlugin {
+
+ protected final ExecutableElement intrinsicMethod;
+ private boolean needInjectionProvider;
+
+ private String pluginName;
+
+ public GeneratedPlugin(ExecutableElement intrinsicMethod) {
+ this.intrinsicMethod = intrinsicMethod;
+ this.needInjectionProvider = false;
+ this.pluginName = intrinsicMethod.getEnclosingElement().getSimpleName() + "_" + intrinsicMethod.getSimpleName();
+ }
+
+ protected abstract TypeElement getAnnotationClass(AbstractProcessor processor);
+
+ public String getPluginName() {
+ return pluginName;
+ }
+
+ public void setPluginName(String pluginName) {
+ this.pluginName = pluginName;
+ }
+
+ public void generate(AbstractProcessor processor, PrintWriter out) {
+ out.printf(" // class: %s\n", intrinsicMethod.getEnclosingElement());
+ out.printf(" // method: %s\n", intrinsicMethod);
+ out.printf(" // generated-by: %s\n", getClass().getName());
+ out.printf(" private static final class %s extends GeneratedInvocationPlugin {\n", pluginName);
+ out.printf("\n");
+ out.printf(" @Override\n");
+ out.printf(" public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n");
+ InjectedDependencies deps = createExecute(processor, out);
+ out.printf(" }\n");
+ out.printf(" @Override\n");
+ out.printf(" public Class<? extends Annotation> getSource() {\n");
+ out.printf(" return %s.class;\n", getAnnotationClass(processor).getQualifiedName().toString().replace('$', '.'));
+ out.printf(" }\n");
+
+ createPrivateMembers(processor, out, deps);
+
+ out.printf(" }\n");
+ }
+
+ public void register(PrintWriter out) {
+ out.printf(" plugins.register(new %s(", pluginName);
+ if (needInjectionProvider) {
+ out.printf("injection");
+ }
+ out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
+ if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+ out.printf(", InvocationPlugin.Receiver.class");
+ }
+ for (VariableElement arg : intrinsicMethod.getParameters()) {
+ out.printf(", %s.class", getErasedType(arg.asType()));
+ }
+ out.printf(");\n");
+ }
+
+ public abstract void extraImports(Set<String> imports);
+
+ protected abstract InjectedDependencies createExecute(AbstractProcessor processor, PrintWriter out);
+
+ static String getErasedType(TypeMirror type) {
+ switch (type.getKind()) {
+ case DECLARED:
+ DeclaredType declared = (DeclaredType) type;
+ TypeElement element = (TypeElement) declared.asElement();
+ return element.getQualifiedName().toString();
+ case TYPEVAR:
+ return getErasedType(((TypeVariable) type).getUpperBound());
+ case WILDCARD:
+ return getErasedType(((WildcardType) type).getExtendsBound());
+ case ARRAY:
+ return getErasedType(((ArrayType) type).getComponentType()) + "[]";
+ default:
+ return type.toString();
+ }
+ }
+
+ static boolean hasRawtypeWarning(TypeMirror type) {
+ switch (type.getKind()) {
+ case DECLARED:
+ DeclaredType declared = (DeclaredType) type;
+ return declared.getTypeArguments().size() > 0;
+ case TYPEVAR:
+ return false;
+ case WILDCARD:
+ return false;
+ case ARRAY:
+ return hasRawtypeWarning(((ArrayType) type).getComponentType());
+ default:
+ return false;
+ }
+ }
+
+ static boolean hasUncheckedWarning(TypeMirror type) {
+ switch (type.getKind()) {
+ case DECLARED:
+ DeclaredType declared = (DeclaredType) type;
+ for (TypeMirror typeParam : declared.getTypeArguments()) {
+ if (hasUncheckedWarning(typeParam)) {
+ return true;
+ }
+ }
+ return false;
+ case TYPEVAR:
+ return true;
+ case WILDCARD:
+ return ((WildcardType) type).getExtendsBound() != null;
+ case ARRAY:
+ return hasUncheckedWarning(((ArrayType) type).getComponentType());
+ default:
+ return false;
+ }
+ }
+
+ private void createPrivateMembers(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps) {
+ if (!deps.isEmpty()) {
+ out.printf("\n");
+ for (Dependency dep : deps) {
+ out.printf(" private final %s %s;\n", dep.type, dep.name);
+ }
+
+ out.printf("\n");
+ out.printf(" private %s(InjectionProvider injection) {\n", pluginName);
+ for (Dependency dep : deps) {
+ out.printf(" this.%s = %s;\n", dep.name, dep.inject(processor, intrinsicMethod));
+ }
+ out.printf(" }\n");
+
+ needInjectionProvider = true;
+ }
+ }
+
+ protected static String getReturnKind(ExecutableElement method) {
+ switch (method.getReturnType().getKind()) {
+ case BOOLEAN:
+ case BYTE:
+ case SHORT:
+ case CHAR:
+ case INT:
+ return "Int";
+ case LONG:
+ return "Long";
+ case FLOAT:
+ return "Float";
+ case DOUBLE:
+ return "Double";
+ case VOID:
+ return "Void";
+ case ARRAY:
+ case TYPEVAR:
+ case DECLARED:
+ return "Object";
+ default:
+ throw new IllegalArgumentException(method.getReturnType().toString());
+ }
+ }
+
+ protected static void constantArgument(AbstractProcessor processor, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) {
+ if (hasRawtypeWarning(type)) {
+ out.printf(" @SuppressWarnings({\"rawtypes\"})\n");
+ }
+ out.printf(" %s arg%d;\n", getErasedType(type), argIdx);
+ out.printf(" if (args[%d].isConstant()) {\n", nodeIdx);
+ if (type.equals(processor.getType("jdk.vm.ci.meta.ResolvedJavaType"))) {
+ out.printf(" arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx);
+ } else {
+ switch (type.getKind()) {
+ case BOOLEAN:
+ out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx);
+ break;
+ case BYTE:
+ out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+ break;
+ case CHAR:
+ out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+ break;
+ case SHORT:
+ out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+ break;
+ case INT:
+ out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
+ break;
+ case LONG:
+ out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx);
+ break;
+ case FLOAT:
+ out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx);
+ break;
+ case DOUBLE:
+ out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx);
+ break;
+ case ARRAY:
+ case DECLARED:
+ out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx);
+ break;
+ default:
+ throw new IllegalArgumentException(type.toString());
+ }
+ }
+ out.printf(" } else {\n");
+ out.printf(" assert b.canDeferPlugin(this) : b.getClass().toString();\n");
+ out.printf(" return false;\n");
+ out.printf(" }\n");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/InjectedDependencies.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValue;
+import static org.graalvm.compiler.replacements.processor.NodeIntrinsicHandler.NODE_INTRINSIC_CLASS_NAME;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+import org.graalvm.compiler.replacements.processor.InjectedDependencies.Dependency;
+
+public class InjectedDependencies implements Iterable<Dependency> {
+
+ public abstract static class Dependency {
+
+ public final String name;
+ public final String type;
+
+ private Dependency(String name, String type) {
+ this.name = name;
+ this.type = type;
+ }
+
+ public abstract String inject(AbstractProcessor processor, ExecutableElement inject);
+ }
+
+ private static final class InjectedDependency extends Dependency {
+
+ private InjectedDependency(String name, String type) {
+ super(name, type);
+ }
+
+ @Override
+ public String inject(AbstractProcessor processor, ExecutableElement inject) {
+ return String.format("injection.getInjectedArgument(%s.class)", type);
+ }
+ }
+
+ private static final class InjectedStampDependency extends Dependency {
+
+ private InjectedStampDependency() {
+ super("stamp", "org.graalvm.compiler.core.common.type.Stamp");
+ }
+
+ @Override
+ public String inject(AbstractProcessor processor, ExecutableElement inject) {
+ AnnotationMirror nodeIntrinsic = processor.getAnnotation(inject, processor.getType(NODE_INTRINSIC_CLASS_NAME));
+ boolean nonNull = nodeIntrinsic != null && getAnnotationValue(nodeIntrinsic, "injectedStampIsNonNull", Boolean.class);
+ return String.format("injection.getInjectedStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nonNull);
+ }
+ }
+
+ public enum WellKnownDependency {
+ CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
+ META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
+ INJECTED_STAMP(new InjectedStampDependency()),
+ SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "org.graalvm.compiler.api.replacements.SnippetReflectionProvider")),
+ STAMP_PROVIDER("b.getStampProvider()", "org.graalvm.compiler.nodes.spi.StampProvider"),
+ STRUCTURED_GRAPH("b.getGraph()", "org.graalvm.compiler.nodes.StructuredGraph");
+
+ private final String expr;
+ private final String type;
+ private final Dependency generateMember;
+
+ WellKnownDependency(String expr, String type) {
+ this.expr = expr;
+ this.type = type;
+ this.generateMember = null;
+ }
+
+ WellKnownDependency(Dependency generateMember) {
+ this.expr = generateMember.name;
+ this.type = generateMember.type;
+ this.generateMember = generateMember;
+ }
+
+ private TypeMirror getType(AbstractProcessor processor) {
+ return processor.getType(type);
+ }
+ }
+
+ private final HashMap<String, Dependency> deps;
+
+ public InjectedDependencies() {
+ deps = new HashMap<>();
+ }
+
+ public String use(WellKnownDependency wellKnown) {
+ if (wellKnown.generateMember != null) {
+ deps.put(wellKnown.type, wellKnown.generateMember);
+ }
+ return wellKnown.expr;
+ }
+
+ public String use(AbstractProcessor processor, DeclaredType type) {
+ for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
+ if (processor.env().getTypeUtils().isAssignable(wellKnown.getType(processor), type)) {
+ return use(wellKnown);
+ }
+ }
+
+ String typeName = type.toString();
+ Dependency ret = deps.get(typeName);
+ if (ret == null) {
+ ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
+ deps.put(typeName, ret);
+ }
+ return ret.name;
+ }
+
+ @Override
+ public Iterator<Dependency> iterator() {
+ return deps.values().iterator();
+ }
+
+ public boolean isEmpty() {
+ return deps.isEmpty();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/MethodSubstitutionHandler.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValue;
+import static org.graalvm.compiler.processor.AbstractProcessor.getSimpleName;
+import static org.graalvm.compiler.replacements.processor.ClassSubstitutionHandler.CLASS_SUBSTITUTION_CLASS_NAME;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.Name;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Handler for the {@value #METHOD_SUBSTITUTION_CLASS_NAME} annotation.
+ */
+public final class MethodSubstitutionHandler extends AnnotationHandler {
+
+ private static final String METHOD_SUBSTITUTION_CLASS_NAME = "org.graalvm.compiler.api.replacements.MethodSubstitution";
+
+ private static final boolean DEBUG = false;
+
+ private static final String ORIGINAL_METHOD_NAME = "value";
+ private static final String ORIGINAL_IS_STATIC = "isStatic";
+ private static final String ORIGINAL_SIGNATURE = "signature";
+
+ private static final String ORIGINAL_METHOD_NAME_DEFAULT = "";
+ private static final String ORIGINAL_SIGNATURE_DEFAULT = "";
+
+ public MethodSubstitutionHandler(AbstractProcessor processor) {
+ super(processor, METHOD_SUBSTITUTION_CLASS_NAME);
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ public void process(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+ if (element.getKind() != ElementKind.METHOD) {
+ assert false : "Element is guaranteed to be a method.";
+ return;
+ }
+ ExecutableElement substitutionMethod = (ExecutableElement) element;
+ TypeElement substitutionType = findEnclosingClass(substitutionMethod);
+ assert substitutionType != null;
+
+ Messager messager = processor.env().getMessager();
+ AnnotationMirror substitutionClassAnnotation = processor.getAnnotation(substitutionType, processor.getType(CLASS_SUBSTITUTION_CLASS_NAME));
+ if (substitutionClassAnnotation == null) {
+ messager.printMessage(Kind.ERROR, String.format("A @%s annotation is required on the enclosing class.", getSimpleName(CLASS_SUBSTITUTION_CLASS_NAME)), element, annotation);
+ return;
+ }
+ boolean optional = getAnnotationValue(substitutionClassAnnotation, "optional", Boolean.class);
+ if (optional) {
+ return;
+ }
+
+ TypeElement originalType = ClassSubstitutionHandler.resolveOriginalType(processor, substitutionType, substitutionClassAnnotation);
+ if (originalType == null) {
+ messager.printMessage(Kind.ERROR, String.format("The @%s annotation is invalid on the enclosing class.", getSimpleName(CLASS_SUBSTITUTION_CLASS_NAME)), element, annotation);
+ return;
+ }
+
+ if (!substitutionMethod.getModifiers().contains(Modifier.STATIC)) {
+ messager.printMessage(Kind.ERROR, String.format("A @%s method must be static.", getSimpleName(METHOD_SUBSTITUTION_CLASS_NAME)), element, annotation);
+ }
+
+ if (substitutionMethod.getModifiers().contains(Modifier.ABSTRACT) || substitutionMethod.getModifiers().contains(Modifier.NATIVE)) {
+ messager.printMessage(Kind.ERROR, String.format("A @%s method must not be native or abstract.", getSimpleName(METHOD_SUBSTITUTION_CLASS_NAME)), element, annotation);
+ }
+
+ String originalName = originalName(substitutionMethod, annotation);
+ boolean isStatic = getAnnotationValue(annotation, ORIGINAL_IS_STATIC, Boolean.class);
+ TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation, isStatic);
+ if (originalSignature == null) {
+ return;
+ }
+ ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature, isStatic);
+ if (DEBUG && originalMethod != null) {
+ messager.printMessage(Kind.NOTE, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
+ }
+ }
+
+ private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation, boolean isStatic) {
+ String signatureString = getAnnotationValue(annotation, ORIGINAL_SIGNATURE, String.class);
+ List<TypeMirror> parameters = new ArrayList<>();
+ Messager messager = processor.env().getMessager();
+ if (signatureString.equals(ORIGINAL_SIGNATURE_DEFAULT)) {
+ for (int i = 0; i < method.getParameters().size(); i++) {
+ parameters.add(method.getParameters().get(i).asType());
+ }
+ if (!isStatic) {
+ if (parameters.isEmpty()) {
+ messager.printMessage(Kind.ERROR, "Method signature must be a static method with the 'this' object as its first parameter", method, annotation);
+ return null;
+ } else {
+ TypeMirror thisParam = parameters.remove(0);
+ if (!isSubtype(originalType.asType(), thisParam)) {
+ Name thisName = method.getParameters().get(0).getSimpleName();
+ messager.printMessage(Kind.ERROR, String.format("The type of %s must assignable from %s", thisName, originalType), method, annotation);
+ }
+ }
+ }
+ parameters.add(0, method.getReturnType());
+ } else {
+ try {
+ APHotSpotSignature signature = new APHotSpotSignature(signatureString);
+ parameters.add(signature.getReturnType(processor.env()));
+ for (int i = 0; i < signature.getParameterCount(false); i++) {
+ parameters.add(signature.getParameterType(processor.env(), i));
+ }
+ } catch (Exception e) {
+ /*
+ * That's not good practice and should be changed after APHotSpotSignature has
+ * received a cleanup.
+ */
+ messager.printMessage(Kind.ERROR, String.format("Parsing the signature failed: %s", e.getMessage() != null ? e.getMessage() : e.toString()), method, annotation);
+ return null;
+ }
+ }
+ return parameters.toArray(new TypeMirror[parameters.size()]);
+ }
+
+ private static String originalName(ExecutableElement substituteMethod, AnnotationMirror substitution) {
+ String originalMethodName = getAnnotationValue(substitution, ORIGINAL_METHOD_NAME, String.class);
+ if (originalMethodName.equals(ORIGINAL_METHOD_NAME_DEFAULT)) {
+ originalMethodName = substituteMethod.getSimpleName().toString();
+ }
+ return originalMethodName;
+ }
+
+ private ExecutableElement originalMethod(ExecutableElement substitutionMethod, AnnotationMirror substitutionAnnotation, TypeElement originalType, String originalName,
+ TypeMirror[] originalSignature, boolean isStatic) {
+ TypeMirror signatureReturnType = originalSignature[0];
+ TypeMirror[] signatureParameters = Arrays.copyOfRange(originalSignature, 1, originalSignature.length);
+ List<ExecutableElement> searchElements;
+ if (originalName.equals("<init>")) {
+ searchElements = ElementFilter.constructorsIn(originalType.getEnclosedElements());
+ } else {
+ searchElements = ElementFilter.methodsIn(originalType.getEnclosedElements());
+ }
+
+ Messager messager = processor.env().getMessager();
+ ExecutableElement originalMethod = null;
+ outer: for (ExecutableElement searchElement : searchElements) {
+ if (searchElement.getSimpleName().toString().equals(originalName) && searchElement.getParameters().size() == signatureParameters.length) {
+ for (int i = 0; i < signatureParameters.length; i++) {
+ VariableElement parameter = searchElement.getParameters().get(i);
+ if (!isTypeCompatible(parameter.asType(), signatureParameters[i])) {
+ continue outer;
+ }
+ }
+ originalMethod = searchElement;
+ break;
+ }
+ }
+ if (originalMethod == null) {
+ boolean optional = getAnnotationValue(substitutionAnnotation, "optional", Boolean.class);
+ if (!optional) {
+ messager.printMessage(Kind.ERROR,
+ String.format("Could not find the original method with name '%s' and parameters '%s'.", originalName, Arrays.toString(signatureParameters)),
+ substitutionMethod, substitutionAnnotation);
+ }
+ return null;
+ }
+
+ if (originalMethod.getModifiers().contains(Modifier.STATIC) != isStatic) {
+ boolean optional = getAnnotationValue(substitutionAnnotation, "optional", Boolean.class);
+ if (!optional) {
+ messager.printMessage(Kind.ERROR, String.format("The %s element must be set to %s.", ORIGINAL_IS_STATIC, !isStatic), substitutionMethod, substitutionAnnotation);
+ }
+ return null;
+ }
+
+ if (!isTypeCompatible(originalMethod.getReturnType(), signatureReturnType)) {
+ messager.printMessage(
+ Kind.ERROR,
+ String.format("The return type of the substitution method '%s' must match with the return type of the original method '%s'.", signatureReturnType,
+ originalMethod.getReturnType()),
+ substitutionMethod, substitutionAnnotation);
+ return null;
+ }
+
+ return originalMethod;
+ }
+
+ private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
+ TypeMirror original = originalType;
+ TypeMirror substitution = substitutionType;
+ if (needsErasure(original)) {
+ original = processor.env().getTypeUtils().erasure(original);
+ }
+ if (needsErasure(substitution)) {
+ substitution = processor.env().getTypeUtils().erasure(substitution);
+ }
+ return processor.env().getTypeUtils().isSameType(original, substitution);
+ }
+
+ /**
+ * Tests whether one type is a subtype of another. Any type is considered to be a subtype of
+ * itself.
+ *
+ * @param t1 the first type
+ * @param t2 the second type
+ * @return {@code true} if and only if the first type is a subtype of the second
+ */
+ private boolean isSubtype(TypeMirror t1, TypeMirror t2) {
+ TypeMirror t1Erased = t1;
+ TypeMirror t2Erased = t2;
+ if (needsErasure(t1Erased)) {
+ t1Erased = processor.env().getTypeUtils().erasure(t1Erased);
+ }
+ if (needsErasure(t2Erased)) {
+ t2Erased = processor.env().getTypeUtils().erasure(t2Erased);
+ }
+ return processor.env().getTypeUtils().isSubtype(t1Erased, t2Erased);
+ }
+
+ private static boolean needsErasure(TypeMirror typeMirror) {
+ return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
+ typeMirror.getKind() != TypeKind.NULL;
+ }
+
+ private static TypeElement findEnclosingClass(Element element) {
+ if (element.getKind().isClass()) {
+ return (TypeElement) element;
+ }
+
+ Element enclosing = element.getEnclosingElement();
+ while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+ if (enclosing.getKind().isClass()) {
+ return (TypeElement) enclosing;
+ }
+ enclosing = enclosing.getEnclosingElement();
+ }
+ return null;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/NodeIntrinsicHandler.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2014, 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.replacements.processor;
+
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValue;
+import static org.graalvm.compiler.processor.AbstractProcessor.getAnnotationValueList;
+import static org.graalvm.compiler.processor.AbstractProcessor.getSimpleName;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.processing.Messager;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.util.ElementFilter;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Handler for the {@value #NODE_INFO_CLASS_NAME} annotation.
+ */
+public final class NodeIntrinsicHandler extends AnnotationHandler {
+
+ static final String CONSTANT_NODE_PARAMETER_CLASS_NAME = "org.graalvm.compiler.graph.Node.ConstantNodeParameter";
+ static final String MARKER_TYPE_CLASS_NAME = "org.graalvm.compiler.nodeinfo.StructuralInput.MarkerType";
+ static final String GRAPH_BUILDER_CONTEXT_CLASS_NAME = "org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext";
+ static final String STRUCTURAL_INPUT_CLASS_NAME = "org.graalvm.compiler.nodeinfo.StructuralInput";
+ static final String RESOLVED_JAVA_METHOD_CLASS_NAME = "jdk.vm.ci.meta.ResolvedJavaMethod";
+ static final String RESOLVED_JAVA_TYPE_CLASS_NAME = "jdk.vm.ci.meta.ResolvedJavaType";
+ static final String VALUE_NODE_CLASS_NAME = "org.graalvm.compiler.nodes.ValueNode";
+ static final String STAMP_CLASS_NAME = "org.graalvm.compiler.core.common.type.Stamp";
+ static final String NODE_CLASS_NAME = "org.graalvm.compiler.graph.Node";
+ static final String NODE_INFO_CLASS_NAME = "org.graalvm.compiler.nodeinfo.NodeInfo";
+ static final String NODE_INTRINSIC_CLASS_NAME = "org.graalvm.compiler.graph.Node.NodeIntrinsic";
+ static final String INJECTED_NODE_PARAMETER_CLASS_NAME = "org.graalvm.compiler.graph.Node.InjectedNodeParameter";
+
+ public NodeIntrinsicHandler(AbstractProcessor processor) {
+ super(processor, NODE_INTRINSIC_CLASS_NAME);
+ }
+
+ @Override
+ public void process(Element element, AnnotationMirror annotation, PluginGenerator generator) {
+ if (element.getKind() != ElementKind.METHOD) {
+ assert false : "Element is guaranteed to be a method.";
+ return;
+ }
+
+ ExecutableElement intrinsicMethod = (ExecutableElement) element;
+ Messager messager = processor.env().getMessager();
+ if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
+ messager.printMessage(Kind.ERROR, String.format("A @%s method must be static.", getSimpleName(NODE_INTRINSIC_CLASS_NAME)), element, annotation);
+ }
+ if (!intrinsicMethod.getModifiers().contains(Modifier.NATIVE)) {
+ messager.printMessage(Kind.ERROR, String.format("A @%s method must be native.", getSimpleName(NODE_INTRINSIC_CLASS_NAME)), element, annotation);
+ }
+
+ TypeMirror nodeClassMirror = getAnnotationValue(annotation, "value", TypeMirror.class);
+ TypeElement nodeClass = processor.asTypeElement(nodeClassMirror);
+ if (processor.env().getTypeUtils().isSameType(nodeClassMirror, annotation.getAnnotationType())) {
+ // default value
+ Element enclosingElement = intrinsicMethod.getEnclosingElement();
+ while (enclosingElement != null && enclosingElement.getKind() != ElementKind.CLASS) {
+ enclosingElement = enclosingElement.getEnclosingElement();
+ }
+ if (enclosingElement != null) {
+ nodeClass = (TypeElement) enclosingElement;
+ }
+ }
+
+ TypeMirror returnType = intrinsicMethod.getReturnType();
+ if (returnType instanceof TypeVariable) {
+ messager.printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
+ }
+
+ boolean injectedStampIsNonNull = getAnnotationValue(annotation, "injectedStampIsNonNull", Boolean.class);
+
+ if (returnType.getKind() == TypeKind.VOID) {
+ for (VariableElement parameter : intrinsicMethod.getParameters()) {
+ if (processor.getAnnotation(parameter, processor.getType(INJECTED_NODE_PARAMETER_CLASS_NAME)) != null) {
+ messager.printMessage(Kind.ERROR, "@NodeIntrinsic with an injected Stamp parameter cannot have a void return type.", element, annotation);
+ break;
+ }
+ }
+ }
+
+ TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
+ Map<ExecutableElement, String> nonMatches = new HashMap<>();
+ List<ExecutableElement> factories = findIntrinsifyFactoryMethod(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull);
+ List<ExecutableElement> constructors = Collections.emptyList();
+ if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
+ if (factories.isEmpty()) {
+ messager.printMessage(Kind.ERROR, String.format("Cannot make a node intrinsic for abstract class %s.", nodeClass.getSimpleName()), element, annotation);
+ }
+ } else if (!isNodeType(nodeClass)) {
+ if (factories.isEmpty()) {
+ messager.printMessage(Kind.ERROR, String.format("%s is not a subclass of %s.", nodeClass.getSimpleName(), processor.getType(NODE_CLASS_NAME)), element, annotation);
+ }
+ } else {
+ TypeMirror ret = returnType;
+ if (processor.env().getTypeUtils().isAssignable(ret, processor.getType(STRUCTURAL_INPUT_CLASS_NAME))) {
+ checkInputType(nodeClass, ret, element, annotation);
+ }
+
+ constructors = findConstructors(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull);
+ }
+ Formatter msg = new Formatter();
+ if (factories.size() > 1) {
+ msg.format("Found more than one factory in %s matching node intrinsic:", nodeClass);
+ for (ExecutableElement candidate : factories) {
+ msg.format("%n %s", candidate);
+ }
+ messager.printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
+ } else if (constructors.size() > 1) {
+ msg.format("Found more than one constructor in %s matching node intrinsic:", nodeClass);
+ for (ExecutableElement candidate : constructors) {
+ msg.format("%n %s", candidate);
+ }
+ messager.printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
+ } else if (factories.size() == 1) {
+ generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, factories.get(0), constructorSignature));
+ } else if (constructors.size() == 1) {
+ generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructors.get(0), constructorSignature));
+ } else {
+ msg.format("Could not find any factories or constructors in %s matching node intrinsic", nodeClass);
+ if (!nonMatches.isEmpty()) {
+ msg.format("%nFactories and constructors that failed to match:");
+ for (Map.Entry<ExecutableElement, String> e : nonMatches.entrySet()) {
+ msg.format("%n %s: %s", e.getKey(), e.getValue());
+ }
+ }
+ messager.printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
+ }
+ }
+
+ private void checkInputType(TypeElement nodeClass, TypeMirror returnType, Element element, AnnotationMirror annotation) {
+ String inputType = getInputType(returnType, element, annotation);
+ if (!inputType.equals("Value")) {
+ boolean allowed = false;
+ List<VariableElement> allowedTypes = getAnnotationValueList(processor.getAnnotation(nodeClass, processor.getType(NODE_INFO_CLASS_NAME)), "allowedUsageTypes", VariableElement.class);
+ for (VariableElement allowedType : allowedTypes) {
+ if (allowedType.getSimpleName().contentEquals(inputType)) {
+ allowed = true;
+ break;
+ }
+ }
+ if (!allowed) {
+ processor.env().getMessager().printMessage(Kind.ERROR, String.format("@NodeIntrinsic returns input type %s, but only %s is allowed.", inputType, allowedTypes), element, annotation);
+ }
+ }
+ }
+
+ private String getInputType(TypeMirror type, Element element, AnnotationMirror annotation) {
+ TypeElement current = processor.asTypeElement(type);
+ while (current != null) {
+ AnnotationMirror markerType = processor.getAnnotation(current, processor.getType(MARKER_TYPE_CLASS_NAME));
+ if (markerType != null) {
+ return getAnnotationValue(markerType, "value", VariableElement.class).getSimpleName().toString();
+ }
+
+ current = processor.asTypeElement(current.getSuperclass());
+ }
+
+ processor.env().getMessager().printMessage(Kind.ERROR,
+ String.format("The class %s is a subclass of StructuralInput, but isn't annotated with @MarkerType. %s", type, element.getAnnotationMirrors()),
+ element, annotation);
+ return "Value";
+ }
+
+ private boolean isNodeType(TypeElement nodeClass) {
+ return processor.env().getTypeUtils().isSubtype(nodeClass.asType(), processor.getType(NODE_CLASS_NAME));
+ }
+
+ private TypeMirror[] constructorSignature(ExecutableElement method) {
+ TypeMirror[] parameters = new TypeMirror[method.getParameters().size()];
+ for (int i = 0; i < method.getParameters().size(); i++) {
+ VariableElement parameter = method.getParameters().get(i);
+ if (processor.getAnnotation(parameter, processor.getType(CONSTANT_NODE_PARAMETER_CLASS_NAME)) == null) {
+ parameters[i] = processor.getType(VALUE_NODE_CLASS_NAME);
+ } else {
+ TypeMirror type = parameter.asType();
+ if (isTypeCompatible(type, processor.getType("java.lang.Class"))) {
+ type = processor.getType(RESOLVED_JAVA_TYPE_CLASS_NAME);
+ }
+ parameters[i] = type;
+ }
+ }
+ return parameters;
+ }
+
+ private List<ExecutableElement> findConstructors(TypeElement nodeClass, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
+ List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
+ List<ExecutableElement> found = new ArrayList<>(constructors.size());
+ for (ExecutableElement constructor : constructors) {
+ if (matchSignature(0, constructor, signature, nonMatches, requiresInjectedStamp)) {
+ found.add(constructor);
+ }
+ }
+ return found;
+ }
+
+ private List<ExecutableElement> findIntrinsifyFactoryMethod(TypeElement nodeClass, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
+ List<ExecutableElement> methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements());
+ List<ExecutableElement> found = new ArrayList<>(methods.size());
+ for (ExecutableElement method : methods) {
+ if (!method.getSimpleName().toString().equals("intrinsify")) {
+ continue;
+ }
+
+ if (method.getParameters().size() < 2) {
+ continue;
+ }
+
+ VariableElement firstArg = method.getParameters().get(0);
+ if (!isTypeCompatible(firstArg.asType(), processor.getType(GRAPH_BUILDER_CONTEXT_CLASS_NAME))) {
+ continue;
+ }
+
+ VariableElement secondArg = method.getParameters().get(1);
+ if (!isTypeCompatible(secondArg.asType(), processor.getType(RESOLVED_JAVA_METHOD_CLASS_NAME))) {
+ continue;
+ }
+
+ if (method.getReturnType().getKind() != TypeKind.BOOLEAN) {
+ continue;
+ }
+
+ if (matchSignature(2, method, signature, nonMatches, requiresInjectedStamp)) {
+ found.add(method);
+ }
+ }
+ return found;
+ }
+
+ private boolean matchSignature(int numSkippedParameters, ExecutableElement method, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
+ int sIdx = 0;
+ int cIdx = numSkippedParameters;
+ boolean missingStampArgument = requiresInjectedStamp;
+ while (cIdx < method.getParameters().size()) {
+ VariableElement parameter = method.getParameters().get(cIdx++);
+ TypeMirror paramType = parameter.asType();
+ if (processor.getAnnotation(parameter, processor.getType(INJECTED_NODE_PARAMETER_CLASS_NAME)) != null) {
+ if (missingStampArgument && processor.env().getTypeUtils().isSameType(paramType, processor.getType(STAMP_CLASS_NAME))) {
+ missingStampArgument = false;
+ }
+ // skip injected parameters
+ continue;
+ }
+ if (missingStampArgument) {
+ nonMatches.put(method, String.format("missing injected %s argument", processor.getType(STAMP_CLASS_NAME)));
+ return false;
+ }
+
+ if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
+ // last argument of constructor is varargs, match remaining intrinsic arguments
+ TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
+ while (sIdx < signature.length) {
+ if (!isTypeCompatible(varargsType, signature[sIdx++])) {
+ nonMatches.put(method, String.format("the types of argument %d are incompatible: %s != %s", sIdx, varargsType, signature[sIdx - 1]));
+ return false;
+ }
+ }
+ } else if (sIdx >= signature.length) {
+ // too many arguments in intrinsic method
+ nonMatches.put(method, "too many arguments");
+ return false;
+ } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
+ nonMatches.put(method, String.format("the type of argument %d is incompatible: %s != %s", sIdx, paramType, signature[sIdx - 1]));
+ return false;
+ }
+ }
+ if (missingStampArgument) {
+ nonMatches.put(method, String.format("missing injected %s argument", processor.getType(STAMP_CLASS_NAME)));
+ return false;
+ }
+
+ if (sIdx != signature.length) {
+ nonMatches.put(method, "not enough arguments");
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
+ TypeMirror original = originalType;
+ TypeMirror substitution = substitutionType;
+ if (needsErasure(original)) {
+ original = processor.env().getTypeUtils().erasure(original);
+ }
+ if (needsErasure(substitution)) {
+ substitution = processor.env().getTypeUtils().erasure(substitution);
+ }
+ return processor.env().getTypeUtils().isSameType(original, substitution);
+ }
+
+ private static boolean needsErasure(TypeMirror typeMirror) {
+ return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
+ typeMirror.getKind() != TypeKind.NULL;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/PluginGenerator.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.DeclaredType;
+import javax.lang.model.type.TypeMirror;
+import javax.lang.model.type.TypeVariable;
+import javax.lang.model.type.WildcardType;
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+public class PluginGenerator {
+
+ private final Map<Element, List<GeneratedPlugin>> plugins;
+
+ public PluginGenerator() {
+ this.plugins = new HashMap<>();
+ }
+
+ public void addPlugin(GeneratedPlugin plugin) {
+ Element topLevel = getTopLevelClass(plugin.intrinsicMethod);
+ List<GeneratedPlugin> list = plugins.get(topLevel);
+ if (list == null) {
+ list = new ArrayList<>();
+ plugins.put(topLevel, list);
+ }
+ list.add(plugin);
+ }
+
+ public void generateAll(AbstractProcessor processor) {
+ for (Entry<Element, List<GeneratedPlugin>> entry : plugins.entrySet()) {
+ disambiguateNames(entry.getValue());
+ createPluginFactory(processor, entry.getKey(), entry.getValue());
+ }
+ }
+
+ private static Element getTopLevelClass(Element element) {
+ Element prev = element;
+ Element enclosing = element.getEnclosingElement();
+ while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
+ prev = enclosing;
+ enclosing = enclosing.getEnclosingElement();
+ }
+ return prev;
+ }
+
+ private static void disambiguateWith(List<GeneratedPlugin> plugins, Function<GeneratedPlugin, String> genName) {
+ plugins.sort(Comparator.comparing(GeneratedPlugin::getPluginName));
+
+ GeneratedPlugin current = plugins.get(0);
+ String currentName = current.getPluginName();
+
+ for (int i = 1; i < plugins.size(); i++) {
+ GeneratedPlugin next = plugins.get(i);
+ if (currentName.equals(next.getPluginName())) {
+ if (current != null) {
+ current.setPluginName(genName.apply(current));
+ current = null;
+ }
+ next.setPluginName(genName.apply(next));
+ } else {
+ current = next;
+ currentName = current.getPluginName();
+ }
+ }
+ }
+
+ private static void appendSimpleTypeName(StringBuilder ret, TypeMirror type) {
+ switch (type.getKind()) {
+ case DECLARED:
+ DeclaredType declared = (DeclaredType) type;
+ TypeElement element = (TypeElement) declared.asElement();
+ ret.append(element.getSimpleName());
+ break;
+ case TYPEVAR:
+ appendSimpleTypeName(ret, ((TypeVariable) type).getUpperBound());
+ break;
+ case WILDCARD:
+ appendSimpleTypeName(ret, ((WildcardType) type).getExtendsBound());
+ break;
+ case ARRAY:
+ appendSimpleTypeName(ret, ((ArrayType) type).getComponentType());
+ ret.append("Array");
+ break;
+ default:
+ ret.append(type);
+ }
+ }
+
+ private static void disambiguateNames(List<GeneratedPlugin> plugins) {
+ // if we have more than one method with the same name, disambiguate with the argument types
+ disambiguateWith(plugins, plugin -> {
+ StringBuilder ret = new StringBuilder(plugin.getPluginName());
+ for (VariableElement param : plugin.intrinsicMethod.getParameters()) {
+ ret.append('_');
+ appendSimpleTypeName(ret, param.asType());
+ }
+ return ret.toString();
+ });
+
+ // since we're using simple names for argument types, we could still have a collision
+ disambiguateWith(plugins, new Function<GeneratedPlugin, String>() {
+
+ private int idx = 0;
+
+ @Override
+ public String apply(GeneratedPlugin plugin) {
+ return plugin.getPluginName() + "_" + (idx++);
+ }
+ });
+ }
+
+ private static void createPluginFactory(AbstractProcessor processor, Element topLevelClass, List<GeneratedPlugin> plugins) {
+ PackageElement pkg = (PackageElement) topLevelClass.getEnclosingElement();
+
+ String genClassName = "PluginFactory_" + topLevelClass.getSimpleName();
+
+ String qualifiedGenClassName = pkg.getQualifiedName() + "." + genClassName;
+ try {
+ JavaFileObject factory = processor.env().getFiler().createSourceFile(qualifiedGenClassName, topLevelClass);
+ try (PrintWriter out = new PrintWriter(factory.openWriter())) {
+ out.printf("// CheckStyle: stop header check\n");
+ out.printf("// CheckStyle: stop line length check\n");
+ out.printf("// GENERATED CONTENT - DO NOT EDIT\n");
+ out.printf("// GENERATORS: %s, %s\n", ReplacementsAnnotationProcessor.class.getName(), PluginGenerator.class.getName());
+ out.printf("package %s;\n", pkg.getQualifiedName());
+ out.printf("\n");
+ createImports(out, plugins);
+ out.printf("\n");
+ out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName);
+ for (GeneratedPlugin plugin : plugins) {
+ out.printf("\n");
+ plugin.generate(processor, out);
+ }
+ out.printf("\n");
+ createPluginFactoryMethod(out, plugins);
+ out.printf("}\n");
+ }
+ } catch (IOException e) {
+ processor.env().getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
+ }
+ processor.createProviderFile(qualifiedGenClassName, "org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory", topLevelClass);
+ }
+
+ protected static void createImports(PrintWriter out, List<GeneratedPlugin> plugins) {
+ out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
+ out.printf("\n");
+ out.printf("import java.lang.annotation.Annotation;\n");
+ out.printf("import org.graalvm.compiler.nodes.ValueNode;\n");
+ out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;\n");
+ out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;\n");
+ out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;\n");
+ out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;\n");
+ out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;\n");
+
+ HashSet<String> extra = new HashSet<>();
+ for (GeneratedPlugin plugin : plugins) {
+ plugin.extraImports(extra);
+ }
+ if (!extra.isEmpty()) {
+ out.printf("\n");
+ for (String i : extra) {
+ out.printf("import %s;\n", i);
+ }
+ }
+ }
+
+ private static void createPluginFactoryMethod(PrintWriter out, List<GeneratedPlugin> plugins) {
+ out.printf(" @Override\n");
+ out.printf(" public void registerPlugins(InvocationPlugins plugins, InjectionProvider injection) {\n");
+ for (GeneratedPlugin plugin : plugins) {
+ plugin.register(out);
+ }
+ out.printf(" }\n");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.processor/src/org/graalvm/compiler/replacements/processor/ReplacementsAnnotationProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * 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.replacements.processor;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic.Kind;
+
+import org.graalvm.compiler.processor.AbstractProcessor;
+
+/**
+ * Processor for annotation types in the {@code org.graalvm.compiler.replacements} name space.
+ */
+public class ReplacementsAnnotationProcessor extends AbstractProcessor {
+
+ private List<AnnotationHandler> handlers;
+
+ @Override
+ public SourceVersion getSupportedSourceVersion() {
+ return SourceVersion.latest();
+ }
+
+ @Override
+ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
+ if (!roundEnv.processingOver()) {
+ PluginGenerator generator = new PluginGenerator();
+ for (AnnotationHandler handler : getHandlers()) {
+ TypeElement annotationClass = getTypeElementOrNull(handler.annotationTypeName);
+ if (annotationClass != null) {
+ for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) {
+ AnnotationMirror annotationMirror = getAnnotation(e, annotationClass.asType());
+ handler.process(e, annotationMirror, generator);
+ }
+ } else {
+ Set<? extends Element> roots = roundEnv.getRootElements();
+ String message = String.format("Processor %s disabled as %s is not resolvable on the compilation class path", handler.getClass().getName(), handler.annotationTypeName);
+ if (roots.isEmpty()) {
+ env().getMessager().printMessage(Kind.WARNING, message);
+ } else {
+ env().getMessager().printMessage(Kind.WARNING, message, roots.iterator().next());
+ }
+ }
+ }
+ generator.generateAll(this);
+ }
+ return false;
+ }
+
+ public List<AnnotationHandler> getHandlers() {
+ if (handlers == null) {
+ handlers = new ArrayList<>();
+ handlers.add(new ClassSubstitutionHandler(this));
+ handlers.add(new MethodSubstitutionHandler(this));
+ handlers.add(new NodeIntrinsicHandler(this));
+ handlers.add(new FoldHandler(this));
+ }
+ return handlers;
+ }
+
+ @Override
+ public Set<String> getSupportedAnnotationTypes() {
+ Set<String> annotationTypes = new HashSet<>();
+ for (AnnotationHandler handler : getHandlers()) {
+ annotationTypes.add(handler.annotationTypeName);
+ }
+ return annotationTypes;
+ }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.sparc/src/org/graalvm/compiler/replacements/sparc/SPARCGraphBuilderPlugins.java Thu May 31 10:38:05 2018 -0700
@@ -38,6 +38,7 @@
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
import org.graalvm.compiler.replacements.IntegerSubstitutions;
import org.graalvm.compiler.replacements.LongSubstitutions;
+import org.graalvm.compiler.replacements.StandardGraphBuilderPlugins;
import org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode;
import org.graalvm.compiler.replacements.nodes.BitCountNode;
import org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode;
@@ -56,6 +57,10 @@
registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, bytecodeProvider);
registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, bytecodeProvider);
registerMathPlugins(invocationPlugins);
+ // This is temporarily disabled until we implement correct emitting of the CAS
+ // instructions of the proper width.
+ StandardGraphBuilderPlugins.registerPlatformSpecificUnsafePlugins(invocationPlugins, bytecodeProvider,
+ new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object});
}
});
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ArrayStoreBytecodeExceptionTest.java Thu May 31 10:38:05 2018 -0700
@@ -32,6 +32,7 @@
import org.junit.runners.Parameterized.Parameters;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -55,7 +56,7 @@
invocationPlugins.register(new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode obj) {
- return throwBytecodeException(b, ArrayStoreException.class, obj);
+ return throwBytecodeException(b, BytecodeExceptionKind.ARRAY_STORE, obj);
}
}, Exceptions.class, "throwArrayStore", Object.class);
super.registerInvocationPlugins(invocationPlugins);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/BytecodeExceptionTest.java Thu May 31 10:38:05 2018 -0700
@@ -26,11 +26,12 @@
import org.graalvm.compiler.nodes.UnwindNode;
import org.graalvm.compiler.nodes.ValueNode;
import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
public abstract class BytecodeExceptionTest extends GraalCompilerTest {
- protected boolean throwBytecodeException(GraphBuilderContext b, Class<? extends Throwable> exception, ValueNode... arguments) {
+ protected boolean throwBytecodeException(GraphBuilderContext b, BytecodeExceptionKind exception, ValueNode... arguments) {
BytecodeExceptionNode exceptionNode = b.add(new BytecodeExceptionNode(b.getMetaAccess(), exception, arguments));
b.add(new UnwindNode(exceptionNode));
return true;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/ClassCastBytecodeExceptionTest.java Thu May 31 10:38:05 2018 -0700
@@ -38,6 +38,7 @@
import org.graalvm.compiler.core.common.type.TypeReference;
import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -83,7 +84,7 @@
Constant hub = b.getConstantReflection().asObjectHub(type);
Stamp hubStamp = b.getStampProvider().createHubStamp(StampFactory.object(TypeReference.createExactTrusted(type)));
ConstantNode hubConst = b.add(ConstantNode.forConstant(hubStamp, hub, b.getMetaAccess()));
- return throwBytecodeException(b, ClassCastException.class, obj, hubConst);
+ return throwBytecodeException(b, BytecodeExceptionKind.CLASS_CAST, obj, hubConst);
}
}, Exceptions.class, "throwClassCast", Object.class, Class.class);
super.registerInvocationPlugins(invocationPlugins);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/IndexOobBytecodeExceptionTest.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -46,8 +47,9 @@
private static Object[] empty = new Object[0];
- public static void throwOutOfBounds(int idx) {
+ public static void throwOutOfBounds(int idx, int length) {
GraalDirectives.blackhole(empty[idx]);
+ GraalDirectives.blackhole(length);
}
}
@@ -55,15 +57,15 @@
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
invocationPlugins.register(new InvocationPlugin() {
@Override
- public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode idx) {
- return throwBytecodeException(b, ArrayIndexOutOfBoundsException.class, idx);
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode idx, ValueNode length) {
+ return throwBytecodeException(b, BytecodeExceptionKind.OUT_OF_BOUNDS, idx, length);
}
- }, Exceptions.class, "throwOutOfBounds", int.class);
+ }, Exceptions.class, "throwOutOfBounds", int.class, int.class);
super.registerInvocationPlugins(invocationPlugins);
}
- public static void oobSnippet(int idx) {
- Exceptions.throwOutOfBounds(idx);
+ public static void oobSnippet(int idx, int length) {
+ Exceptions.throwOutOfBounds(idx, length);
}
@Parameter public int index;
@@ -81,6 +83,6 @@
@Test
public void testOutOfBoundsException() {
- test("oobSnippet", index);
+ test("oobSnippet", index, Exceptions.empty.length);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NullBytecodeExceptionTest.java Thu May 31 10:38:05 2018 -0700
@@ -23,7 +23,7 @@
package org.graalvm.compiler.replacements.test;
import org.junit.Test;
-
+import org.graalvm.compiler.nodes.extended.BytecodeExceptionNode.BytecodeExceptionKind;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
@@ -46,7 +46,7 @@
invocationPlugins.register(new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
- return throwBytecodeException(b, NullPointerException.class);
+ return throwBytecodeException(b, BytecodeExceptionKind.NULL_POINTER);
}
}, Exceptions.class, "throwNull");
super.registerInvocationPlugins(invocationPlugins);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/META-INF/services/javax.annotation.processing.Processor Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-org.graalvm.compiler.replacements.verifier.VerifierAnnotationProcessor
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/APHotSpotSignature.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.replacements.verifier;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.tools.Diagnostic.Kind;
-
-/**
- * Pretty much copied from HotSpotSignature but using a different method for resolving types. This
- * class should be rewritten, its just a quick hack to get signatures working.
- */
-final class APHotSpotSignature {
-
- private final List<String> arguments = new ArrayList<>();
- private final String returnType;
- private final String originalString;
- private TypeMirror[] argumentTypes;
- private TypeMirror returnTypeCache;
-
- APHotSpotSignature(String signature) {
- assert signature.length() > 0;
- this.originalString = signature;
-
- if (signature.charAt(0) == '(') {
- int cur = 1;
- while (cur < signature.length() && signature.charAt(cur) != ')') {
- int nextCur = parseSignature(signature, cur);
- arguments.add(signature.substring(cur, nextCur));
- cur = nextCur;
- }
-
- cur++;
- int nextCur = parseSignature(signature, cur);
- returnType = signature.substring(cur, nextCur);
- if (nextCur != signature.length()) {
- throw new RuntimeException("Invalid trailing characters.");
- }
- } else {
- returnType = null;
- }
- }
-
- private static int parseSignature(String signature, int start) {
- int cur = start;
- char first;
- do {
- first = signature.charAt(cur++);
- } while (first == '[');
-
- switch (first) {
- case 'L':
- while (signature.charAt(cur) != ';') {
- cur++;
- }
- cur++;
- break;
- case 'V':
- case 'I':
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'J':
- case 'S':
- case 'Z':
- break;
- default:
- throw new RuntimeException("Invalid character at index " + cur + " in signature: " + signature);
- }
- return cur;
- }
-
- public int getParameterCount(boolean withReceiver) {
- return arguments.size() + (withReceiver ? 1 : 0);
- }
-
- public TypeMirror getParameterType(ProcessingEnvironment env, int index) {
- if (argumentTypes == null) {
- argumentTypes = new TypeMirror[arguments.size()];
- }
- TypeMirror type = argumentTypes[index];
- if (arguments.get(index) == null) {
- throw new RuntimeException(String.format("Invalid argument at index %s.", index));
- }
-
- if (type == null) {
- argumentTypes[index] = lookupType(env, arguments.get(index));
- }
- return argumentTypes[index];
- }
-
- private static TypeMirror lookupType(ProcessingEnvironment env, String binaryName) {
- if (binaryName.length() == 1) {
- TypeKind kind = fromPrimitiveOrVoidTypeChar(binaryName.charAt(0));
- if (kind.isPrimitive()) {
- return env.getTypeUtils().getPrimitiveType(kind);
- } else if (kind == TypeKind.VOID) {
- return env.getTypeUtils().getNoType(kind);
- }
- }
-
- String canonicalName = binaryName;
- if (canonicalName.startsWith("L") && canonicalName.endsWith(";")) {
- canonicalName = canonicalName.substring(1, canonicalName.length() - 1);
- }
- env.getMessager().printMessage(Kind.ERROR, canonicalName);
-
- int arrayDims = 0;
- while (canonicalName.startsWith("[")) {
- canonicalName = canonicalName.substring(1, canonicalName.length());
- arrayDims++;
- }
-
- canonicalName = canonicalName.replaceAll("/", ".");
- TypeElement typeElement = env.getElementUtils().getTypeElement(canonicalName);
- if (typeElement == null) {
- throw new RuntimeException(String.format("Type with name %s not found.", canonicalName));
- }
- TypeMirror mirror = typeElement.asType();
- for (int i = 0; i < arrayDims; i++) {
- mirror = env.getTypeUtils().getArrayType(mirror);
- }
- return mirror;
- }
-
- /**
- * Returns the kind from the character describing a primitive or void.
- *
- * @param ch the character
- * @return the kind
- */
- public static TypeKind fromPrimitiveOrVoidTypeChar(char ch) {
- switch (ch) {
- case 'Z':
- return TypeKind.BOOLEAN;
- case 'C':
- return TypeKind.CHAR;
- case 'F':
- return TypeKind.FLOAT;
- case 'D':
- return TypeKind.DOUBLE;
- case 'B':
- return TypeKind.BYTE;
- case 'S':
- return TypeKind.SHORT;
- case 'I':
- return TypeKind.INT;
- case 'J':
- return TypeKind.LONG;
- case 'V':
- return TypeKind.VOID;
- }
- throw new IllegalArgumentException("unknown primitive or void type character: " + ch);
- }
-
- public TypeMirror getReturnType(ProcessingEnvironment env) {
- if (returnTypeCache == null) {
- if (returnType == null) {
- throw new RuntimeException("Invalid return type.");
- }
- returnTypeCache = lookupType(env, returnType);
- }
- return returnTypeCache;
- }
-
- @Override
- public String toString() {
- return "Signature<" + originalString + ">";
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/AbstractVerifier.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-
-public abstract class AbstractVerifier {
-
- protected final ProcessingEnvironment env;
-
- public AbstractVerifier(ProcessingEnvironment env) {
- this.env = env;
- }
-
- public abstract void verify(Element element, AnnotationMirror annotation, PluginGenerator generator);
-
- public abstract Class<? extends Annotation> getAnnotationClass();
-
- @SuppressWarnings("unchecked")
- protected static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
- if (value == null) {
- return null;
- }
- if (expectedType.isArray()) {
- ArrayList<Object> result = new ArrayList<>();
- List<AnnotationValue> l = (List<AnnotationValue>) value.getValue();
- for (AnnotationValue el : l) {
- result.add(resolveAnnotationValue(expectedType.getComponentType(), el));
- }
- return (T) result.toArray((Object[]) Array.newInstance(expectedType.getComponentType(), result.size()));
- }
- Object unboxedValue = value.getValue();
- if (unboxedValue != null) {
- if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
- /*
- * Happens if type is invalid when using the ECJ compiler. The ECJ does not match
- * AP-API specification here.
- */
- return null;
- }
- if (!expectedType.isAssignableFrom(unboxedValue.getClass())) {
- throw new ClassCastException(unboxedValue.getClass().getName() + " not assignable from " + expectedType.getName());
- }
- }
- return (T) unboxedValue;
- }
-
- protected static AnnotationValue findAnnotationValue(AnnotationMirror mirror, String name) {
- ExecutableElement valueMethod = null;
- for (ExecutableElement method : ElementFilter.methodsIn(mirror.getAnnotationType().asElement().getEnclosedElements())) {
- if (method.getSimpleName().toString().equals(name)) {
- valueMethod = method;
- break;
- }
- }
-
- if (valueMethod == null) {
- return null;
- }
-
- AnnotationValue value = mirror.getElementValues().get(valueMethod);
- if (value == null) {
- value = valueMethod.getDefaultValue();
- }
-
- return value;
- }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/ClassSubstitutionVerifier.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.tools.Diagnostic.Kind;
-
-import org.graalvm.compiler.api.replacements.ClassSubstitution;
-
-public final class ClassSubstitutionVerifier extends AbstractVerifier {
-
- private static final String TYPE_VALUE = "value";
- private static final String STRING_VALUE = "className";
- private static final String OPTIONAL = "optional";
-
- public ClassSubstitutionVerifier(ProcessingEnvironment env) {
- super(env);
- }
-
- @Override
- public Class<? extends Annotation> getAnnotationClass() {
- return ClassSubstitution.class;
- }
-
- @Override
- public void verify(Element element, AnnotationMirror classSubstitution, PluginGenerator generator) {
- if (!element.getKind().isClass()) {
- assert false : "Element is guaranteed to be a class.";
- return;
- }
- TypeElement type = (TypeElement) element;
-
- TypeElement substitutionType = resolveOriginalType(env, type, classSubstitution);
- if (substitutionType == null) {
- return;
- }
- }
-
- static TypeElement resolveOriginalType(ProcessingEnvironment env, Element sourceElement, AnnotationMirror classSubstition) {
- AnnotationValue typeValue = findAnnotationValue(classSubstition, TYPE_VALUE);
- AnnotationValue stringValue = findAnnotationValue(classSubstition, STRING_VALUE);
- AnnotationValue optionalValue = findAnnotationValue(classSubstition, OPTIONAL);
-
- assert typeValue != null && stringValue != null && optionalValue != null;
-
- TypeMirror type = resolveAnnotationValue(TypeMirror.class, typeValue);
- String[] classNames = resolveAnnotationValue(String[].class, stringValue);
- boolean optional = resolveAnnotationValue(Boolean.class, optionalValue);
-
- if (type.getKind() != TypeKind.DECLARED) {
- env.getMessager().printMessage(Kind.ERROR, "The provided class must be a declared type.", sourceElement, classSubstition, typeValue);
- return null;
- }
-
- if (!classSubstition.getAnnotationType().asElement().equals(((DeclaredType) type).asElement())) {
- if (classNames.length != 0) {
- String msg = "The usage of value and className is exclusive.";
- env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, stringValue);
- env.getMessager().printMessage(Kind.ERROR, msg, sourceElement, classSubstition, typeValue);
- }
-
- return (TypeElement) ((DeclaredType) type).asElement();
- }
-
- if (classNames.length != 0) {
- TypeElement typeElement = null;
- for (String className : classNames) {
- typeElement = env.getElementUtils().getTypeElement(className);
- if (typeElement != null) {
- break;
- }
- }
- if (typeElement == null && !optional) {
- env.getMessager().printMessage(Kind.ERROR, String.format("The class '%s' was not found on the classpath.", stringValue), sourceElement, classSubstition, stringValue);
- }
-
- return typeElement;
- }
-
- if (!optional) {
- env.getMessager().printMessage(Kind.ERROR, String.format("No value for '%s' or '%s' provided but required.", TYPE_VALUE, STRING_VALUE), sourceElement, classSubstition);
- }
-
- return null;
- }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/FoldVerifier.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.type.TypeKind;
-import javax.tools.Diagnostic.Kind;
-
-import org.graalvm.compiler.api.replacements.Fold;
-
-public final class FoldVerifier extends AbstractVerifier {
-
- public FoldVerifier(ProcessingEnvironment env) {
- super(env);
- }
-
- @Override
- public Class<? extends Annotation> getAnnotationClass() {
- return Fold.class;
- }
-
- @Override
- public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
- if (element.getKind() != ElementKind.METHOD) {
- assert false : "Element is guaranteed to be a method.";
- return;
- }
-
- ExecutableElement foldMethod = (ExecutableElement) element;
- if (foldMethod.getReturnType().getKind() == TypeKind.VOID) {
- env.getMessager().printMessage(Kind.ERROR,
- String.format("A @%s method must not be void as it won't yield a compile-time constant (the reason for supporting folding!).", Fold.class.getSimpleName()), element,
- annotation);
- } else if (foldMethod.getModifiers().contains(Modifier.PRIVATE)) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be private.", Fold.class.getSimpleName()), element, annotation);
- } else {
- generator.addPlugin(new GeneratedFoldPlugin(foldMethod));
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedFoldPlugin.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Set;
-import java.util.TreeSet;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-import org.graalvm.compiler.api.replacements.Fold;
-import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
-import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
-
-/**
- * Create graph builder plugins for {@link Fold} methods.
- */
-public class GeneratedFoldPlugin extends GeneratedPlugin {
-
- public GeneratedFoldPlugin(ExecutableElement intrinsicMethod) {
- super(intrinsicMethod);
- }
-
- private static TypeMirror stringType(ProcessingEnvironment env) {
- return env.getElementUtils().getTypeElement("java.lang.String").asType();
- }
-
- @Override
- public void extraImports(Set<String> imports) {
- imports.add("jdk.vm.ci.meta.JavaConstant");
- imports.add("jdk.vm.ci.meta.JavaKind");
- imports.add("org.graalvm.compiler.nodes.ConstantNode");
- }
-
- @Override
- protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
- InjectedDependencies deps = new InjectedDependencies();
- List<? extends VariableElement> params = intrinsicMethod.getParameters();
-
- int argCount = 0;
- Object receiver;
- if (intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
- receiver = intrinsicMethod.getEnclosingElement();
- } else {
- receiver = "arg0";
- TypeElement type = (TypeElement) intrinsicMethod.getEnclosingElement();
- constantArgument(env, out, deps, argCount, type.asType(), argCount);
- argCount++;
- }
-
- int firstArg = argCount;
- for (VariableElement param : params) {
- if (param.getAnnotation(InjectedParameter.class) == null) {
- constantArgument(env, out, deps, argCount, param.asType(), argCount);
- } else {
- out.printf(" assert checkInjectedArgument(b, args[%d], targetMethod);\n", argCount);
- out.printf(" %s arg%d = %s;\n", param.asType(), argCount, deps.use(env, (DeclaredType) param.asType()));
- }
- argCount++;
- }
-
- Set<String> suppressWarnings = new TreeSet<>();
- if (intrinsicMethod.getAnnotation(Deprecated.class) != null) {
- suppressWarnings.add("deprecation");
- }
- if (hasRawtypeWarning(intrinsicMethod.getReturnType())) {
- suppressWarnings.add("rawtypes");
- }
- for (VariableElement param : params) {
- if (hasUncheckedWarning(param.asType())) {
- suppressWarnings.add("unchecked");
- }
- }
- if (suppressWarnings.size() > 0) {
- out.printf(" @SuppressWarnings({");
- String sep = "";
- for (String suppressWarning : suppressWarnings) {
- out.printf("%s\"%s\"", sep, suppressWarning);
- sep = ", ";
- }
- out.printf("})\n");
- }
-
- out.printf(" %s result = %s.%s(", getErasedType(intrinsicMethod.getReturnType()), receiver, intrinsicMethod.getSimpleName());
- if (argCount > firstArg) {
- out.printf("arg%d", firstArg);
- for (int i = firstArg + 1; i < argCount; i++) {
- out.printf(", arg%d", i);
- }
- }
- out.printf(");\n");
-
- TypeMirror returnType = intrinsicMethod.getReturnType();
- switch (returnType.getKind()) {
- case BOOLEAN:
- out.printf(" JavaConstant constant = JavaConstant.forInt(result ? 1 : 0);\n");
- break;
- case BYTE:
- case SHORT:
- case CHAR:
- case INT:
- out.printf(" JavaConstant constant = JavaConstant.forInt(result);\n");
- break;
- case LONG:
- out.printf(" JavaConstant constant = JavaConstant.forLong(result);\n");
- break;
- case FLOAT:
- out.printf(" JavaConstant constant = JavaConstant.forFloat(result);\n");
- break;
- case DOUBLE:
- out.printf(" JavaConstant constant = JavaConstant.forDouble(result);\n");
- break;
- case ARRAY:
- case TYPEVAR:
- case DECLARED:
- if (returnType.equals(stringType(env))) {
- out.printf(" JavaConstant constant = %s.forString(result);\n", deps.use(WellKnownDependency.CONSTANT_REFLECTION));
- } else {
- out.printf(" JavaConstant constant = %s.forObject(result);\n", deps.use(WellKnownDependency.SNIPPET_REFLECTION));
- }
- break;
- default:
- throw new IllegalArgumentException(returnType.toString());
- }
-
- out.printf(" ConstantNode node = ConstantNode.forConstant(constant, %s, %s);\n", deps.use(WellKnownDependency.META_ACCESS), deps.use(WellKnownDependency.STRUCTURED_GRAPH));
- out.printf(" b.push(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
- out.printf(" b.notifyReplacedCall(targetMethod, node);\n");
- out.printf(" return true;\n");
-
- return deps;
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedNodeIntrinsicPlugin.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.graph.Node.InjectedNodeParameter;
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-
-/**
- * Create graph builder plugins for {@link NodeIntrinsic} methods.
- */
-public abstract class GeneratedNodeIntrinsicPlugin extends GeneratedPlugin {
-
- private final TypeMirror[] signature;
-
- public GeneratedNodeIntrinsicPlugin(ExecutableElement intrinsicMethod, TypeMirror[] signature) {
- super(intrinsicMethod);
- this.signature = signature;
- }
-
- private static TypeMirror valueNodeType(ProcessingEnvironment env) {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType();
- }
-
- protected abstract List<? extends VariableElement> getParameters();
-
- protected abstract void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount);
-
- @Override
- protected InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out) {
- InjectedDependencies deps = new InjectedDependencies();
-
- List<? extends VariableElement> params = getParameters();
-
- int idx = 0;
- for (; idx < params.size(); idx++) {
- VariableElement param = params.get(idx);
- if (param.getAnnotation(InjectedNodeParameter.class) == null) {
- break;
- }
-
- out.printf(" %s arg%d = %s;\n", param.asType(), idx, deps.use(env, (DeclaredType) param.asType()));
- }
-
- for (int i = 0; i < signature.length; i++, idx++) {
- if (intrinsicMethod.getParameters().get(i).getAnnotation(ConstantNodeParameter.class) != null) {
- constantArgument(env, out, deps, idx, signature[i], i);
- } else {
- if (signature[i].equals(valueNodeType(env))) {
- out.printf(" ValueNode arg%d = args[%d];\n", idx, i);
- } else {
- out.printf(" %s arg%d = (%s) args[%d];\n", signature[i], idx, signature[i], i);
- }
- }
- }
-
- factoryCall(env, out, deps, idx);
-
- return deps;
- }
-
- public static class ConstructorPlugin extends GeneratedNodeIntrinsicPlugin {
-
- private final ExecutableElement constructor;
-
- public ConstructorPlugin(ExecutableElement intrinsicMethod, ExecutableElement constructor, TypeMirror[] signature) {
- super(intrinsicMethod, signature);
- this.constructor = constructor;
- }
-
- @Override
- public void extraImports(Set<String> imports) {
- if (intrinsicMethod.getReturnType().getKind() != TypeKind.VOID) {
- imports.add("jdk.vm.ci.meta.JavaKind");
- }
- }
-
- @Override
- protected List<? extends VariableElement> getParameters() {
- return constructor.getParameters();
- }
-
- @Override
- protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
- out.printf(" %s node = new %s(", constructor.getEnclosingElement(), constructor.getEnclosingElement());
- if (argCount > 0) {
- out.printf("arg0");
- for (int i = 1; i < argCount; i++) {
- out.printf(", arg%d", i);
- }
- }
- out.printf(");\n");
-
- if (intrinsicMethod.getReturnType().getKind() == TypeKind.VOID) {
- out.printf(" b.add(node);\n");
- } else {
- out.printf(" b.addPush(JavaKind.%s, node);\n", getReturnKind(intrinsicMethod));
- }
- out.printf(" return true;\n");
- }
- }
-
- public static class CustomFactoryPlugin extends GeneratedNodeIntrinsicPlugin {
-
- private final ExecutableElement customFactory;
-
- public CustomFactoryPlugin(ExecutableElement intrinsicMethod, ExecutableElement customFactory, TypeMirror[] signature) {
- super(intrinsicMethod, signature);
- this.customFactory = customFactory;
- }
-
- @Override
- public void extraImports(Set<String> imports) {
- }
-
- @Override
- protected List<? extends VariableElement> getParameters() {
- List<? extends VariableElement> ret = customFactory.getParameters();
- // remove initial GraphBuilderContext and ResolvedJavaMethod parameters
- return ret.subList(2, ret.size());
- }
-
- @Override
- protected void factoryCall(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argCount) {
- out.printf(" return %s.%s(b, targetMethod", customFactory.getEnclosingElement(), customFactory.getSimpleName());
- for (int i = 0; i < argCount; i++) {
- out.printf(", arg%d", i);
- }
- out.printf(");\n");
- }
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/GeneratedPlugin.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,245 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.io.PrintWriter;
-import java.util.Set;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-
-import org.graalvm.compiler.replacements.verifier.InjectedDependencies.Dependency;
-import org.graalvm.compiler.replacements.verifier.InjectedDependencies.WellKnownDependency;
-
-public abstract class GeneratedPlugin {
-
- protected final ExecutableElement intrinsicMethod;
- private boolean needInjectionProvider;
-
- private String pluginName;
-
- public GeneratedPlugin(ExecutableElement intrinsicMethod) {
- this.intrinsicMethod = intrinsicMethod;
- this.needInjectionProvider = false;
- this.pluginName = intrinsicMethod.getEnclosingElement().getSimpleName() + "_" + intrinsicMethod.getSimpleName();
- }
-
- public String getPluginName() {
- return pluginName;
- }
-
- public void setPluginName(String pluginName) {
- this.pluginName = pluginName;
- }
-
- public void generate(ProcessingEnvironment env, PrintWriter out) {
- out.printf(" // class: %s\n", intrinsicMethod.getEnclosingElement());
- out.printf(" // method: %s\n", intrinsicMethod);
- out.printf(" // generated-by: %s\n", getClass().getName());
- out.printf(" private static final class %s extends GeneratedInvocationPlugin {\n", pluginName);
- out.printf("\n");
- out.printf(" @Override\n");
- out.printf(" public boolean execute(GraphBuilderContext b, ResolvedJavaMethod targetMethod, InvocationPlugin.Receiver receiver, ValueNode[] args) {\n");
- InjectedDependencies deps = createExecute(env, out);
- out.printf(" }\n");
-
- createPrivateMembers(out, deps);
-
- out.printf(" }\n");
- }
-
- public void register(PrintWriter out) {
- out.printf(" plugins.register(new %s(", pluginName);
- if (needInjectionProvider) {
- out.printf("injection");
- }
- out.printf("), %s.class, \"%s\"", intrinsicMethod.getEnclosingElement(), intrinsicMethod.getSimpleName());
- if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
- out.printf(", InvocationPlugin.Receiver.class");
- }
- for (VariableElement arg : intrinsicMethod.getParameters()) {
- out.printf(", %s.class", getErasedType(arg.asType()));
- }
- out.printf(");\n");
- }
-
- public abstract void extraImports(Set<String> imports);
-
- protected abstract InjectedDependencies createExecute(ProcessingEnvironment env, PrintWriter out);
-
- private static TypeMirror resolvedJavaTypeType(ProcessingEnvironment env) {
- return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
- }
-
- static String getErasedType(TypeMirror type) {
- switch (type.getKind()) {
- case DECLARED:
- DeclaredType declared = (DeclaredType) type;
- TypeElement element = (TypeElement) declared.asElement();
- return element.getQualifiedName().toString();
- case TYPEVAR:
- return getErasedType(((TypeVariable) type).getUpperBound());
- case WILDCARD:
- return getErasedType(((WildcardType) type).getExtendsBound());
- case ARRAY:
- return getErasedType(((ArrayType) type).getComponentType()) + "[]";
- default:
- return type.toString();
- }
- }
-
- static boolean hasRawtypeWarning(TypeMirror type) {
- switch (type.getKind()) {
- case DECLARED:
- DeclaredType declared = (DeclaredType) type;
- return declared.getTypeArguments().size() > 0;
- case TYPEVAR:
- return false;
- case WILDCARD:
- return false;
- case ARRAY:
- return hasRawtypeWarning(((ArrayType) type).getComponentType());
- default:
- return false;
- }
- }
-
- static boolean hasUncheckedWarning(TypeMirror type) {
- switch (type.getKind()) {
- case DECLARED:
- DeclaredType declared = (DeclaredType) type;
- for (TypeMirror typeParam : declared.getTypeArguments()) {
- if (hasUncheckedWarning(typeParam)) {
- return true;
- }
- }
- return false;
- case TYPEVAR:
- return true;
- case WILDCARD:
- return ((WildcardType) type).getExtendsBound() != null;
- case ARRAY:
- return hasUncheckedWarning(((ArrayType) type).getComponentType());
- default:
- return false;
- }
- }
-
- private void createPrivateMembers(PrintWriter out, InjectedDependencies deps) {
- if (!deps.isEmpty()) {
- out.printf("\n");
- for (Dependency dep : deps) {
- out.printf(" private final %s %s;\n", dep.type, dep.name);
- }
-
- out.printf("\n");
- out.printf(" private %s(InjectionProvider injection) {\n", pluginName);
- for (Dependency dep : deps) {
- out.printf(" this.%s = %s;\n", dep.name, dep.inject(intrinsicMethod));
- }
- out.printf(" }\n");
-
- needInjectionProvider = true;
- }
- }
-
- protected static String getReturnKind(ExecutableElement method) {
- switch (method.getReturnType().getKind()) {
- case BOOLEAN:
- case BYTE:
- case SHORT:
- case CHAR:
- case INT:
- return "Int";
- case LONG:
- return "Long";
- case FLOAT:
- return "Float";
- case DOUBLE:
- return "Double";
- case VOID:
- return "Void";
- case ARRAY:
- case TYPEVAR:
- case DECLARED:
- return "Object";
- default:
- throw new IllegalArgumentException(method.getReturnType().toString());
- }
- }
-
- protected static void constantArgument(ProcessingEnvironment env, PrintWriter out, InjectedDependencies deps, int argIdx, TypeMirror type, int nodeIdx) {
- if (hasRawtypeWarning(type)) {
- out.printf(" @SuppressWarnings({\"rawtypes\"})\n");
- }
- out.printf(" %s arg%d;\n", getErasedType(type), argIdx);
- out.printf(" if (args[%d].isConstant()) {\n", nodeIdx);
- if (type.equals(resolvedJavaTypeType(env))) {
- out.printf(" arg%d = %s.asJavaType(args[%d].asConstant());\n", argIdx, deps.use(WellKnownDependency.CONSTANT_REFLECTION), nodeIdx);
- } else {
- switch (type.getKind()) {
- case BOOLEAN:
- out.printf(" arg%d = args[%d].asJavaConstant().asInt() != 0;\n", argIdx, nodeIdx);
- break;
- case BYTE:
- out.printf(" arg%d = (byte) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
- break;
- case CHAR:
- out.printf(" arg%d = (char) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
- break;
- case SHORT:
- out.printf(" arg%d = (short) args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
- break;
- case INT:
- out.printf(" arg%d = args[%d].asJavaConstant().asInt();\n", argIdx, nodeIdx);
- break;
- case LONG:
- out.printf(" arg%d = args[%d].asJavaConstant().asLong();\n", argIdx, nodeIdx);
- break;
- case FLOAT:
- out.printf(" arg%d = args[%d].asJavaConstant().asFloat();\n", argIdx, nodeIdx);
- break;
- case DOUBLE:
- out.printf(" arg%d = args[%d].asJavaConstant().asDouble();\n", argIdx, nodeIdx);
- break;
- case ARRAY:
- case DECLARED:
- out.printf(" arg%d = %s.asObject(%s.class, args[%d].asJavaConstant());\n", argIdx, deps.use(WellKnownDependency.SNIPPET_REFLECTION), getErasedType(type), nodeIdx);
- break;
- default:
- throw new IllegalArgumentException(type.toString());
- }
- }
- out.printf(" } else {\n");
- out.printf(" return false;\n");
- out.printf(" }\n");
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/InjectedDependencies.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,143 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.util.HashMap;
-import java.util.Iterator;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-import org.graalvm.compiler.replacements.verifier.InjectedDependencies.Dependency;
-
-public class InjectedDependencies implements Iterable<Dependency> {
-
- public abstract static class Dependency {
-
- public final String name;
- public final String type;
-
- private Dependency(String name, String type) {
- this.name = name;
- this.type = type;
- }
-
- public abstract String inject(ExecutableElement inject);
- }
-
- private static final class InjectedDependency extends Dependency {
-
- private InjectedDependency(String name, String type) {
- super(name, type);
- }
-
- @Override
- public String inject(ExecutableElement inject) {
- return String.format("injection.getInjectedArgument(%s.class)", type);
- }
- }
-
- private static final class InjectedStampDependency extends Dependency {
-
- private InjectedStampDependency() {
- super("stamp", "org.graalvm.compiler.core.common.type.Stamp");
- }
-
- @Override
- public String inject(ExecutableElement inject) {
- NodeIntrinsic nodeIntrinsic = inject.getAnnotation(NodeIntrinsic.class);
- boolean nonNull = nodeIntrinsic != null && nodeIntrinsic.injectedStampIsNonNull();
- return String.format("injection.getInjectedStamp(%s.class, %s)", GeneratedPlugin.getErasedType(inject.getReturnType()), nonNull);
- }
- }
-
- public enum WellKnownDependency {
- CONSTANT_REFLECTION("b.getConstantReflection()", "jdk.vm.ci.meta.ConstantReflectionProvider"),
- META_ACCESS("b.getMetaAccess()", "jdk.vm.ci.meta.MetaAccessProvider"),
- INJECTED_STAMP(new InjectedStampDependency()),
- SNIPPET_REFLECTION(new InjectedDependency("snippetReflection", "org.graalvm.compiler.api.replacements.SnippetReflectionProvider")),
- STAMP_PROVIDER("b.getStampProvider()", "org.graalvm.compiler.nodes.spi.StampProvider"),
- STRUCTURED_GRAPH("b.getGraph()", "org.graalvm.compiler.nodes.StructuredGraph");
-
- private final String expr;
- private final String type;
- private final Dependency generateMember;
-
- WellKnownDependency(String expr, String type) {
- this.expr = expr;
- this.type = type;
- this.generateMember = null;
- }
-
- WellKnownDependency(Dependency generateMember) {
- this.expr = generateMember.name;
- this.type = generateMember.type;
- this.generateMember = generateMember;
- }
-
- private TypeMirror getType(ProcessingEnvironment env) {
- return env.getElementUtils().getTypeElement(type).asType();
- }
- }
-
- private final HashMap<String, Dependency> deps;
-
- public InjectedDependencies() {
- deps = new HashMap<>();
- }
-
- public String use(WellKnownDependency wellKnown) {
- if (wellKnown.generateMember != null) {
- deps.put(wellKnown.type, wellKnown.generateMember);
- }
- return wellKnown.expr;
- }
-
- public String use(ProcessingEnvironment env, DeclaredType type) {
- for (WellKnownDependency wellKnown : WellKnownDependency.values()) {
- if (env.getTypeUtils().isAssignable(wellKnown.getType(env), type)) {
- return use(wellKnown);
- }
- }
-
- String typeName = type.toString();
- Dependency ret = deps.get(typeName);
- if (ret == null) {
- ret = new InjectedDependency("injected" + type.asElement().getSimpleName(), typeName);
- deps.put(typeName, ret);
- }
- return ret.name;
- }
-
- @Override
- public Iterator<Dependency> iterator() {
- return deps.values().iterator();
- }
-
- public boolean isEmpty() {
- return deps.isEmpty();
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/MethodSubstitutionVerifier.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.AnnotationValue;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.Name;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.util.ElementFilter;
-import javax.tools.Diagnostic.Kind;
-
-import org.graalvm.compiler.api.replacements.ClassSubstitution;
-import org.graalvm.compiler.api.replacements.MethodSubstitution;
-
-public final class MethodSubstitutionVerifier extends AbstractVerifier {
-
- private static final boolean DEBUG = false;
-
- private static final String ORIGINAL_METHOD_NAME = "value";
- private static final String ORIGINAL_IS_STATIC = "isStatic";
- private static final String ORIGINAL_SIGNATURE = "signature";
-
- private static final String ORIGINAL_METHOD_NAME_DEFAULT = "";
- private static final String ORIGINAL_SIGNATURE_DEFAULT = "";
-
- public MethodSubstitutionVerifier(ProcessingEnvironment env) {
- super(env);
- }
-
- @Override
- public Class<? extends Annotation> getAnnotationClass() {
- return MethodSubstitution.class;
- }
-
- @SuppressWarnings("unused")
- @Override
- public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
- if (element.getKind() != ElementKind.METHOD) {
- assert false : "Element is guaranteed to be a method.";
- return;
- }
- ExecutableElement substitutionMethod = (ExecutableElement) element;
- TypeElement substitutionType = findEnclosingClass(substitutionMethod);
- assert substitutionType != null;
-
- AnnotationMirror substitutionClassAnnotation = VerifierAnnotationProcessor.findAnnotationMirror(env, substitutionType.getAnnotationMirrors(), ClassSubstitution.class);
- if (substitutionClassAnnotation == null) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s annotation is required on the enclosing class.", ClassSubstitution.class.getSimpleName()), element, annotation);
- return;
- }
- boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionClassAnnotation, "optional"));
- if (optional) {
- return;
- }
-
- TypeElement originalType = ClassSubstitutionVerifier.resolveOriginalType(env, substitutionType, substitutionClassAnnotation);
- if (originalType == null) {
- env.getMessager().printMessage(Kind.ERROR, String.format("The @%s annotation is invalid on the enclosing class.", ClassSubstitution.class.getSimpleName()), element, annotation);
- return;
- }
-
- if (!substitutionMethod.getModifiers().contains(Modifier.STATIC)) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be static.", MethodSubstitution.class.getSimpleName()), element, annotation);
- }
-
- if (substitutionMethod.getModifiers().contains(Modifier.ABSTRACT) || substitutionMethod.getModifiers().contains(Modifier.NATIVE)) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must not be native or abstract.", MethodSubstitution.class.getSimpleName()), element, annotation);
- }
-
- String originalName = originalName(substitutionMethod, annotation);
- boolean isStatic = resolveAnnotationValue(Boolean.class, findAnnotationValue(annotation, ORIGINAL_IS_STATIC));
- TypeMirror[] originalSignature = originalSignature(originalType, substitutionMethod, annotation, isStatic);
- if (originalSignature == null) {
- return;
- }
- ExecutableElement originalMethod = originalMethod(substitutionMethod, annotation, originalType, originalName, originalSignature, isStatic);
- if (DEBUG && originalMethod != null) {
- env.getMessager().printMessage(Kind.NOTE, String.format("Found original method %s in type %s.", originalMethod, findEnclosingClass(originalMethod)));
- }
- }
-
- private TypeMirror[] originalSignature(TypeElement originalType, ExecutableElement method, AnnotationMirror annotation, boolean isStatic) {
- AnnotationValue signatureValue = findAnnotationValue(annotation, ORIGINAL_SIGNATURE);
- String signatureString = resolveAnnotationValue(String.class, signatureValue);
- List<TypeMirror> parameters = new ArrayList<>();
- if (signatureString.equals(ORIGINAL_SIGNATURE_DEFAULT)) {
- for (int i = 0; i < method.getParameters().size(); i++) {
- parameters.add(method.getParameters().get(i).asType());
- }
- if (!isStatic) {
- if (parameters.isEmpty()) {
- env.getMessager().printMessage(Kind.ERROR, "Method signature must be a static method with the 'this' object as its first parameter", method, annotation);
- return null;
- } else {
- TypeMirror thisParam = parameters.remove(0);
- if (!isSubtype(originalType.asType(), thisParam)) {
- Name thisName = method.getParameters().get(0).getSimpleName();
- env.getMessager().printMessage(Kind.ERROR, String.format("The type of %s must assignable from %s", thisName, originalType), method, annotation);
- }
- }
- }
- parameters.add(0, method.getReturnType());
- } else {
- try {
- APHotSpotSignature signature = new APHotSpotSignature(signatureString);
- parameters.add(signature.getReturnType(env));
- for (int i = 0; i < signature.getParameterCount(false); i++) {
- parameters.add(signature.getParameterType(env, i));
- }
- } catch (Exception e) {
- /*
- * That's not good practice and should be changed after APHotSpotSignature has
- * received a cleanup.
- */
- env.getMessager().printMessage(Kind.ERROR, String.format("Parsing the signature failed: %s", e.getMessage() != null ? e.getMessage() : e.toString()), method, annotation,
- signatureValue);
- return null;
- }
- }
- return parameters.toArray(new TypeMirror[parameters.size()]);
- }
-
- private static String originalName(ExecutableElement substituteMethod, AnnotationMirror substitution) {
- String originalMethodName = resolveAnnotationValue(String.class, findAnnotationValue(substitution, ORIGINAL_METHOD_NAME));
- if (originalMethodName.equals(ORIGINAL_METHOD_NAME_DEFAULT)) {
- originalMethodName = substituteMethod.getSimpleName().toString();
- }
- return originalMethodName;
- }
-
- private ExecutableElement originalMethod(ExecutableElement substitutionMethod, AnnotationMirror substitutionAnnotation, TypeElement originalType, String originalName,
- TypeMirror[] originalSignature, boolean isStatic) {
- TypeMirror signatureReturnType = originalSignature[0];
- TypeMirror[] signatureParameters = Arrays.copyOfRange(originalSignature, 1, originalSignature.length);
- List<ExecutableElement> searchElements;
- if (originalName.equals("<init>")) {
- searchElements = ElementFilter.constructorsIn(originalType.getEnclosedElements());
- } else {
- searchElements = ElementFilter.methodsIn(originalType.getEnclosedElements());
- }
-
- ExecutableElement originalMethod = null;
- outer: for (ExecutableElement searchElement : searchElements) {
- if (searchElement.getSimpleName().toString().equals(originalName) && searchElement.getParameters().size() == signatureParameters.length) {
- for (int i = 0; i < signatureParameters.length; i++) {
- VariableElement parameter = searchElement.getParameters().get(i);
- if (!isTypeCompatible(parameter.asType(), signatureParameters[i])) {
- continue outer;
- }
- }
- originalMethod = searchElement;
- break;
- }
- }
- if (originalMethod == null) {
- boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionAnnotation, "optional"));
- if (!optional) {
- env.getMessager().printMessage(Kind.ERROR, String.format("Could not find the original method with name '%s' and parameters '%s'.", originalName, Arrays.toString(signatureParameters)),
- substitutionMethod, substitutionAnnotation);
- }
- return null;
- }
-
- if (originalMethod.getModifiers().contains(Modifier.STATIC) != isStatic) {
- boolean optional = resolveAnnotationValue(Boolean.class, findAnnotationValue(substitutionAnnotation, "optional"));
- if (!optional) {
- env.getMessager().printMessage(Kind.ERROR, String.format("The %s element must be set to %s.", ORIGINAL_IS_STATIC, !isStatic), substitutionMethod, substitutionAnnotation);
- }
- return null;
- }
-
- if (!isTypeCompatible(originalMethod.getReturnType(), signatureReturnType)) {
- env.getMessager().printMessage(
- Kind.ERROR,
- String.format("The return type of the substitution method '%s' must match with the return type of the original method '%s'.", signatureReturnType,
- originalMethod.getReturnType()),
- substitutionMethod, substitutionAnnotation);
- return null;
- }
-
- return originalMethod;
- }
-
- private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
- TypeMirror original = originalType;
- TypeMirror substitution = substitutionType;
- if (needsErasure(original)) {
- original = env.getTypeUtils().erasure(original);
- }
- if (needsErasure(substitution)) {
- substitution = env.getTypeUtils().erasure(substitution);
- }
- return env.getTypeUtils().isSameType(original, substitution);
- }
-
- /**
- * Tests whether one type is a subtype of another. Any type is considered to be a subtype of
- * itself.
- *
- * @param t1 the first type
- * @param t2 the second type
- * @return {@code true} if and only if the first type is a subtype of the second
- */
- private boolean isSubtype(TypeMirror t1, TypeMirror t2) {
- TypeMirror t1Erased = t1;
- TypeMirror t2Erased = t2;
- if (needsErasure(t1Erased)) {
- t1Erased = env.getTypeUtils().erasure(t1Erased);
- }
- if (needsErasure(t2Erased)) {
- t2Erased = env.getTypeUtils().erasure(t2Erased);
- }
- return env.getTypeUtils().isSubtype(t1Erased, t2Erased);
- }
-
- private static boolean needsErasure(TypeMirror typeMirror) {
- return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
- typeMirror.getKind() != TypeKind.NULL;
- }
-
- private static TypeElement findEnclosingClass(Element element) {
- if (element.getKind().isClass()) {
- return (TypeElement) element;
- }
-
- Element enclosing = element.getEnclosingElement();
- while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
- if (enclosing.getKind().isClass()) {
- return (TypeElement) enclosing;
- }
- enclosing = enclosing.getEnclosingElement();
- }
- return null;
- }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/NodeIntrinsicVerifier.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,357 +0,0 @@
-/*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Formatter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.ExecutableElement;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.TypeKind;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.util.ElementFilter;
-import javax.tools.Diagnostic.Kind;
-
-import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
-import org.graalvm.compiler.graph.Node.InjectedNodeParameter;
-import org.graalvm.compiler.graph.Node.NodeIntrinsic;
-import org.graalvm.compiler.nodeinfo.InputType;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodeinfo.StructuralInput.MarkerType;
-
-public final class NodeIntrinsicVerifier extends AbstractVerifier {
-
- private static final String NODE_CLASS_NAME = "value";
-
- private TypeMirror nodeType() {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.graph.Node").asType();
- }
-
- private TypeMirror stampType() {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.core.common.type.Stamp").asType();
- }
-
- private TypeMirror valueNodeType() {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.ValueNode").asType();
- }
-
- private TypeMirror classType() {
- return env.getElementUtils().getTypeElement("java.lang.Class").asType();
- }
-
- private TypeMirror resolvedJavaTypeType() {
- return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaType").asType();
- }
-
- private TypeMirror resolvedJavaMethodType() {
- return env.getElementUtils().getTypeElement("jdk.vm.ci.meta.ResolvedJavaMethod").asType();
- }
-
- private TypeMirror structuralInputType() {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodeinfo.StructuralInput").asType();
- }
-
- private TypeMirror graphBuilderContextType() {
- return env.getElementUtils().getTypeElement("org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext").asType();
- }
-
- public NodeIntrinsicVerifier(ProcessingEnvironment env) {
- super(env);
- }
-
- @Override
- public Class<? extends Annotation> getAnnotationClass() {
- return NodeIntrinsic.class;
- }
-
- @Override
- public void verify(Element element, AnnotationMirror annotation, PluginGenerator generator) {
- if (element.getKind() != ElementKind.METHOD) {
- assert false : "Element is guaranteed to be a method.";
- return;
- }
-
- ExecutableElement intrinsicMethod = (ExecutableElement) element;
- if (!intrinsicMethod.getModifiers().contains(Modifier.STATIC)) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be static.", NodeIntrinsic.class.getSimpleName()), element, annotation);
- }
- if (!intrinsicMethod.getModifiers().contains(Modifier.NATIVE)) {
- env.getMessager().printMessage(Kind.ERROR, String.format("A @%s method must be native.", NodeIntrinsic.class.getSimpleName()), element, annotation);
- }
-
- TypeMirror nodeClassMirror = resolveAnnotationValue(TypeMirror.class, findAnnotationValue(annotation, NODE_CLASS_NAME));
- TypeElement nodeClass = (TypeElement) env.getTypeUtils().asElement(nodeClassMirror);
- if (nodeClass.getSimpleName().contentEquals(NodeIntrinsic.class.getSimpleName())) {
- // default value
- Element enclosingElement = intrinsicMethod.getEnclosingElement();
- while (enclosingElement != null && enclosingElement.getKind() != ElementKind.CLASS) {
- enclosingElement = enclosingElement.getEnclosingElement();
- }
- if (enclosingElement != null) {
- nodeClass = (TypeElement) enclosingElement;
- }
- }
-
- TypeMirror returnType = intrinsicMethod.getReturnType();
- if (returnType instanceof TypeVariable) {
- env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic cannot have a generic return type.", element, annotation);
- }
-
- boolean injectedStampIsNonNull = intrinsicMethod.getAnnotation(NodeIntrinsic.class).injectedStampIsNonNull();
-
- if (returnType.getKind() == TypeKind.VOID) {
- for (VariableElement parameter : intrinsicMethod.getParameters()) {
- if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
- env.getMessager().printMessage(Kind.ERROR, "@NodeIntrinsic with an injected Stamp parameter cannot have a void return type.", element, annotation);
- break;
- }
- }
- }
-
- TypeMirror[] constructorSignature = constructorSignature(intrinsicMethod);
- Map<ExecutableElement, String> nonMatches = new HashMap<>();
- List<ExecutableElement> factories = findIntrinsifyFactoryMethod(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull);
- List<ExecutableElement> constructors = Collections.emptyList();
- if (nodeClass.getModifiers().contains(Modifier.ABSTRACT)) {
- if (factories.isEmpty()) {
- env.getMessager().printMessage(Kind.ERROR, String.format("Cannot make a node intrinsic for an abstract class %s.", nodeClass.getSimpleName()), element, annotation);
- }
- } else if (!isNodeType(nodeClass)) {
- if (factories.isEmpty()) {
- env.getMessager().printMessage(Kind.ERROR, String.format("%s is not a subclass of %s.", nodeClass.getSimpleName(), nodeType()), element, annotation);
- }
- } else {
- TypeMirror ret = returnType;
- if (env.getTypeUtils().isAssignable(ret, structuralInputType())) {
- checkInputType(nodeClass, ret, element, annotation);
- }
-
- constructors = findConstructors(nodeClass, constructorSignature, nonMatches, injectedStampIsNonNull);
- }
- Formatter msg = new Formatter();
- if (factories.size() > 1) {
- msg.format("Found more than one factory in %s matching node intrinsic:", nodeClass);
- for (ExecutableElement candidate : factories) {
- msg.format("%n %s", candidate);
- }
- env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
- } else if (constructors.size() > 1) {
- msg.format("Found more than one constructor in %s matching node intrinsic:", nodeClass);
- for (ExecutableElement candidate : constructors) {
- msg.format("%n %s", candidate);
- }
- env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
- } else if (factories.size() == 1) {
- generator.addPlugin(new GeneratedNodeIntrinsicPlugin.CustomFactoryPlugin(intrinsicMethod, factories.get(0), constructorSignature));
- } else if (constructors.size() == 1) {
- generator.addPlugin(new GeneratedNodeIntrinsicPlugin.ConstructorPlugin(intrinsicMethod, constructors.get(0), constructorSignature));
- } else {
- msg.format("Could not find any factories or constructors in %s matching node intrinsic", nodeClass);
- if (!nonMatches.isEmpty()) {
- msg.format("%nFactories and constructors that failed to match:");
- for (Map.Entry<ExecutableElement, String> e : nonMatches.entrySet()) {
- msg.format("%n %s: %s", e.getKey(), e.getValue());
- }
- }
- env.getMessager().printMessage(Kind.ERROR, msg.toString(), intrinsicMethod, annotation);
- }
- }
-
- private void checkInputType(TypeElement nodeClass, TypeMirror returnType, Element element, AnnotationMirror annotation) {
- InputType inputType = getInputType(returnType, element, annotation);
- if (inputType != InputType.Value) {
- boolean allowed = false;
- InputType[] allowedTypes = nodeClass.getAnnotation(NodeInfo.class).allowedUsageTypes();
- for (InputType allowedType : allowedTypes) {
- if (inputType == allowedType) {
- allowed = true;
- break;
- }
- }
- if (!allowed) {
- env.getMessager().printMessage(Kind.ERROR, String.format("@NodeIntrinsic returns input type %s, but only %s is allowed.", inputType, Arrays.toString(allowedTypes)), element,
- annotation);
- }
- }
- }
-
- private InputType getInputType(TypeMirror type, Element element, AnnotationMirror annotation) {
- TypeElement current = (TypeElement) env.getTypeUtils().asElement(type);
- while (current != null) {
- MarkerType markerType = current.getAnnotation(MarkerType.class);
- if (markerType != null) {
- return markerType.value();
- }
-
- current = (TypeElement) env.getTypeUtils().asElement(current.getSuperclass());
- }
-
- env.getMessager().printMessage(Kind.ERROR, String.format("The class %s is a subclass of StructuralInput, but isn't annotated with @MarkerType.", type), element, annotation);
- return InputType.Value;
- }
-
- private boolean isNodeType(TypeElement nodeClass) {
- return env.getTypeUtils().isSubtype(nodeClass.asType(), nodeType());
- }
-
- private TypeMirror[] constructorSignature(ExecutableElement method) {
- TypeMirror[] parameters = new TypeMirror[method.getParameters().size()];
- for (int i = 0; i < method.getParameters().size(); i++) {
- VariableElement parameter = method.getParameters().get(i);
- if (parameter.getAnnotation(ConstantNodeParameter.class) == null) {
- parameters[i] = valueNodeType();
- } else {
- TypeMirror type = parameter.asType();
- if (isTypeCompatible(type, classType())) {
- type = resolvedJavaTypeType();
- }
- parameters[i] = type;
- }
- }
- return parameters;
- }
-
- private List<ExecutableElement> findConstructors(TypeElement nodeClass, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
- List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeClass.getEnclosedElements());
- List<ExecutableElement> found = new ArrayList<>(constructors.size());
- for (ExecutableElement constructor : constructors) {
- if (matchSignature(0, constructor, signature, nonMatches, requiresInjectedStamp)) {
- found.add(constructor);
- }
- }
- return found;
- }
-
- private List<ExecutableElement> findIntrinsifyFactoryMethod(TypeElement nodeClass, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
- List<ExecutableElement> methods = ElementFilter.methodsIn(nodeClass.getEnclosedElements());
- List<ExecutableElement> found = new ArrayList<>(methods.size());
- for (ExecutableElement method : methods) {
- if (!method.getSimpleName().toString().equals("intrinsify")) {
- continue;
- }
-
- if (method.getParameters().size() < 2) {
- continue;
- }
-
- VariableElement firstArg = method.getParameters().get(0);
- if (!isTypeCompatible(firstArg.asType(), graphBuilderContextType())) {
- continue;
- }
-
- VariableElement secondArg = method.getParameters().get(1);
- if (!isTypeCompatible(secondArg.asType(), resolvedJavaMethodType())) {
- continue;
- }
-
- if (method.getReturnType().getKind() != TypeKind.BOOLEAN) {
- continue;
- }
-
- if (matchSignature(2, method, signature, nonMatches, requiresInjectedStamp)) {
- found.add(method);
- }
- }
- return found;
- }
-
- private boolean matchSignature(int numSkippedParameters, ExecutableElement method, TypeMirror[] signature, Map<ExecutableElement, String> nonMatches, boolean requiresInjectedStamp) {
- int sIdx = 0;
- int cIdx = numSkippedParameters;
- boolean missingStampArgument = requiresInjectedStamp;
- while (cIdx < method.getParameters().size()) {
- VariableElement parameter = method.getParameters().get(cIdx++);
- TypeMirror paramType = parameter.asType();
- if (parameter.getAnnotation(InjectedNodeParameter.class) != null) {
- if (missingStampArgument && env.getTypeUtils().isSameType(paramType, stampType())) {
- missingStampArgument = false;
- }
- // skip injected parameters
- continue;
- }
- if (missingStampArgument) {
- nonMatches.put(method, String.format("missing injected %s argument", stampType()));
- return false;
- }
-
- if (cIdx == method.getParameters().size() && paramType.getKind() == TypeKind.ARRAY) {
- // last argument of constructor is varargs, match remaining intrinsic arguments
- TypeMirror varargsType = ((ArrayType) paramType).getComponentType();
- while (sIdx < signature.length) {
- if (!isTypeCompatible(varargsType, signature[sIdx++])) {
- nonMatches.put(method, String.format("the types of argument %d are incompatible: %s != %s", sIdx, varargsType, signature[sIdx - 1]));
- return false;
- }
- }
- } else if (sIdx >= signature.length) {
- // too many arguments in intrinsic method
- nonMatches.put(method, "too many arguments");
- return false;
- } else if (!isTypeCompatible(paramType, signature[sIdx++])) {
- nonMatches.put(method, String.format("the type of argument %d is incompatible: %s != %s", sIdx, paramType, signature[sIdx - 1]));
- return false;
- }
- }
- if (missingStampArgument) {
- nonMatches.put(method, String.format("missing injected %s argument", stampType()));
- return false;
- }
-
- if (sIdx != signature.length) {
- nonMatches.put(method, "not enough arguments");
- return false;
- }
- return true;
- }
-
- private boolean isTypeCompatible(TypeMirror originalType, TypeMirror substitutionType) {
- TypeMirror original = originalType;
- TypeMirror substitution = substitutionType;
- if (needsErasure(original)) {
- original = env.getTypeUtils().erasure(original);
- }
- if (needsErasure(substitution)) {
- substitution = env.getTypeUtils().erasure(substitution);
- }
- return env.getTypeUtils().isSameType(original, substitution);
- }
-
- private static boolean needsErasure(TypeMirror typeMirror) {
- return typeMirror.getKind() != TypeKind.NONE && typeMirror.getKind() != TypeKind.VOID && !typeMirror.getKind().isPrimitive() && typeMirror.getKind() != TypeKind.OTHER &&
- typeMirror.getKind() != TypeKind.NULL;
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/PluginGenerator.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,213 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.replacements.verifier;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.function.Function;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.ElementKind;
-import javax.lang.model.element.PackageElement;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.ArrayType;
-import javax.lang.model.type.DeclaredType;
-import javax.lang.model.type.TypeMirror;
-import javax.lang.model.type.TypeVariable;
-import javax.lang.model.type.WildcardType;
-import javax.tools.Diagnostic;
-import javax.tools.JavaFileObject;
-
-public class PluginGenerator {
-
- private final Map<Element, List<GeneratedPlugin>> plugins;
-
- public PluginGenerator() {
- this.plugins = new HashMap<>();
- }
-
- public void addPlugin(GeneratedPlugin plugin) {
- Element topLevel = getTopLevelClass(plugin.intrinsicMethod);
- List<GeneratedPlugin> list = plugins.get(topLevel);
- if (list == null) {
- list = new ArrayList<>();
- plugins.put(topLevel, list);
- }
- list.add(plugin);
- }
-
- public void generateAll(ProcessingEnvironment env) {
- for (Entry<Element, List<GeneratedPlugin>> entry : plugins.entrySet()) {
- disambiguateNames(entry.getValue());
- createPluginFactory(env, entry.getKey(), entry.getValue());
- }
- }
-
- private static Element getTopLevelClass(Element element) {
- Element prev = element;
- Element enclosing = element.getEnclosingElement();
- while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
- prev = enclosing;
- enclosing = enclosing.getEnclosingElement();
- }
- return prev;
- }
-
- private static void disambiguateWith(List<GeneratedPlugin> plugins, Function<GeneratedPlugin, String> genName) {
- plugins.sort(Comparator.comparing(GeneratedPlugin::getPluginName));
-
- GeneratedPlugin current = plugins.get(0);
- String currentName = current.getPluginName();
-
- for (int i = 1; i < plugins.size(); i++) {
- GeneratedPlugin next = plugins.get(i);
- if (currentName.equals(next.getPluginName())) {
- if (current != null) {
- current.setPluginName(genName.apply(current));
- current = null;
- }
- next.setPluginName(genName.apply(next));
- } else {
- current = next;
- currentName = current.getPluginName();
- }
- }
- }
-
- private static void appendSimpleTypeName(StringBuilder ret, TypeMirror type) {
- switch (type.getKind()) {
- case DECLARED:
- DeclaredType declared = (DeclaredType) type;
- TypeElement element = (TypeElement) declared.asElement();
- ret.append(element.getSimpleName());
- break;
- case TYPEVAR:
- appendSimpleTypeName(ret, ((TypeVariable) type).getUpperBound());
- break;
- case WILDCARD:
- appendSimpleTypeName(ret, ((WildcardType) type).getExtendsBound());
- break;
- case ARRAY:
- appendSimpleTypeName(ret, ((ArrayType) type).getComponentType());
- ret.append("Array");
- break;
- default:
- ret.append(type);
- }
- }
-
- private static void disambiguateNames(List<GeneratedPlugin> plugins) {
- // if we have more than one method with the same name, disambiguate with the argument types
- disambiguateWith(plugins, plugin -> {
- StringBuilder ret = new StringBuilder(plugin.getPluginName());
- for (VariableElement param : plugin.intrinsicMethod.getParameters()) {
- ret.append('_');
- appendSimpleTypeName(ret, param.asType());
- }
- return ret.toString();
- });
-
- // since we're using simple names for argument types, we could still have a collision
- disambiguateWith(plugins, new Function<GeneratedPlugin, String>() {
-
- private int idx = 0;
-
- @Override
- public String apply(GeneratedPlugin plugin) {
- return plugin.getPluginName() + "_" + (idx++);
- }
- });
- }
-
- private static void createPluginFactory(ProcessingEnvironment env, Element topLevelClass, List<GeneratedPlugin> plugins) {
- PackageElement pkg = (PackageElement) topLevelClass.getEnclosingElement();
-
- String genClassName = "PluginFactory_" + topLevelClass.getSimpleName();
-
- try {
- JavaFileObject factory = env.getFiler().createSourceFile(pkg.getQualifiedName() + "." + genClassName, topLevelClass);
- try (PrintWriter out = new PrintWriter(factory.openWriter())) {
- out.printf("// CheckStyle: stop header check\n");
- out.printf("// CheckStyle: stop line length check\n");
- out.printf("// GENERATED CONTENT - DO NOT EDIT\n");
- out.printf("// GENERATORS: %s, %s\n", VerifierAnnotationProcessor.class.getName(), PluginGenerator.class.getName());
- out.printf("package %s;\n", pkg.getQualifiedName());
- out.printf("\n");
- createImports(out, plugins);
- out.printf("\n");
- out.printf("@ServiceProvider(NodeIntrinsicPluginFactory.class)\n");
- out.printf("public class %s implements NodeIntrinsicPluginFactory {\n", genClassName);
- for (GeneratedPlugin plugin : plugins) {
- out.printf("\n");
- plugin.generate(env, out);
- }
- out.printf("\n");
- createPluginFactoryMethod(out, plugins);
- out.printf("}\n");
- }
- } catch (IOException e) {
- env.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
- }
- }
-
- protected static void createImports(PrintWriter out, List<GeneratedPlugin> plugins) {
- out.printf("import jdk.vm.ci.meta.ResolvedJavaMethod;\n");
- out.printf("import org.graalvm.compiler.serviceprovider.ServiceProvider;\n");
- out.printf("\n");
- out.printf("import org.graalvm.compiler.nodes.ValueNode;\n");
- out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;\n");
- out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;\n");
- out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;\n");
- out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;\n");
- out.printf("import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;\n");
-
- HashSet<String> extra = new HashSet<>();
- for (GeneratedPlugin plugin : plugins) {
- plugin.extraImports(extra);
- }
- if (!extra.isEmpty()) {
- out.printf("\n");
- for (String i : extra) {
- out.printf("import %s;\n", i);
- }
- }
- }
-
- private static void createPluginFactoryMethod(PrintWriter out, List<GeneratedPlugin> plugins) {
- out.printf(" @Override\n");
- out.printf(" public void registerPlugins(InvocationPlugins plugins, InjectionProvider injection) {\n");
- for (GeneratedPlugin plugin : plugins) {
- plugin.register(out);
- }
- out.printf(" }\n");
- }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.verifier/src/org/graalvm/compiler/replacements/verifier/VerifierAnnotationProcessor.java Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * 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.replacements.verifier;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.annotation.processing.RoundEnvironment;
-import javax.lang.model.SourceVersion;
-import javax.lang.model.element.AnnotationMirror;
-import javax.lang.model.element.Element;
-import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.DeclaredType;
-
-public class VerifierAnnotationProcessor extends AbstractProcessor {
-
- private List<AbstractVerifier> verifiers;
-
- @Override
- public SourceVersion getSupportedSourceVersion() {
- return SourceVersion.latest();
- }
-
- @Override
- public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
- if (!roundEnv.processingOver()) {
- PluginGenerator generator = new PluginGenerator();
- for (AbstractVerifier verifier : getVerifiers()) {
- Class<? extends Annotation> annotationClass = verifier.getAnnotationClass();
- for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) {
- AnnotationMirror annotationMirror = findAnnotationMirror(processingEnv, e.getAnnotationMirrors(), annotationClass);
- if (annotationMirror == null) {
- assert false : "Annotation mirror always expected.";
- continue;
- }
- verifier.verify(e, annotationMirror, generator);
- }
- }
-
- generator.generateAll(processingEnv);
- }
- return false;
- }
-
- public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List<? extends AnnotationMirror> mirrors, Class<?> annotationClass) {
- TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName());
- for (AnnotationMirror mirror : mirrors) {
- DeclaredType annotationType = mirror.getAnnotationType();
- TypeElement actualAnnotationType = (TypeElement) annotationType.asElement();
- if (actualAnnotationType.equals(expectedAnnotationType)) {
- return mirror;
- }
- }
- return null;
- }
-
- public List<AbstractVerifier> getVerifiers() {
- /*
- * Initialized lazily to fail(CNE) when the processor is invoked and not when it is created.
- */
- if (verifiers == null) {
- assert this.processingEnv != null : "ProcessingEnv must be initialized before calling getVerifiers.";
- verifiers = new ArrayList<>();
- verifiers.add(new ClassSubstitutionVerifier(this.processingEnv));
- verifiers.add(new MethodSubstitutionVerifier(this.processingEnv));
- verifiers.add(new NodeIntrinsicVerifier(this.processingEnv));
- verifiers.add(new FoldVerifier(this.processingEnv));
- }
- return verifiers;
- }
-
- @Override
- public Set<String> getSupportedAnnotationTypes() {
- Set<String> annotationTypes = new HashSet<>();
- for (AbstractVerifier verifier : getVerifiers()) {
- annotationTypes.add(verifier.getAnnotationClass().getCanonicalName());
- }
- return annotationTypes;
- }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java Thu May 31 10:38:05 2018 -0700
@@ -41,6 +41,7 @@
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.LIRKind;
import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -84,6 +85,7 @@
import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.extended.JavaReadNode;
import org.graalvm.compiler.nodes.extended.JavaWriteNode;
+import org.graalvm.compiler.nodes.extended.LoadArrayComponentHubNode;
import org.graalvm.compiler.nodes.extended.LoadHubNode;
import org.graalvm.compiler.nodes.extended.MembarNode;
import org.graalvm.compiler.nodes.extended.RawLoadNode;
@@ -109,7 +111,9 @@
import org.graalvm.compiler.nodes.java.RawMonitorEnterNode;
import org.graalvm.compiler.nodes.java.StoreFieldNode;
import org.graalvm.compiler.nodes.java.StoreIndexedNode;
+import org.graalvm.compiler.nodes.java.UnsafeCompareAndExchangeNode;
import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
+import org.graalvm.compiler.nodes.java.ValueCompareAndSwapNode;
import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
import org.graalvm.compiler.nodes.memory.ReadNode;
import org.graalvm.compiler.nodes.memory.WriteNode;
@@ -156,6 +160,7 @@
protected final ForeignCallsProvider foreignCalls;
protected final TargetDescription target;
private final boolean useCompressedOops;
+ private final ResolvedJavaType objectArrayType;
private BoxingSnippets.Templates boxingSnippets;
private ConstantStringIndexOfSnippets.Templates indexOfSnippets;
@@ -165,6 +170,7 @@
this.foreignCalls = foreignCalls;
this.target = target;
this.useCompressedOops = useCompressedOops;
+ this.objectArrayType = metaAccess.lookupJavaType(Object[].class);
}
public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, SnippetCounter.Group.Factory factory, Providers providers, SnippetReflectionProvider snippetReflection) {
@@ -178,57 +184,64 @@
}
@Override
+ @SuppressWarnings("try")
public void lower(Node n, LoweringTool tool) {
assert n instanceof Lowerable;
StructuredGraph graph = (StructuredGraph) n.graph();
- if (n instanceof LoadFieldNode) {
- lowerLoadFieldNode((LoadFieldNode) n, tool);
- } else if (n instanceof StoreFieldNode) {
- lowerStoreFieldNode((StoreFieldNode) n, tool);
- } else if (n instanceof LoadIndexedNode) {
- lowerLoadIndexedNode((LoadIndexedNode) n, tool);
- } else if (n instanceof StoreIndexedNode) {
- lowerStoreIndexedNode((StoreIndexedNode) n, tool);
- } else if (n instanceof ArrayLengthNode) {
- lowerArrayLengthNode((ArrayLengthNode) n, tool);
- } else if (n instanceof LoadHubNode) {
- lowerLoadHubNode((LoadHubNode) n, tool);
- } else if (n instanceof MonitorEnterNode) {
- lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
- } else if (n instanceof UnsafeCompareAndSwapNode) {
- lowerCompareAndSwapNode((UnsafeCompareAndSwapNode) n);
- } else if (n instanceof AtomicReadAndWriteNode) {
- lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
- } else if (n instanceof RawLoadNode) {
- lowerUnsafeLoadNode((RawLoadNode) n, tool);
- } else if (n instanceof UnsafeMemoryLoadNode) {
- lowerUnsafeMemoryLoadNode((UnsafeMemoryLoadNode) n);
- } else if (n instanceof RawStoreNode) {
- lowerUnsafeStoreNode((RawStoreNode) n);
- } else if (n instanceof UnsafeMemoryStoreNode) {
- lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
- } else if (n instanceof JavaReadNode) {
- lowerJavaReadNode((JavaReadNode) n);
- } else if (n instanceof JavaWriteNode) {
- lowerJavaWriteNode((JavaWriteNode) n);
- } else if (n instanceof CommitAllocationNode) {
- lowerCommitAllocationNode((CommitAllocationNode) n, tool);
- } else if (n instanceof BoxNode) {
- boxingSnippets.lower((BoxNode) n, tool);
- } else if (n instanceof UnboxNode) {
- boxingSnippets.lower((UnboxNode) n, tool);
- } else if (n instanceof VerifyHeapNode) {
- lowerVerifyHeap((VerifyHeapNode) n);
- } else if (n instanceof UnaryMathIntrinsicNode) {
- lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
- } else if (n instanceof BinaryMathIntrinsicNode) {
- lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
- } else if (n instanceof StringIndexOfNode) {
- lowerIndexOf((StringIndexOfNode) n);
- } else if (n instanceof UnpackEndianHalfNode) {
- lowerSecondHalf((UnpackEndianHalfNode) n);
- } else {
- throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+ try (DebugCloseable context = n.withNodeSourcePosition()) {
+ if (n instanceof LoadFieldNode) {
+ lowerLoadFieldNode((LoadFieldNode) n, tool);
+ } else if (n instanceof StoreFieldNode) {
+ lowerStoreFieldNode((StoreFieldNode) n, tool);
+ } else if (n instanceof LoadIndexedNode) {
+ lowerLoadIndexedNode((LoadIndexedNode) n, tool);
+ } else if (n instanceof StoreIndexedNode) {
+ lowerStoreIndexedNode((StoreIndexedNode) n, tool);
+ } else if (n instanceof ArrayLengthNode) {
+ lowerArrayLengthNode((ArrayLengthNode) n, tool);
+ } else if (n instanceof LoadHubNode) {
+ lowerLoadHubNode((LoadHubNode) n, tool);
+ } else if (n instanceof LoadArrayComponentHubNode) {
+ lowerLoadArrayComponentHubNode((LoadArrayComponentHubNode) n);
+ } else if (n instanceof MonitorEnterNode) {
+ lowerMonitorEnterNode((MonitorEnterNode) n, tool, graph);
+ } else if (n instanceof UnsafeCompareAndSwapNode) {
+ lowerCompareAndSwapNode((UnsafeCompareAndSwapNode) n);
+ } else if (n instanceof UnsafeCompareAndExchangeNode) {
+ lowerCompareAndExchangeNode((UnsafeCompareAndExchangeNode) n);
+ } else if (n instanceof AtomicReadAndWriteNode) {
+ lowerAtomicReadAndWriteNode((AtomicReadAndWriteNode) n);
+ } else if (n instanceof RawLoadNode) {
+ lowerUnsafeLoadNode((RawLoadNode) n, tool);
+ } else if (n instanceof UnsafeMemoryLoadNode) {
+ lowerUnsafeMemoryLoadNode((UnsafeMemoryLoadNode) n);
+ } else if (n instanceof RawStoreNode) {
+ lowerUnsafeStoreNode((RawStoreNode) n);
+ } else if (n instanceof UnsafeMemoryStoreNode) {
+ lowerUnsafeMemoryStoreNode((UnsafeMemoryStoreNode) n);
+ } else if (n instanceof JavaReadNode) {
+ lowerJavaReadNode((JavaReadNode) n);
+ } else if (n instanceof JavaWriteNode) {
+ lowerJavaWriteNode((JavaWriteNode) n);
+ } else if (n instanceof CommitAllocationNode) {
+ lowerCommitAllocationNode((CommitAllocationNode) n, tool);
+ } else if (n instanceof BoxNode) {
+ boxingSnippets.lower((BoxNode) n, tool);
+ } else if (n instanceof UnboxNode) {
+ boxingSnippets.lower((UnboxNode) n, tool);
+ } else if (n instanceof VerifyHeapNode) {
+ lowerVerifyHeap((VerifyHeapNode) n);
+ } else if (n instanceof UnaryMathIntrinsicNode) {
+ lowerUnaryMath((UnaryMathIntrinsicNode) n, tool);
+ } else if (n instanceof BinaryMathIntrinsicNode) {
+ lowerBinaryMath((BinaryMathIntrinsicNode) n, tool);
+ } else if (n instanceof StringIndexOfNode) {
+ lowerIndexOf((StringIndexOfNode) n);
+ } else if (n instanceof UnpackEndianHalfNode) {
+ lowerSecondHalf((UnpackEndianHalfNode) n);
+ } else {
+ throw GraalError.shouldNotReachHere("Node implementing Lowerable not handled: " + n);
+ }
}
}
@@ -445,7 +458,7 @@
JavaKind elementKind = storeIndexed.elementKind();
LogicNode condition = null;
- if (elementKind == JavaKind.Object && !StampTool.isPointerAlwaysNull(value)) {
+ if (storeIndexed.getStoreCheck() == null && elementKind == JavaKind.Object && !StampTool.isPointerAlwaysNull(value)) {
/* Array store check. */
TypeReference arrayType = StampTool.typeReferenceOrNull(array);
if (arrayType != null && arrayType.isExact()) {
@@ -510,6 +523,12 @@
loadHub.replaceAtUsagesAndDelete(hub);
}
+ protected void lowerLoadArrayComponentHubNode(LoadArrayComponentHubNode loadHub) {
+ StructuredGraph graph = loadHub.graph();
+ ValueNode hub = createReadArrayComponentHub(graph, loadHub.getValue(), loadHub);
+ graph.replaceFixed(loadHub, hub);
+ }
+
protected void lowerMonitorEnterNode(MonitorEnterNode monitorEnter, LoweringTool tool, StructuredGraph graph) {
ValueNode object = createNullCheckedValue(monitorEnter.object(), monitorEnter, tool);
ValueNode hub = graph.addOrUnique(LoadHubNode.create(object, tool.getStampProvider(), tool.getMetaAccess(), tool.getConstantReflection()));
@@ -527,12 +546,28 @@
ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
- BarrierType barrierType = storeBarrierType(cas.object(), expectedValue);
+ BarrierType barrierType = guessStoreBarrierType(cas.object(), expectedValue);
LogicCompareAndSwapNode atomicNode = graph.add(new LogicCompareAndSwapNode(address, cas.getLocationIdentity(), expectedValue, newValue, barrierType));
atomicNode.setStateAfter(cas.stateAfter());
graph.replaceFixedWithFixed(cas, atomicNode);
}
+ protected void lowerCompareAndExchangeNode(UnsafeCompareAndExchangeNode cas) {
+ StructuredGraph graph = cas.graph();
+ JavaKind valueKind = cas.getValueKind();
+
+ ValueNode expectedValue = implicitStoreConvert(graph, valueKind, cas.expected());
+ ValueNode newValue = implicitStoreConvert(graph, valueKind, cas.newValue());
+
+ AddressNode address = graph.unique(new OffsetAddressNode(cas.object(), cas.offset()));
+ BarrierType barrierType = guessStoreBarrierType(cas.object(), expectedValue);
+ ValueCompareAndSwapNode atomicNode = graph.add(new ValueCompareAndSwapNode(address, expectedValue, newValue, cas.getLocationIdentity(), barrierType));
+ ValueNode coercedNode = implicitLoadConvert(graph, valueKind, atomicNode, true);
+ atomicNode.setStateAfter(cas.stateAfter());
+ cas.replaceAtUsages(coercedNode);
+ graph.replaceFixedWithFixed(cas, atomicNode);
+ }
+
protected void lowerAtomicReadAndWriteNode(AtomicReadAndWriteNode n) {
StructuredGraph graph = n.graph();
JavaKind valueKind = n.getValueKind();
@@ -540,8 +575,9 @@
ValueNode newValue = implicitStoreConvert(graph, valueKind, n.newValue());
AddressNode address = graph.unique(new OffsetAddressNode(n.object(), n.offset()));
- BarrierType barrierType = storeBarrierType(n.object(), n.newValue());
- LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, barrierType));
+ BarrierType barrierType = guessStoreBarrierType(n.object(), n.newValue());
+ LIRKind lirAccessKind = LIRKind.fromJavaKind(target.arch, valueKind);
+ LoweredAtomicReadAndWriteNode memoryRead = graph.add(new LoweredAtomicReadAndWriteNode(address, n.getLocationIdentity(), newValue, lirAccessKind, barrierType));
memoryRead.setStateAfter(n.stateAfter());
ValueNode readValue = implicitLoadConvert(graph, valueKind, memoryRead);
@@ -687,85 +723,87 @@
int valuePos = 0;
for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
- int entryCount = virtual.entryCount();
- AbstractNewObjectNode newObject;
- try (DebugCloseable nsp = virtual.withNodeSourcePosition()) {
+ try (DebugCloseable nsp = graph.withNodeSourcePosition(virtual)) {
+ int entryCount = virtual.entryCount();
+ AbstractNewObjectNode newObject;
if (virtual instanceof VirtualInstanceNode) {
newObject = graph.add(createNewInstanceFromVirtual(virtual));
} else {
newObject = graph.add(createNewArrayFromVirtual(virtual, ConstantNode.forInt(entryCount, graph)));
}
- }
- recursiveLowerings.add(newObject);
- graph.addBeforeFixed(commit, newObject);
- allocations[objIndex] = newObject;
- for (int i = 0; i < entryCount; i++) {
- ValueNode value = commit.getValues().get(valuePos);
- if (value instanceof VirtualObjectNode) {
- value = allocations[commit.getVirtualObjects().indexOf(value)];
- }
- if (value == null) {
- omittedValues.set(valuePos);
- } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
- // Constant.illegal is always the defaultForKind, so it is skipped
- JavaKind valueKind = value.getStackKind();
- JavaKind entryKind = virtual.entryKind(i);
+
+ recursiveLowerings.add(newObject);
+ graph.addBeforeFixed(commit, newObject);
+ allocations[objIndex] = newObject;
+ for (int i = 0; i < entryCount; i++) {
+ ValueNode value = commit.getValues().get(valuePos);
+ if (value instanceof VirtualObjectNode) {
+ value = allocations[commit.getVirtualObjects().indexOf(value)];
+ }
+ if (value == null) {
+ omittedValues.set(valuePos);
+ } else if (!(value.isConstant() && value.asConstant().isDefaultForKind())) {
+ // Constant.illegal is always the defaultForKind, so it is skipped
+ JavaKind valueKind = value.getStackKind();
+ JavaKind entryKind = virtual.entryKind(i);
- // Truffle requires some leniency in terms of what can be put where:
- assert valueKind.getStackKind() == entryKind.getStackKind() ||
- (valueKind == JavaKind.Long || valueKind == JavaKind.Double || (valueKind == JavaKind.Int && virtual instanceof VirtualArrayNode));
- AddressNode address = null;
- BarrierType barrierType = null;
- if (virtual instanceof VirtualInstanceNode) {
- ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
- long offset = fieldOffset(field);
- if (offset >= 0) {
- address = createOffsetAddress(graph, newObject, offset);
- barrierType = fieldInitializationBarrier(entryKind);
+ // Truffle requires some leniency in terms of what can be put where:
+ assert valueKind.getStackKind() == entryKind.getStackKind() ||
+ (valueKind == JavaKind.Long || valueKind == JavaKind.Double || (valueKind == JavaKind.Int && virtual instanceof VirtualArrayNode));
+ AddressNode address = null;
+ BarrierType barrierType = null;
+ if (virtual instanceof VirtualInstanceNode) {
+ ResolvedJavaField field = ((VirtualInstanceNode) virtual).field(i);
+ long offset = fieldOffset(field);
+ if (offset >= 0) {
+ address = createOffsetAddress(graph, newObject, offset);
+ barrierType = fieldInitializationBarrier(entryKind);
+ }
+ } else {
+ address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
+ barrierType = arrayInitializationBarrier(entryKind);
}
- } else {
- address = createOffsetAddress(graph, newObject, arrayBaseOffset(entryKind) + i * arrayScalingFactor(entryKind));
- barrierType = arrayInitializationBarrier(entryKind);
+ if (address != null) {
+ WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
+ graph.addAfterFixed(newObject, graph.add(write));
+ }
}
- if (address != null) {
- WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, entryKind, value), barrierType);
- graph.addAfterFixed(newObject, graph.add(write));
- }
+ valuePos++;
}
- valuePos++;
-
}
}
valuePos = 0;
for (int objIndex = 0; objIndex < commit.getVirtualObjects().size(); objIndex++) {
VirtualObjectNode virtual = commit.getVirtualObjects().get(objIndex);
- int entryCount = virtual.entryCount();
- ValueNode newObject = allocations[objIndex];
- for (int i = 0; i < entryCount; i++) {
- if (omittedValues.get(valuePos)) {
- ValueNode value = commit.getValues().get(valuePos);
- assert value instanceof VirtualObjectNode;
- ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
- if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
- assert virtual.entryKind(i) == JavaKind.Object && allocValue.getStackKind() == JavaKind.Object;
- AddressNode address;
- BarrierType barrierType;
- if (virtual instanceof VirtualInstanceNode) {
- VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
- address = createFieldAddress(graph, newObject, virtualInstance.field(i));
- barrierType = BarrierType.IMPRECISE;
- } else {
- address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
- barrierType = BarrierType.PRECISE;
- }
- if (address != null) {
- WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
- graph.addBeforeFixed(commit, graph.add(write));
+ try (DebugCloseable nsp = graph.withNodeSourcePosition(virtual)) {
+ int entryCount = virtual.entryCount();
+ ValueNode newObject = allocations[objIndex];
+ for (int i = 0; i < entryCount; i++) {
+ if (omittedValues.get(valuePos)) {
+ ValueNode value = commit.getValues().get(valuePos);
+ assert value instanceof VirtualObjectNode;
+ ValueNode allocValue = allocations[commit.getVirtualObjects().indexOf(value)];
+ if (!(allocValue.isConstant() && allocValue.asConstant().isDefaultForKind())) {
+ assert virtual.entryKind(i) == JavaKind.Object && allocValue.getStackKind() == JavaKind.Object;
+ AddressNode address;
+ BarrierType barrierType;
+ if (virtual instanceof VirtualInstanceNode) {
+ VirtualInstanceNode virtualInstance = (VirtualInstanceNode) virtual;
+ address = createFieldAddress(graph, newObject, virtualInstance.field(i));
+ barrierType = BarrierType.IMPRECISE;
+ } else {
+ address = createArrayAddress(graph, newObject, virtual.entryKind(i), ConstantNode.forInt(i, graph));
+ barrierType = BarrierType.PRECISE;
+ }
+ if (address != null) {
+ WriteNode write = new WriteNode(address, LocationIdentity.init(), implicitStoreConvert(graph, JavaKind.Object, allocValue), barrierType);
+ graph.addBeforeFixed(commit, graph.add(write));
+ }
}
}
+ valuePos++;
}
- valuePos++;
}
}
@@ -776,6 +814,7 @@
recursiveLowering.lower(tool);
}
}
+
}
public NewInstanceNode createNewInstanceFromVirtual(VirtualObjectNode virtual) {
@@ -890,20 +929,22 @@
return entryKind == JavaKind.Object ? BarrierType.PRECISE : BarrierType.NONE;
}
- private static BarrierType unsafeStoreBarrierType(RawStoreNode store) {
+ private BarrierType unsafeStoreBarrierType(RawStoreNode store) {
if (!store.needsBarrier()) {
return BarrierType.NONE;
}
- return storeBarrierType(store.object(), store.value());
+ return guessStoreBarrierType(store.object(), store.value());
}
- private static BarrierType storeBarrierType(ValueNode object, ValueNode value) {
+ private BarrierType guessStoreBarrierType(ValueNode object, ValueNode value) {
if (value.getStackKind() == JavaKind.Object && object.getStackKind() == JavaKind.Object) {
ResolvedJavaType type = StampTool.typeOrNull(object);
- if (type != null && !type.isArray()) {
+ // Array types must use a precise barrier, so if the type is unknown or is a supertype
+ // of Object[] then treat it as an array.
+ if (type == null || type.isArray() || type.isAssignableFrom(objectArrayType)) {
+ return BarrierType.PRECISE;
+ } else {
return BarrierType.IMPRECISE;
- } else {
- return BarrierType.PRECISE;
}
}
return BarrierType.NONE;
@@ -1030,6 +1071,10 @@
protected abstract ValueNode createReadArrayComponentHub(StructuredGraph graph, ValueNode arrayHub, FixedNode anchor);
protected GuardingNode getBoundsCheck(AccessIndexedNode n, ValueNode array, LoweringTool tool) {
+ if (n.getBoundsCheck() != null) {
+ return n.getBoundsCheck();
+ }
+
StructuredGraph graph = n.graph();
ValueNode arrayLength = readArrayLength(array, tool.getConstantReflection());
if (arrayLength == null) {
@@ -1049,7 +1094,7 @@
if (StampTool.isPointerNonNull(object)) {
return null;
}
- return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true);
+ return tool.createGuard(before, before.graph().unique(IsNullNode.create(object)), NullCheckException, InvalidateReprofile, JavaConstant.NULL_POINTER, true, null);
}
protected ValueNode createNullCheckedValue(ValueNode object, FixedNode before, LoweringTool tool) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/GraphKit.java Thu May 31 10:38:05 2018 -0700
@@ -359,7 +359,7 @@
calleeGraph.setTrackNodeSourcePosition();
}
IntrinsicContext initialReplacementContext = new IntrinsicContext(method, method, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING);
- GraphBuilderPhase.Instance instance = new GraphBuilderPhase.Instance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
+ GraphBuilderPhase.Instance instance = createGraphBuilderInstance(metaAccess, providers.getStampProvider(), providers.getConstantReflection(), providers.getConstantFieldProvider(), config,
OptimisticOptimizations.NONE,
initialReplacementContext);
instance.apply(calleeGraph);
@@ -371,6 +371,11 @@
InliningUtil.inline(invoke, calleeGraph, false, method, reason, phase);
}
+ protected GraphBuilderPhase.Instance createGraphBuilderInstance(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection,
+ ConstantFieldProvider constantFieldProvider, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
+ return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts, initialIntrinsicContext);
+ }
+
protected void pushStructure(Structure structure) {
structures.add(structure);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java Thu May 31 10:38:05 2018 -0700
@@ -22,6 +22,7 @@
*/
package org.graalvm.compiler.replacements;
+import java.net.URI;
import static org.graalvm.compiler.debug.GraalError.unimplemented;
import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
@@ -34,6 +35,7 @@
import jdk.internal.vm.compiler.collections.EconomicMap;
import jdk.internal.vm.compiler.collections.Equivalence;
+import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.bytecode.Bytecode;
import org.graalvm.compiler.bytecode.BytecodeProvider;
import org.graalvm.compiler.core.common.PermanentBailoutException;
@@ -46,6 +48,7 @@
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.debug.GraalError;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.SourceLanguagePosition;
@@ -78,6 +81,7 @@
import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
import org.graalvm.compiler.nodes.extended.ForeignCallNode;
import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
+import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
@@ -157,7 +161,7 @@
protected final int inliningDepth;
protected final ValueNode[] arguments;
- private final SourceLanguagePosition sourceLanguagePosition;
+ private SourceLanguagePosition sourceLanguagePosition = UnresolvedSourceLanguagePosition.INSTANCE;
protected FrameState outerState;
protected FrameState exceptionState;
@@ -173,13 +177,6 @@
this.invokeData = invokeData;
this.inliningDepth = inliningDepth;
this.arguments = arguments;
- SourceLanguagePosition position = null;
- if (arguments != null && method.hasReceiver() && arguments.length > 0 && arguments[0].isJavaConstant()) {
- JavaConstant constantArgument = arguments[0].asJavaConstant();
- position = sourceLanguagePositionProvider.getPosition(constantArgument);
- }
- this.sourceLanguagePosition = position;
-
}
@Override
@@ -201,13 +198,61 @@
callerBytecodePosition = invokePosition;
}
if (position != null) {
- return position.addCaller(caller.sourceLanguagePosition, callerBytecodePosition);
+ return position.addCaller(caller.resolveSourceLanguagePosition(), callerBytecodePosition);
}
- if (caller.sourceLanguagePosition != null && callerBytecodePosition != null) {
- return new NodeSourcePosition(caller.sourceLanguagePosition, callerBytecodePosition.getCaller(), callerBytecodePosition.getMethod(), callerBytecodePosition.getBCI());
+ final SourceLanguagePosition pos = caller.resolveSourceLanguagePosition();
+ if (pos != null && callerBytecodePosition != null) {
+ return new NodeSourcePosition(pos, callerBytecodePosition.getCaller(), callerBytecodePosition.getMethod(), callerBytecodePosition.getBCI());
}
return callerBytecodePosition;
}
+
+ private SourceLanguagePosition resolveSourceLanguagePosition() {
+ SourceLanguagePosition res = sourceLanguagePosition;
+ if (res == UnresolvedSourceLanguagePosition.INSTANCE) {
+ res = null;
+ if (arguments != null && method.hasReceiver() && arguments.length > 0 && arguments[0].isJavaConstant()) {
+ JavaConstant constantArgument = arguments[0].asJavaConstant();
+ res = sourceLanguagePositionProvider.getPosition(constantArgument);
+ }
+ sourceLanguagePosition = res;
+ }
+ return res;
+ }
+ }
+
+ private static final class UnresolvedSourceLanguagePosition implements SourceLanguagePosition {
+ static final SourceLanguagePosition INSTANCE = new UnresolvedSourceLanguagePosition();
+
+ @Override
+ public String toShortString() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
+
+ @Override
+ public int getOffsetEnd() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
+
+ @Override
+ public int getOffsetStart() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
+
+ @Override
+ public int getLineNumber() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
+
+ @Override
+ public URI getURI() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
+
+ @Override
+ public String getLanguage() {
+ throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable.");
+ }
}
protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
@@ -237,6 +282,21 @@
this.invoke = invoke;
}
+ /**
+ * {@link Fold} and {@link NodeIntrinsic} can be deferred during parsing/decoding. Only by
+ * the end of {@linkplain SnippetTemplate#instantiate Snippet instantiation} do they need to
+ * have been processed.
+ *
+ * This is how SVM handles snippets. They are parsed with plugins disabled and then encoded
+ * and stored in the image. When the snippet is needed at runtime the graph is decoded and
+ * the plugins are run during the decoding process. If they aren't handled at this point
+ * then they will never be handled.
+ */
+ @Override
+ public boolean canDeferPlugin(GeneratedInvocationPlugin plugin) {
+ return plugin.getSource().equals(Fold.class) || plugin.getSource().equals(Node.NodeIntrinsic.class);
+ }
+
@Override
public BailoutException bailout(String string) {
BailoutException bailout = new PermanentBailoutException(string);
@@ -1056,7 +1116,7 @@
ValueNode array = loadIndexedNode.array();
ValueNode index = loadIndexedNode.index();
for (NodePlugin nodePlugin : nodePlugins) {
- if (nodePlugin.handleLoadIndexed(graphBuilderContext, array, index, loadIndexedNode.elementKind())) {
+ if (nodePlugin.handleLoadIndexed(graphBuilderContext, array, index, loadIndexedNode.getBoundsCheck(), loadIndexedNode.elementKind())) {
replacedNode = graphBuilderContext.pushedNode;
break;
}
@@ -1068,7 +1128,7 @@
ValueNode index = storeIndexedNode.index();
ValueNode value = storeIndexedNode.value();
for (NodePlugin nodePlugin : nodePlugins) {
- if (nodePlugin.handleStoreIndexed(graphBuilderContext, array, index, storeIndexedNode.elementKind(), value)) {
+ if (nodePlugin.handleStoreIndexed(graphBuilderContext, array, index, storeIndexedNode.getBoundsCheck(), storeIndexedNode.getStoreCheck(), storeIndexedNode.elementKind(), value)) {
replacedNode = graphBuilderContext.pushedNode;
break;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java Thu May 31 10:38:05 2018 -0700
@@ -51,6 +51,7 @@
import jdk.internal.vm.compiler.collections.EconomicSet;
import jdk.internal.vm.compiler.collections.Equivalence;
import jdk.internal.vm.compiler.collections.UnmodifiableEconomicMap;
+import org.graalvm.compiler.api.replacements.Fold;
import org.graalvm.compiler.api.replacements.Snippet;
import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
@@ -70,6 +71,7 @@
import org.graalvm.compiler.debug.TimerKey;
import org.graalvm.compiler.graph.Graph.Mark;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.Node.NodeIntrinsic;
import org.graalvm.compiler.graph.NodeClass;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.graph.Position;
@@ -103,6 +105,7 @@
import org.graalvm.compiler.nodes.ValueNodeUtil;
import org.graalvm.compiler.nodes.calc.FloatingNode;
import org.graalvm.compiler.nodes.java.LoadIndexedNode;
+import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
import org.graalvm.compiler.nodes.java.StoreIndexedNode;
import org.graalvm.compiler.nodes.memory.MemoryAccess;
import org.graalvm.compiler.nodes.memory.MemoryAnchorNode;
@@ -510,7 +513,7 @@
}
@Override
- public ValueNode length() {
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
return ConstantNode.forInt(varargs.length);
}
}
@@ -955,6 +958,8 @@
merge.setNext(this.returnNode);
}
+ assert verifyIntrinsicsProcessed(snippetCopy);
+
this.sideEffectNodes = curSideEffectNodes;
this.deoptNodes = curDeoptNodes;
this.placeholderStampedNodes = curPlaceholderStampedNodes;
@@ -977,6 +982,16 @@
}
}
+ private static boolean verifyIntrinsicsProcessed(StructuredGraph snippetCopy) {
+ for (MethodCallTargetNode target : snippetCopy.getNodes(MethodCallTargetNode.TYPE)) {
+ ResolvedJavaMethod targetMethod = target.targetMethod();
+ if (targetMethod != null) {
+ assert targetMethod.getAnnotation(Fold.class) == null && targetMethod.getAnnotation(NodeIntrinsic.class) == null : "plugin should have been processed";
+ }
+ }
+ return true;
+ }
+
public static void explodeLoops(final StructuredGraph snippetCopy, PhaseContext phaseContext) {
// Do any required loop explosion
boolean exploded = false;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java Thu May 31 10:38:05 2018 -0700
@@ -37,8 +37,6 @@
import java.lang.reflect.Field;
import java.util.Arrays;
-import jdk.vm.ci.code.BytecodePosition;
-import jdk.vm.ci.meta.SpeculationLog;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
import org.graalvm.compiler.bytecode.BytecodeProvider;
@@ -63,6 +61,7 @@
import org.graalvm.compiler.nodes.calc.AbsNode;
import org.graalvm.compiler.nodes.calc.CompareNode;
import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatEqualsNode;
import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
import org.graalvm.compiler.nodes.calc.NarrowNode;
import org.graalvm.compiler.nodes.calc.ReinterpretNode;
@@ -97,6 +96,7 @@
import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
import org.graalvm.compiler.nodes.java.LoadFieldNode;
import org.graalvm.compiler.nodes.java.RegisterFinalizerNode;
+import org.graalvm.compiler.nodes.java.UnsafeCompareAndExchangeNode;
import org.graalvm.compiler.nodes.java.UnsafeCompareAndSwapNode;
import org.graalvm.compiler.nodes.util.GraphUtil;
import org.graalvm.compiler.nodes.virtual.EnsureVirtualizedNode;
@@ -107,6 +107,7 @@
import org.graalvm.compiler.replacements.nodes.arithmetic.IntegerSubExactNode;
import jdk.internal.vm.compiler.word.LocationIdentity;
+import jdk.vm.ci.code.BytecodePosition;
import jdk.vm.ci.meta.DeoptimizationAction;
import jdk.vm.ci.meta.DeoptimizationReason;
import jdk.vm.ci.meta.JavaConstant;
@@ -115,6 +116,7 @@
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.SpeculationLog;
import sun.misc.Unsafe;
/**
@@ -210,6 +212,76 @@
r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class);
}
+ private abstract static class UnsafeCompareAndUpdatePluginsRegistrar {
+ public void register(Registration r, String casPrefix, JavaKind[] compareAndSwapTypes) {
+ for (JavaKind kind : compareAndSwapTypes) {
+ Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
+ r.register5(casPrefix + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
+ // Emits a null-check for the otherwise unused receiver
+ unsafe.get();
+ b.addPush(returnKind(kind), createNode(object, offset, expected, x, kind, LocationIdentity.any()));
+ b.getGraph().markUnsafeAccess();
+ return true;
+ }
+ });
+ }
+ }
+
+ public abstract ValueNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity);
+
+ public abstract JavaKind returnKind(JavaKind accessKind);
+ }
+
+ private static class UnsafeCompareAndSwapPluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar {
+ @Override
+ public ValueNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) {
+ return new UnsafeCompareAndSwapNode(object, offset, expected, newValue, kind, LocationIdentity.any());
+ }
+
+ @Override
+ public JavaKind returnKind(JavaKind accessKind) {
+ return JavaKind.Boolean.getStackKind();
+ }
+ }
+
+ private static UnsafeCompareAndSwapPluginsRegistrar unsafeCompareAndSwapPluginsRegistrar = new UnsafeCompareAndSwapPluginsRegistrar();
+
+ private static class UnsafeCompareAndExchangePluginsRegistrar extends UnsafeCompareAndUpdatePluginsRegistrar {
+ @Override
+ public ValueNode createNode(ValueNode object, ValueNode offset, ValueNode expected, ValueNode newValue, JavaKind kind, LocationIdentity identity) {
+ return new UnsafeCompareAndExchangeNode(object, offset, expected, newValue, kind, LocationIdentity.any());
+ }
+
+ @Override
+ public JavaKind returnKind(JavaKind accessKind) {
+ if (accessKind.isNumericInteger()) {
+ return accessKind.getStackKind();
+ } else {
+ return accessKind;
+ }
+ }
+ }
+
+ private static UnsafeCompareAndExchangePluginsRegistrar unsafeCompareAndExchangePluginsRegistrar = new UnsafeCompareAndExchangePluginsRegistrar();
+
+ public static void registerPlatformSpecificUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider, JavaKind[] supportedCasKinds) {
+ Registration r;
+ if (Java8OrEarlier) {
+ r = new Registration(plugins, Unsafe.class);
+ } else {
+ r = new Registration(plugins, "jdk.internal.misc.Unsafe", bytecodeProvider);
+ }
+
+ if (Java8OrEarlier) {
+ unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSwap", new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object});
+ } else {
+ unsafeCompareAndSwapPluginsRegistrar.register(r, "compareAndSet", supportedCasKinds);
+ unsafeCompareAndExchangePluginsRegistrar.register(r, "compareAndExchange", supportedCasKinds);
+ }
+ }
+
private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
Registration r;
if (Java8OrEarlier) {
@@ -250,26 +322,6 @@
r.register2("getAddress", Receiver.class, long.class, new UnsafeGetPlugin(JavaKind.Long, false));
r.register3("putAddress", Receiver.class, long.class, long.class, new UnsafePutPlugin(JavaKind.Long, false));
- for (JavaKind kind : new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}) {
- Class<?> javaClass = kind == JavaKind.Object ? Object.class : kind.toJavaClass();
- String casName;
- if (Java8OrEarlier) {
- casName = "compareAndSwap";
- } else {
- casName = "compareAndSet";
- }
- r.register5(casName + kind.name(), Receiver.class, Object.class, long.class, javaClass, javaClass, new InvocationPlugin() {
- @Override
- public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode object, ValueNode offset, ValueNode expected, ValueNode x) {
- // Emits a null-check for the otherwise unused receiver
- unsafe.get();
- b.addPush(JavaKind.Int, new UnsafeCompareAndSwapNode(object, offset, expected, x, kind, LocationIdentity.any()));
- b.getGraph().markUnsafeAccess();
- return true;
- }
- });
- }
-
r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() {
@Override
@@ -301,14 +353,14 @@
r.register2("divideUnsigned", type, type, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
- b.push(kind, b.append(UnsignedDivNode.create(dividend, divisor, NodeView.DEFAULT)));
+ b.push(kind, b.append(UnsignedDivNode.create(dividend, divisor, null, NodeView.DEFAULT)));
return true;
}
});
r.register2("remainderUnsigned", type, type, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode dividend, ValueNode divisor) {
- b.push(kind, b.append(UnsignedRemNode.create(dividend, divisor, NodeView.DEFAULT)));
+ b.push(kind, b.append(UnsignedRemNode.create(dividend, divisor, null, NodeView.DEFAULT)));
return true;
}
});
@@ -353,6 +405,16 @@
return true;
}
});
+ r.register1("floatToIntBits", float.class, new InvocationPlugin() {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+ LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
+ ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Int, value, NodeView.DEFAULT));
+ ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forInt(0x7fc00000), NodeView.DEFAULT));
+ b.push(JavaKind.Int, result);
+ return true;
+ }
+ });
r.register1("intBitsToFloat", int.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
@@ -371,6 +433,16 @@
return true;
}
});
+ r.register1("doubleToLongBits", double.class, new InvocationPlugin() {
+ @Override
+ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
+ LogicNode notNan = b.append(FloatEqualsNode.create(value, value, NodeView.DEFAULT));
+ ValueNode raw = b.append(ReinterpretNode.create(JavaKind.Long, value, NodeView.DEFAULT));
+ ValueNode result = b.append(ConditionalNode.create(notNan, raw, ConstantNode.forLong(0x7ff8000000000000L), NodeView.DEFAULT));
+ b.push(JavaKind.Long, result);
+ return true;
+ }
+ });
r.register1("longBitsToDouble", long.class, new InvocationPlugin() {
@Override
public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) {
@@ -906,6 +978,11 @@
b.add(new BlackholeNode(value));
return true;
}
+
+ @Override
+ public boolean isDecorator() {
+ return true;
+ }
};
String[] names = {"org.openjdk.jmh.infra.Blackhole", "org.openjdk.jmh.logic.BlackHole"};
for (String name : names) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/D Thu May 31 10:14:41 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
-index 88403c3..728297d 100644
---- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
-+++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java
-@@ -138,7 +138,11 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider {
- return classfile;
- }
-
-- synchronized Class<?> resolveToClass(String descriptor) {
-+ Class<?> resolveToClass(String descriptor) {
-+ return resolveToClass(descriptor, false);
-+ }
-+
-+ synchronized Class<?> resolveToClass(String descriptor, boolean initialize) {
- Class<?> c = classes.get(descriptor);
- if (c == null) {
- if (descriptor.length() == 1) {
-@@ -155,7 +159,7 @@ public final class ClassfileBytecodeProvider implements BytecodeProvider {
- name = descriptor.replace('/', '.');
- }
- try {
-- c = Class.forName(name, true, loader);
-+ c = Class.forName(name, initialize, loader);
- classes.put(descriptor, c);
- } catch (ClassNotFoundException e) {
- throw new NoClassDefFoundError(descriptor);
-diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java
-index 087f78b..bde2dd4 100644
---- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java
-+++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java
-@@ -70,8 +70,9 @@ abstract class ClassfileConstant {
- * @param cp
- * @param index
- * @param opcode
-+ * @param initialize
- */
-- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
-+ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) {
- }
-
- @Override
-@@ -90,15 +91,19 @@ abstract class ClassfileConstant {
- }
-
- @Override
-- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
-- resolve(cp);
-+ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) {
-+ resolve(cp, initialize);
- }
-
- public ResolvedJavaType resolve(ClassfileConstantPool cp) throws GraalError {
-+ return resolve(cp, false /* initialize */);
-+ }
-+
-+ public ResolvedJavaType resolve(ClassfileConstantPool cp, boolean initialize) throws GraalError {
- if (type == null) {
- String typeDescriptor = cp.get(Utf8.class, nameIndex).value;
- ClassfileBytecodeProvider context = cp.context;
-- type = context.metaAccess.lookupJavaType(context.resolveToClass(typeDescriptor));
-+ type = context.metaAccess.lookupJavaType(context.resolveToClass(typeDescriptor, initialize));
- }
- return type;
- }
-@@ -116,8 +121,8 @@ abstract class ClassfileConstant {
- }
-
- @Override
-- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
-- cp.get(ClassRef.class, classIndex).loadReferencedType(cp, classIndex, opcode);
-+ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) {
-+ cp.get(ClassRef.class, classIndex).loadReferencedType(cp, classIndex, opcode, initialize);
- }
- }
-
-@@ -269,7 +274,7 @@ abstract class ClassfileConstant {
- }
-
- @Override
-- public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode) {
-+ public void loadReferencedType(ClassfileConstantPool cp, int index, int opcode, boolean initialize) {
- throw new GraalError("Resolution of " + name + " constant pool entries not supported by " + ClassfileBytecodeProvider.class.getSimpleName());
- }
- }
-diff --git a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java
-index 218df10..a54779b 100644
---- a/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java
-+++ b/compiler/src/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java
-@@ -133,11 +133,11 @@ class ClassfileConstantPool implements ConstantPool {
- }
-
- @Override
-- public void loadReferencedType(int index, int opcode) {
-+ public void loadReferencedType(int index, int opcode, boolean initialize) {
- if (opcode == Bytecodes.INVOKEDYNAMIC) {
- throw new GraalError("INVOKEDYNAMIC not supported by " + ClassfileBytecodeProvider.class.getSimpleName());
- }
-- entries[index].loadReferencedType(this, index, opcode);
-+ entries[index].loadReferencedType(this, index, opcode, initialize);
- }
-
- @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicArrayCopyNode.java Thu May 31 10:38:05 2018 -0700
@@ -234,7 +234,8 @@
return;
}
for (int i = 0; i < len; i++) {
- LoadIndexedNode load = new LoadIndexedNode(graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), destComponentType.getJavaKind());
+ LoadIndexedNode load = new LoadIndexedNode(graph().getAssumptions(), srcAlias, ConstantNode.forInt(i + srcPosInt, graph()), null, destComponentType.getJavaKind());
+ load.setNodeSourcePosition(getNodeSourcePosition());
tool.addNode(load);
tool.setVirtualEntry(destVirtual, destPosInt + i, load);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java Thu May 31 10:38:05 2018 -0700
@@ -139,7 +139,7 @@
}
@Override
- public ValueNode length() {
- return GraphUtil.arrayLength(getObject());
+ public ValueNode findLength(ArrayLengthProvider.FindLengthMode mode) {
+ return GraphUtil.arrayLength(getObject(), mode);
}
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/MethodHandleNode.java Thu May 31 10:38:05 2018 -0700
@@ -333,7 +333,7 @@
FixedGuardNode fixedGuard = adder.add(new FixedGuardNode(inst, reason, action, speculation, false));
guard = fixedGuard;
} else {
- GuardNode newGuard = adder.add(new GuardNode(inst, guardAnchor, reason, action, false, speculation));
+ GuardNode newGuard = adder.add(new GuardNode(inst, guardAnchor, reason, action, false, speculation, null));
adder.add(new ValueAnchorNode(newGuard));
guard = newGuard;
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java Thu May 31 10:38:05 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,34 +22,27 @@
*/
package org.graalvm.compiler.serviceprovider.processor;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import javax.annotation.processing.AbstractProcessor;
-import javax.annotation.processing.FilerException;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
+import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.TypeMirror;
import javax.tools.Diagnostic.Kind;
-import javax.tools.FileObject;
-import javax.tools.StandardLocation;
-import org.graalvm.compiler.serviceprovider.ServiceProvider;
+import org.graalvm.compiler.processor.AbstractProcessor;
/**
- * Processes classes annotated with {@link ServiceProvider}. For a service defined by {@code S} and
+ * Processes classes annotated with {@code ServiceProvider}. For a service defined by {@code S} and
* a class {@code P} implementing the service, this processor generates the file
* {@code META-INF/providers/P} whose contents are a single line containing the fully qualified name
* of {@code S}.
@@ -57,6 +50,7 @@
@SupportedAnnotationTypes("org.graalvm.compiler.serviceprovider.ServiceProvider")
public class ServiceProviderProcessor extends AbstractProcessor {
+ private static final String SERVICE_PROVIDER_CLASS_NAME = "org.graalvm.compiler.serviceprovider.ServiceProvider";
private final Set<TypeElement> processed = new HashSet<>();
private final Map<TypeElement, String> serviceProviders = new HashMap<>();
@@ -81,90 +75,59 @@
}
processed.add(serviceProvider);
- ServiceProvider annotation = serviceProvider.getAnnotation(ServiceProvider.class);
+ AnnotationMirror annotation = getAnnotation(serviceProvider, getType(SERVICE_PROVIDER_CLASS_NAME));
if (annotation != null) {
- try {
- annotation.value();
- } catch (MirroredTypeException ex) {
- TypeMirror service = ex.getTypeMirror();
- if (verifyAnnotation(service, serviceProvider)) {
- if (serviceProvider.getNestingKind().isNested()) {
- /*
- * This is a simplifying constraint that means we don't have to process the
- * qualified name to insert '$' characters at the relevant positions.
- */
- String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName());
- processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
- } else {
- /*
- * Since the definition of the service class is not necessarily modifiable,
- * we need to support a non-top-level service class and ensure its name is
- * properly expressed with '$' separating nesting levels instead of '.'.
- */
- TypeElement serviceElement = (TypeElement) processingEnv.getTypeUtils().asElement(service);
- String serviceName = serviceElement.getSimpleName().toString();
- Element enclosing = serviceElement.getEnclosingElement();
- while (enclosing != null) {
- final ElementKind kind = enclosing.getKind();
- if (kind == ElementKind.PACKAGE) {
- serviceName = ((PackageElement) enclosing).getQualifiedName().toString() + "." + serviceName;
- break;
- } else if (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE) {
- serviceName = ((TypeElement) enclosing).getSimpleName().toString() + "$" + serviceName;
- enclosing = enclosing.getEnclosingElement();
- } else {
- String msg = String.format("Cannot generate provider descriptor for service class %s as it is not nested in a package, class or interface",
- serviceElement.getQualifiedName());
- processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
- return;
- }
+ TypeMirror service = getAnnotationValue(annotation, "value", TypeMirror.class);
+ if (verifyAnnotation(service, serviceProvider)) {
+ if (serviceProvider.getNestingKind().isNested()) {
+ /*
+ * This is a simplifying constraint that means we don't have to process the
+ * qualified name to insert '$' characters at the relevant positions.
+ */
+ String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName());
+ processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+ } else {
+ /*
+ * Since the definition of the service class is not necessarily modifiable, we
+ * need to support a non-top-level service class and ensure its name is properly
+ * expressed with '$' separating nesting levels instead of '.'.
+ */
+ TypeElement serviceElement = (TypeElement) processingEnv.getTypeUtils().asElement(service);
+ String serviceName = serviceElement.getSimpleName().toString();
+ Element enclosing = serviceElement.getEnclosingElement();
+ while (enclosing != null) {
+ final ElementKind kind = enclosing.getKind();
+ if (kind == ElementKind.PACKAGE) {
+ serviceName = ((PackageElement) enclosing).getQualifiedName().toString() + "." + serviceName;
+ break;
+ } else if (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE) {
+ serviceName = ((TypeElement) enclosing).getSimpleName().toString() + "$" + serviceName;
+ enclosing = enclosing.getEnclosingElement();
+ } else {
+ String msg = String.format("Cannot generate provider descriptor for service class %s as it is not nested in a package, class or interface",
+ serviceElement.getQualifiedName());
+ processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+ return;
}
- serviceProviders.put(serviceProvider, serviceName);
}
+ serviceProviders.put(serviceProvider, serviceName);
}
}
}
}
- private void writeProviderFile(TypeElement serviceProvider, String interfaceName) {
- String filename = "META-INF/providers/" + serviceProvider.getQualifiedName();
- try {
- FileObject file = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", filename, serviceProvider);
- PrintWriter writer = new PrintWriter(new OutputStreamWriter(file.openOutputStream(), "UTF-8"));
- writer.println(interfaceName);
- writer.close();
- } catch (IOException e) {
- processingEnv.getMessager().printMessage(isBug367599(e) ? Kind.NOTE : Kind.ERROR, e.getMessage(), serviceProvider);
- }
- }
-
- /**
- * Determines if a given exception is (most likely) caused by
- * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
- */
- private static boolean isBug367599(Throwable t) {
- if (t instanceof FilerException) {
- for (StackTraceElement ste : t.getStackTrace()) {
- if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
- // See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
- return true;
- }
- }
- }
- return t.getCause() != null && isBug367599(t.getCause());
- }
-
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
for (Entry<TypeElement, String> e : serviceProviders.entrySet()) {
- writeProviderFile(e.getKey(), e.getValue());
+ createProviderFile(e.getKey().getQualifiedName().toString(), e.getValue(), e.getKey());
}
serviceProviders.clear();
return true;
}
- for (Element element : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
+ TypeElement serviceProviderTypeElement = getTypeElement(SERVICE_PROVIDER_CLASS_NAME);
+ for (Element element : roundEnv.getElementsAnnotatedWith(serviceProviderTypeElement)) {
assert element.getKind().isClass();
processElement((TypeElement) element);
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeBlockState.java Thu May 31 10:38:05 2018 -0700
@@ -26,8 +26,10 @@
import java.util.Arrays;
import java.util.List;
+import org.graalvm.compiler.debug.DebugCloseable;
import org.graalvm.compiler.debug.DebugContext;
import org.graalvm.compiler.graph.Node;
+import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.nodes.FixedNode;
import org.graalvm.compiler.nodes.FixedWithNextNode;
import org.graalvm.compiler.nodes.StructuredGraph;
@@ -183,6 +185,7 @@
* This transitively also materializes all other virtual objects that are reachable from the
* entries.
*/
+ @SuppressWarnings("try")
public void materializeBefore(FixedNode fixed, VirtualObjectNode virtual, GraphEffectList materializeEffects) {
PartialEscapeClosure.COUNTER_MATERIALIZATIONS.increment(fixed.getDebug());
List<AllocatedObjectNode> objects = new ArrayList<>(2);
@@ -209,8 +212,10 @@
if (fixed.predecessor() instanceof CommitAllocationNode) {
commit = (CommitAllocationNode) fixed.predecessor();
} else {
- commit = graph.add(new CommitAllocationNode());
- graph.addBeforeFixed(fixed, commit);
+ try (DebugCloseable context = graph.withNodeSourcePosition(NodeSourcePosition.placeholder(graph.method()))) {
+ commit = graph.add(new CommitAllocationNode());
+ graph.addBeforeFixed(fixed, commit);
+ }
}
for (AllocatedObjectNode obj : objects) {
graph.addWithoutUnique(obj);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java Thu May 31 10:38:05 2018 -0700
@@ -650,7 +650,9 @@
if (needsCaching) {
return getValueObjectVirtualCached(phi, virtual);
} else {
- return virtual.duplicate();
+ VirtualObjectNode duplicate = virtual.duplicate();
+ duplicate.setNodeSourcePosition(virtual.getNodeSourcePosition());
+ return duplicate;
}
}
@@ -661,6 +663,7 @@
VirtualObjectNode result = valueObjectVirtuals.get(phi);
if (result == null) {
result = virtual.duplicate();
+ result.setNodeSourcePosition(virtual.getNodeSourcePosition());
valueObjectVirtuals.put(phi, result);
}
return result;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/Word.java Thu May 31 10:38:05 2018 -0700
@@ -88,6 +88,7 @@
*/
public enum Opcode {
NODE_CLASS,
+ NODE_CLASS_WITH_GUARD,
COMPARISON,
IS_NULL,
IS_NON_NULL,
@@ -248,69 +249,69 @@
}
@Override
- @Operation(node = SignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedDivNode.class)
public Word signedDivide(SignedWord val) {
return signedDivide((Word) val);
}
@Override
- @Operation(node = SignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedDivNode.class)
public Word signedDivide(int val) {
return signedDivide(intParam(val));
}
- @Operation(node = SignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedDivNode.class)
public Word signedDivide(Word val) {
return box(unbox() / val.unbox());
}
@Override
- @Operation(node = UnsignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedDivNode.class)
public Word unsignedDivide(UnsignedWord val) {
return unsignedDivide((Word) val);
}
@Override
- @Operation(node = UnsignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedDivNode.class)
public Word unsignedDivide(int val) {
return signedDivide(intParam(val));
}
- @Operation(node = UnsignedDivNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedDivNode.class)
public Word unsignedDivide(Word val) {
return box(Long.divideUnsigned(unbox(), val.unbox()));
}
@Override
- @Operation(node = SignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedRemNode.class)
public Word signedRemainder(SignedWord val) {
return signedRemainder((Word) val);
}
@Override
- @Operation(node = SignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedRemNode.class)
public Word signedRemainder(int val) {
return signedRemainder(intParam(val));
}
- @Operation(node = SignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = SignedRemNode.class)
public Word signedRemainder(Word val) {
return box(unbox() % val.unbox());
}
@Override
- @Operation(node = UnsignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedRemNode.class)
public Word unsignedRemainder(UnsignedWord val) {
return unsignedRemainder((Word) val);
}
@Override
- @Operation(node = UnsignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedRemNode.class)
public Word unsignedRemainder(int val) {
return signedRemainder(intParam(val));
}
- @Operation(node = UnsignedRemNode.class)
+ @Operation(opcode = Opcode.NODE_CLASS_WITH_GUARD, node = UnsignedRemNode.class)
public Word unsignedRemainder(Word val) {
return box(Long.remainderUnsigned(unbox(), val.unbox()));
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java Thu May 31 10:38:05 2018 -0700
@@ -51,6 +51,7 @@
import org.graalvm.compiler.nodes.calc.SignExtendNode;
import org.graalvm.compiler.nodes.calc.XorNode;
import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.extended.GuardingNode;
import org.graalvm.compiler.nodes.extended.JavaReadNode;
import org.graalvm.compiler.nodes.extended.JavaWriteNode;
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
@@ -160,7 +161,7 @@
}
@Override
- public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind) {
+ public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
ResolvedJavaType arrayType = StampTool.typeOrNull(array);
/*
* There are cases where the array does not have a known type yet, i.e., the type is null.
@@ -168,14 +169,14 @@
*/
if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
assert elementKind == JavaKind.Object;
- b.addPush(elementKind, createLoadIndexedNode(array, index));
+ b.addPush(elementKind, createLoadIndexedNode(array, index, boundsCheck));
return true;
}
return false;
}
- protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index) {
- return new LoadIndexedNode(null, array, index, wordKind);
+ protected LoadIndexedNode createLoadIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck) {
+ return new LoadIndexedNode(null, array, index, boundsCheck, wordKind);
}
@Override
@@ -201,14 +202,15 @@
}
@Override
- public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, JavaKind elementKind, ValueNode value) {
+ public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) {
ResolvedJavaType arrayType = StampTool.typeOrNull(array);
if (arrayType != null && wordTypes.isWord(arrayType.getComponentType())) {
assert elementKind == JavaKind.Object;
if (value.getStackKind() != wordKind) {
throw bailout(b, "Cannot store a non-word value into a word array: " + arrayType.toJavaName(true));
}
- b.add(createStoreIndexedNode(array, index, value));
+ GraalError.guarantee(storeCheck == null, "Word array stores are primitive stores and therefore do not require a store check");
+ b.add(createStoreIndexedNode(array, index, boundsCheck, value));
return true;
}
if (elementKind == JavaKind.Object && value.getStackKind() == wordKind) {
@@ -217,8 +219,8 @@
return false;
}
- protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, ValueNode value) {
- return new StoreIndexedNode(array, index, wordKind, value);
+ protected StoreIndexedNode createStoreIndexedNode(ValueNode array, ValueNode index, GuardingNode boundsCheck, ValueNode value) {
+ return new StoreIndexedNode(array, index, boundsCheck, null, wordKind, value);
}
@Override
@@ -275,11 +277,12 @@
}
switch (operation.opcode()) {
case NODE_CLASS:
+ case NODE_CLASS_WITH_GUARD:
assert args.length == 2;
ValueNode left = args[0];
ValueNode right = operation.rightOperandIsInt() ? toUnsigned(b, args[1], JavaKind.Int) : fromSigned(b, args[1]);
- b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right));
+ b.addPush(returnKind, createBinaryNodeInstance(operation.node(), left, right, operation.opcode() == Opcode.NODE_CLASS_WITH_GUARD));
break;
case COMPARISON:
@@ -399,10 +402,12 @@
* method is called for all {@link Word} operations which are annotated with @Operation(node =
* ...) and encapsulates the reflective allocation of the node.
*/
- private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right) {
+ private static ValueNode createBinaryNodeInstance(Class<? extends ValueNode> nodeClass, ValueNode left, ValueNode right, boolean withGuardingNode) {
try {
- Constructor<?> cons = nodeClass.getDeclaredConstructor(ValueNode.class, ValueNode.class);
- return (ValueNode) cons.newInstance(left, right);
+ Class<?>[] parameterTypes = withGuardingNode ? new Class<?>[]{ValueNode.class, ValueNode.class, GuardingNode.class} : new Class<?>[]{ValueNode.class, ValueNode.class};
+ Constructor<?> cons = nodeClass.getDeclaredConstructor(parameterTypes);
+ Object[] initargs = withGuardingNode ? new Object[]{left, right, null} : new Object[]{left, right};
+ return (ValueNode) cons.newInstance(initargs);
} catch (Throwable ex) {
throw new GraalError(ex).addContext(nodeClass.getName());
}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphJavadocSnippets.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphJavadocSnippets.java Thu May 31 10:38:05 2018 -0700
@@ -149,8 +149,8 @@
static GraphOutput<AcmeGraph, ?> buildOutput(WritableByteChannel channel)
throws IOException {
return GraphOutput.newBuilder(acmeGraphStructure()).
- // use the latest version; currently 5.0
- protocolVersion(5, 0).
+ // use the latest version; currently 6.0
+ protocolVersion(6, 0).
build(channel);
}
// END: org.graalvm.graphio.GraphJavadocSnippets#buildOutput
@@ -164,7 +164,7 @@
GraphTypes graphTypes = acmeTypes();
return GraphOutput.newBuilder(acmeGraphStructure()).
- protocolVersion(5, 0).
+ protocolVersion(6, 0).
blocks(graphBlocks).
elements(graphElements).
types(graphTypes).
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphProtocol.java Thu May 31 10:38:05 2018 -0700
@@ -606,7 +606,7 @@
throw new IOException(ex);
}
if (uri == null) {
- throw new IOException("No URI for " + loc);
+ continue;
}
String l = findLocationLanguage(loc);
if (l == null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java Thu May 31 10:14:41 2018 -0700
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/ProtocolImpl.java Thu May 31 10:38:05 2018 -0700
@@ -78,7 +78,11 @@
@Override
protected NodeClass findClassForNode(Node obj) {
- return structure.classForNode(obj);
+ NodeClass clazz = structure.classForNode(obj);
+ if (clazz != null && (findNodeClass(clazz) == null || findNode(clazz) != null)) {
+ throw new IllegalStateException("classForNode method shall return node class representation rather than node: " + clazz);
+ }
+ return clazz;
}
@Override